2
0

egl-helpers.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /*
  2. * Copyright (C) 2015-2016 Gerd Hoffmann <kraxel@redhat.com>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "qemu/osdep.h"
  18. #include "qemu/drm.h"
  19. #include "qemu/error-report.h"
  20. #include "ui/console.h"
  21. #include "ui/egl-helpers.h"
  22. #include "sysemu/sysemu.h"
  23. #include "qapi/error.h"
  24. EGLDisplay *qemu_egl_display;
  25. EGLConfig qemu_egl_config;
  26. DisplayGLMode qemu_egl_mode;
  27. /* ------------------------------------------------------------------ */
  28. static const char *egl_get_error_string(void)
  29. {
  30. EGLint error = eglGetError();
  31. switch (error) {
  32. case EGL_SUCCESS:
  33. return "EGL_SUCCESS";
  34. case EGL_NOT_INITIALIZED:
  35. return "EGL_NOT_INITIALIZED";
  36. case EGL_BAD_ACCESS:
  37. return "EGL_BAD_ACCESS";
  38. case EGL_BAD_ALLOC:
  39. return "EGL_BAD_ALLOC";
  40. case EGL_BAD_ATTRIBUTE:
  41. return "EGL_BAD_ATTRIBUTE";
  42. case EGL_BAD_CONTEXT:
  43. return "EGL_BAD_CONTEXT";
  44. case EGL_BAD_CONFIG:
  45. return "EGL_BAD_CONFIG";
  46. case EGL_BAD_CURRENT_SURFACE:
  47. return "EGL_BAD_CURRENT_SURFACE";
  48. case EGL_BAD_DISPLAY:
  49. return "EGL_BAD_DISPLAY";
  50. case EGL_BAD_SURFACE:
  51. return "EGL_BAD_SURFACE";
  52. case EGL_BAD_MATCH:
  53. return "EGL_BAD_MATCH";
  54. case EGL_BAD_PARAMETER:
  55. return "EGL_BAD_PARAMETER";
  56. case EGL_BAD_NATIVE_PIXMAP:
  57. return "EGL_BAD_NATIVE_PIXMAP";
  58. case EGL_BAD_NATIVE_WINDOW:
  59. return "EGL_BAD_NATIVE_WINDOW";
  60. case EGL_CONTEXT_LOST:
  61. return "EGL_CONTEXT_LOST";
  62. default:
  63. return "Unknown EGL error";
  64. }
  65. }
  66. static void egl_fb_delete_texture(egl_fb *fb)
  67. {
  68. if (!fb->delete_texture) {
  69. return;
  70. }
  71. glDeleteTextures(1, &fb->texture);
  72. fb->delete_texture = false;
  73. }
  74. void egl_fb_destroy(egl_fb *fb)
  75. {
  76. if (!fb->framebuffer) {
  77. return;
  78. }
  79. egl_fb_delete_texture(fb);
  80. glDeleteFramebuffers(1, &fb->framebuffer);
  81. fb->width = 0;
  82. fb->height = 0;
  83. fb->texture = 0;
  84. fb->framebuffer = 0;
  85. }
  86. void egl_fb_setup_default(egl_fb *fb, int width, int height)
  87. {
  88. fb->width = width;
  89. fb->height = height;
  90. fb->framebuffer = 0; /* default framebuffer */
  91. }
  92. void egl_fb_setup_for_tex_target(egl_fb *fb, int width, int height,
  93. GLuint texture, GLenum target, bool delete)
  94. {
  95. egl_fb_delete_texture(fb);
  96. fb->width = width;
  97. fb->height = height;
  98. fb->texture = texture;
  99. fb->texture_target = target;
  100. fb->delete_texture = delete;
  101. if (!fb->framebuffer) {
  102. glGenFramebuffers(1, &fb->framebuffer);
  103. }
  104. glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb->framebuffer);
  105. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
  106. fb->texture_target, fb->texture, 0);
  107. }
  108. void egl_fb_setup_for_tex(egl_fb *fb, int width, int height,
  109. GLuint texture, bool delete)
  110. {
  111. egl_fb_setup_for_tex_target(fb, width, height, texture, GL_TEXTURE_2D, delete);
  112. }
  113. void egl_fb_setup_new_tex_target(egl_fb *fb, int width, int height, GLenum target)
  114. {
  115. GLuint texture;
  116. glGenTextures(1, &texture);
  117. glBindTexture(target, texture);
  118. glTexImage2D(target, 0, GL_RGBA, width, height,
  119. 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
  120. egl_fb_setup_for_tex_target(fb, width, height, texture, target, true);
  121. }
  122. void egl_fb_setup_new_tex(egl_fb *fb, int width, int height)
  123. {
  124. egl_fb_setup_new_tex_target(fb, width, height, GL_TEXTURE_2D);
  125. }
  126. void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip)
  127. {
  128. GLuint x1 = 0;
  129. GLuint y1 = 0;
  130. GLuint x2, y2;
  131. GLuint w = src->width;
  132. GLuint h = src->height;
  133. glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
  134. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer);
  135. glViewport(0, 0, dst->width, dst->height);
  136. if (src->dmabuf) {
  137. x1 = src->dmabuf->x;
  138. y1 = src->dmabuf->y;
  139. w = src->dmabuf->scanout_width;
  140. h = src->dmabuf->scanout_height;
  141. }
  142. w = (x1 + w) > src->width ? src->width - x1 : w;
  143. h = (y1 + h) > src->height ? src->height - y1 : h;
  144. y2 = flip ? y1 : h + y1;
  145. y1 = flip ? h + y1 : y1;
  146. x2 = x1 + w;
  147. glBlitFramebuffer(x1, y1, x2, y2,
  148. 0, 0, dst->width, dst->height,
  149. GL_COLOR_BUFFER_BIT, GL_LINEAR);
  150. }
  151. void egl_fb_read(DisplaySurface *dst, egl_fb *src)
  152. {
  153. glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer);
  154. glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
  155. glReadPixels(0, 0, surface_width(dst), surface_height(dst),
  156. GL_BGRA, GL_UNSIGNED_BYTE, surface_data(dst));
  157. }
  158. void egl_texture_blit(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip, bool swap)
  159. {
  160. glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
  161. glViewport(0, 0, dst->width, dst->height);
  162. glEnable(GL_TEXTURE_2D);
  163. glBindTexture(src->texture_target, src->texture);
  164. qemu_gl_run_texture_blit(gls, flip, swap);
  165. }
  166. void egl_texture_blend(QemuGLShader *gls, egl_fb *dst, egl_fb *src, bool flip,
  167. bool swap, int x, int y, double scale_x, double scale_y)
  168. {
  169. glBindFramebuffer(GL_FRAMEBUFFER_EXT, dst->framebuffer);
  170. int w = scale_x * src->width;
  171. int h = scale_y * src->height;
  172. if (flip) {
  173. glViewport(x, y, w, h);
  174. } else {
  175. glViewport(x, dst->height - h - y, w, h);
  176. }
  177. glEnable(GL_TEXTURE_2D);
  178. glBindTexture(src->texture_target, src->texture);
  179. glEnable(GL_BLEND);
  180. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  181. qemu_gl_run_texture_blit(gls, flip, swap);
  182. glDisable(GL_BLEND);
  183. }
  184. /* ---------------------------------------------------------------------- */
  185. #ifdef CONFIG_GBM
  186. int qemu_egl_rn_fd;
  187. struct gbm_device *qemu_egl_rn_gbm_dev;
  188. EGLContext qemu_egl_rn_ctx;
  189. int egl_rendernode_init(const char *rendernode, DisplayGLMode mode)
  190. {
  191. qemu_egl_rn_fd = -1;
  192. int rc;
  193. qemu_egl_rn_fd = qemu_drm_rendernode_open(rendernode);
  194. if (qemu_egl_rn_fd == -1) {
  195. error_report("egl: no drm render node available");
  196. goto err;
  197. }
  198. qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd);
  199. if (!qemu_egl_rn_gbm_dev) {
  200. error_report("egl: gbm_create_device failed");
  201. goto err;
  202. }
  203. rc = qemu_egl_init_dpy_mesa((EGLNativeDisplayType)qemu_egl_rn_gbm_dev,
  204. mode);
  205. if (rc != 0) {
  206. /* qemu_egl_init_dpy_mesa reports error */
  207. goto err;
  208. }
  209. if (!epoxy_has_egl_extension(qemu_egl_display,
  210. "EGL_KHR_surfaceless_context")) {
  211. error_report("egl: EGL_KHR_surfaceless_context not supported");
  212. goto err;
  213. }
  214. if (!epoxy_has_egl_extension(qemu_egl_display,
  215. "EGL_MESA_image_dma_buf_export")) {
  216. error_report("egl: EGL_MESA_image_dma_buf_export not supported");
  217. goto err;
  218. }
  219. qemu_egl_rn_ctx = qemu_egl_init_ctx();
  220. if (!qemu_egl_rn_ctx) {
  221. error_report("egl: egl_init_ctx failed");
  222. goto err;
  223. }
  224. return 0;
  225. err:
  226. if (qemu_egl_rn_gbm_dev) {
  227. gbm_device_destroy(qemu_egl_rn_gbm_dev);
  228. }
  229. if (qemu_egl_rn_fd != -1) {
  230. close(qemu_egl_rn_fd);
  231. }
  232. return -1;
  233. }
  234. int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
  235. EGLuint64KHR *modifier)
  236. {
  237. EGLImageKHR image;
  238. EGLint num_planes, fd;
  239. image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
  240. EGL_GL_TEXTURE_2D_KHR,
  241. (EGLClientBuffer)(unsigned long)tex_id,
  242. NULL);
  243. if (!image) {
  244. return -1;
  245. }
  246. eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc,
  247. &num_planes, modifier);
  248. if (num_planes != 1) {
  249. eglDestroyImageKHR(qemu_egl_display, image);
  250. return -1;
  251. }
  252. eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL);
  253. eglDestroyImageKHR(qemu_egl_display, image);
  254. return fd;
  255. }
  256. void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
  257. {
  258. EGLImageKHR image = EGL_NO_IMAGE_KHR;
  259. EGLint attrs[64];
  260. int i = 0;
  261. if (dmabuf->texture != 0) {
  262. return;
  263. }
  264. attrs[i++] = EGL_WIDTH;
  265. attrs[i++] = dmabuf->width;
  266. attrs[i++] = EGL_HEIGHT;
  267. attrs[i++] = dmabuf->height;
  268. attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
  269. attrs[i++] = dmabuf->fourcc;
  270. attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
  271. attrs[i++] = dmabuf->fd;
  272. attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
  273. attrs[i++] = dmabuf->stride;
  274. attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
  275. attrs[i++] = 0;
  276. #ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT
  277. if (dmabuf->modifier) {
  278. attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
  279. attrs[i++] = (dmabuf->modifier >> 0) & 0xffffffff;
  280. attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
  281. attrs[i++] = (dmabuf->modifier >> 32) & 0xffffffff;
  282. }
  283. #endif
  284. attrs[i++] = EGL_NONE;
  285. image = eglCreateImageKHR(qemu_egl_display,
  286. EGL_NO_CONTEXT,
  287. EGL_LINUX_DMA_BUF_EXT,
  288. NULL, attrs);
  289. if (image == EGL_NO_IMAGE_KHR) {
  290. error_report("eglCreateImageKHR failed");
  291. return;
  292. }
  293. glGenTextures(1, &dmabuf->texture);
  294. glBindTexture(GL_TEXTURE_2D, dmabuf->texture);
  295. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  296. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  297. glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
  298. eglDestroyImageKHR(qemu_egl_display, image);
  299. }
  300. void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf)
  301. {
  302. if (dmabuf->texture == 0) {
  303. return;
  304. }
  305. glDeleteTextures(1, &dmabuf->texture);
  306. dmabuf->texture = 0;
  307. }
  308. void egl_dmabuf_create_sync(QemuDmaBuf *dmabuf)
  309. {
  310. EGLSyncKHR sync;
  311. if (epoxy_has_egl_extension(qemu_egl_display,
  312. "EGL_KHR_fence_sync") &&
  313. epoxy_has_egl_extension(qemu_egl_display,
  314. "EGL_ANDROID_native_fence_sync")) {
  315. sync = eglCreateSyncKHR(qemu_egl_display,
  316. EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
  317. if (sync != EGL_NO_SYNC_KHR) {
  318. dmabuf->sync = sync;
  319. }
  320. }
  321. }
  322. void egl_dmabuf_create_fence(QemuDmaBuf *dmabuf)
  323. {
  324. if (dmabuf->sync) {
  325. dmabuf->fence_fd = eglDupNativeFenceFDANDROID(qemu_egl_display,
  326. dmabuf->sync);
  327. eglDestroySyncKHR(qemu_egl_display, dmabuf->sync);
  328. dmabuf->sync = NULL;
  329. }
  330. }
  331. #endif /* CONFIG_GBM */
  332. /* ---------------------------------------------------------------------- */
  333. EGLSurface qemu_egl_init_surface(EGLContext ectx, EGLNativeWindowType win)
  334. {
  335. EGLSurface esurface;
  336. EGLBoolean b;
  337. esurface = eglCreateWindowSurface(qemu_egl_display,
  338. qemu_egl_config,
  339. win, NULL);
  340. if (esurface == EGL_NO_SURFACE) {
  341. error_report("egl: eglCreateWindowSurface failed");
  342. return NULL;
  343. }
  344. b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
  345. if (b == EGL_FALSE) {
  346. error_report("egl: eglMakeCurrent failed");
  347. return NULL;
  348. }
  349. return esurface;
  350. }
  351. EGLSurface qemu_egl_init_buffer_surface(EGLContext ectx,
  352. EGLenum buftype,
  353. EGLClientBuffer buffer,
  354. const EGLint *attrib_list)
  355. {
  356. EGLSurface esurface;
  357. EGLBoolean b;
  358. esurface = eglCreatePbufferFromClientBuffer(qemu_egl_display,
  359. buftype,
  360. buffer,
  361. qemu_egl_config,
  362. attrib_list);
  363. if (esurface == EGL_NO_SURFACE) {
  364. error_report("egl: eglCreatePbufferFromClientBuffer failed");
  365. return NULL;
  366. }
  367. b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
  368. if (b == EGL_FALSE) {
  369. error_report("egl: eglMakeCurrent failed");
  370. qemu_egl_destroy_surface(esurface);
  371. return NULL;
  372. }
  373. return esurface;
  374. }
  375. bool qemu_egl_destroy_surface(EGLSurface surface)
  376. {
  377. return eglDestroySurface(qemu_egl_display, surface);
  378. }
  379. /* ---------------------------------------------------------------------- */
  380. static int qemu_egl_init_dpy(EGLDisplay dpy, DisplayGLMode mode)
  381. {
  382. static const EGLint conf_att_core[] = {
  383. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  384. EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
  385. EGL_RED_SIZE, 5,
  386. EGL_GREEN_SIZE, 5,
  387. EGL_BLUE_SIZE, 5,
  388. EGL_ALPHA_SIZE, 0,
  389. EGL_NONE,
  390. };
  391. static const EGLint conf_att_gles[] = {
  392. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  393. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  394. EGL_RED_SIZE, 5,
  395. EGL_GREEN_SIZE, 5,
  396. EGL_BLUE_SIZE, 5,
  397. EGL_ALPHA_SIZE, 0,
  398. EGL_NONE,
  399. };
  400. EGLint major, minor;
  401. EGLBoolean b;
  402. EGLint n;
  403. bool gles = (mode == DISPLAYGL_MODE_ES);
  404. qemu_egl_display = dpy;
  405. b = eglInitialize(qemu_egl_display, &major, &minor);
  406. if (b == EGL_FALSE) {
  407. error_report("egl: eglInitialize failed: %s", egl_get_error_string());
  408. return -1;
  409. }
  410. b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
  411. if (b == EGL_FALSE) {
  412. error_report("egl: eglBindAPI failed (%s mode): %s",
  413. gles ? "gles" : "core", egl_get_error_string());
  414. return -1;
  415. }
  416. b = eglChooseConfig(qemu_egl_display,
  417. gles ? conf_att_gles : conf_att_core,
  418. &qemu_egl_config, 1, &n);
  419. if (b == EGL_FALSE || n != 1) {
  420. error_report("egl: eglChooseConfig failed (%s mode): %s",
  421. gles ? "gles" : "core", egl_get_error_string());
  422. return -1;
  423. }
  424. qemu_egl_mode = gles ? DISPLAYGL_MODE_ES : DISPLAYGL_MODE_CORE;
  425. return 0;
  426. }
  427. int qemu_egl_init_dpy_cocoa(DisplayGLMode mode)
  428. {
  429. EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  430. if (dpy == EGL_NO_DISPLAY) {
  431. error_report("egl: eglGetDisplay failed");
  432. return -1;
  433. }
  434. return qemu_egl_init_dpy(dpy, mode);
  435. }
  436. /*
  437. * Taken from glamor_egl.h from the Xorg xserver, which is MIT licensed
  438. *
  439. * Create an EGLDisplay from a native display type. This is a little quirky
  440. * for a few reasons.
  441. *
  442. * 1: GetPlatformDisplayEXT and GetPlatformDisplay are the API you want to
  443. * use, but have different function signatures in the third argument; this
  444. * happens not to matter for us, at the moment, but it means epoxy won't alias
  445. * them together.
  446. *
  447. * 2: epoxy 1.3 and earlier don't understand EGL client extensions, which
  448. * means you can't call "eglGetPlatformDisplayEXT" directly, as the resolver
  449. * will crash.
  450. *
  451. * 3: You can't tell whether you have EGL 1.5 at this point, because
  452. * eglQueryString(EGL_VERSION) is a property of the display, which we don't
  453. * have yet. So you have to query for extensions no matter what. Fortunately
  454. * epoxy_has_egl_extension _does_ let you query for client extensions, so
  455. * we don't have to write our own extension string parsing.
  456. *
  457. * 4. There is no EGL_KHR_platform_base to complement the EXT one, thus one
  458. * needs to know EGL 1.5 is supported in order to use the eglGetPlatformDisplay
  459. * function pointer.
  460. * We can workaround this (circular dependency) by probing for the EGL 1.5
  461. * platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem
  462. * like mesa will be able to advertise these (even though it can do EGL 1.5).
  463. */
  464. static int qemu_egl_init_dpy_platform(EGLNativeDisplayType native,
  465. EGLenum platform,
  466. DisplayGLMode mode)
  467. {
  468. EGLDisplay dpy = EGL_NO_DISPLAY;
  469. /* In practise any EGL 1.5 implementation would support the EXT extension */
  470. if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
  471. PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
  472. (void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
  473. if (getPlatformDisplayEXT && platform != 0) {
  474. dpy = getPlatformDisplayEXT(platform, native, NULL);
  475. }
  476. }
  477. #if defined(CONFIG_X11) || defined(CONFIG_GBM)
  478. if (dpy == EGL_NO_DISPLAY) {
  479. /* fallback */
  480. dpy = eglGetDisplay(native);
  481. }
  482. #endif
  483. if (dpy == EGL_NO_DISPLAY) {
  484. error_report("egl: eglGetDisplay failed");
  485. return -1;
  486. }
  487. return qemu_egl_init_dpy(dpy, mode);
  488. }
  489. int qemu_egl_init_dpy_surfaceless(DisplayGLMode mode)
  490. {
  491. return qemu_egl_init_dpy_platform(NULL, EGL_PLATFORM_SURFACELESS_MESA, mode);
  492. }
  493. #if defined(CONFIG_X11) || defined(CONFIG_GBM)
  494. int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode)
  495. {
  496. #ifdef EGL_KHR_platform_x11
  497. return qemu_egl_init_dpy_platform(dpy, EGL_PLATFORM_X11_KHR, mode);
  498. #else
  499. return qemu_egl_init_dpy_platform(dpy, 0, mode);
  500. #endif
  501. }
  502. int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
  503. {
  504. #ifdef EGL_MESA_platform_gbm
  505. return qemu_egl_init_dpy_platform(dpy, EGL_PLATFORM_GBM_MESA, mode);
  506. #else
  507. return qemu_egl_init_dpy_platform(dpy, 0, mode);
  508. #endif
  509. }
  510. #endif
  511. #if defined(CONFIG_ANGLE)
  512. int qemu_egl_init_dpy_angle(DisplayGLMode mode)
  513. {
  514. return qemu_egl_init_dpy_platform(NULL, EGL_PLATFORM_ANGLE_ANGLE, mode);
  515. }
  516. #endif
  517. bool qemu_egl_has_dmabuf(void)
  518. {
  519. if (qemu_egl_display == EGL_NO_DISPLAY) {
  520. return false;
  521. }
  522. return epoxy_has_egl_extension(qemu_egl_display,
  523. "EGL_EXT_image_dma_buf_import");
  524. }
  525. EGLContext qemu_egl_init_ctx(void)
  526. {
  527. static const EGLint ctx_att_core[] = {
  528. EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
  529. EGL_NONE
  530. };
  531. static const EGLint ctx_att_gles[] = {
  532. EGL_CONTEXT_CLIENT_VERSION, 2,
  533. EGL_NONE
  534. };
  535. bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES);
  536. EGLContext ectx;
  537. EGLBoolean b;
  538. ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
  539. gles ? ctx_att_gles : ctx_att_core);
  540. if (ectx == EGL_NO_CONTEXT) {
  541. error_report("egl: eglCreateContext failed");
  542. return NULL;
  543. }
  544. b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx);
  545. if (b == EGL_FALSE) {
  546. error_report("egl: eglMakeCurrent failed");
  547. return NULL;
  548. }
  549. return ectx;
  550. }
  551. bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
  552. {
  553. ERRP_GUARD();
  554. if (mode == DISPLAYGL_MODE_OFF) {
  555. error_setg(errp, "egl: turning off GL doesn't make sense");
  556. return false;
  557. }
  558. #ifdef CONFIG_GBM
  559. if (egl_rendernode_init(rendernode, mode) < 0) {
  560. error_setg(errp, "egl: render node init failed");
  561. return false;
  562. }
  563. display_opengl = 1;
  564. return true;
  565. #else
  566. error_setg(errp, "egl: not available on this platform");
  567. return false;
  568. #endif
  569. }