gl-x11-egl.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /******************************************************************************
  2. Copyright (C) 2019 by Ivan Avdeev <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. /* GL context initialization using EGL instead of GLX
  15. * Which is essential for improved and more performant screen grabbing and
  16. * VA-API feeding techniques.
  17. *
  18. * Note: most of x11-related functionality was taken from gl-x11.c
  19. */
  20. #include <X11/Xlib.h>
  21. #include <X11/Xlib-xcb.h>
  22. #include <xcb/xcb.h>
  23. #include <stdio.h>
  24. #include "gl-egl-common.h"
  25. #include "gl-x11-egl.h"
  26. #include <glad/glad_egl.h>
  27. typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(
  28. EGLenum platform, void *native_display, const EGLint *attrib_list);
  29. static const int ctx_attribs[] = {
  30. #ifdef _DEBUG
  31. EGL_CONTEXT_OPENGL_DEBUG,
  32. EGL_TRUE,
  33. #endif
  34. EGL_CONTEXT_OPENGL_PROFILE_MASK,
  35. EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
  36. EGL_CONTEXT_MAJOR_VERSION,
  37. 3,
  38. EGL_CONTEXT_MINOR_VERSION,
  39. 3,
  40. EGL_NONE,
  41. };
  42. static int ctx_pbuffer_attribs[] = {EGL_WIDTH, 2, EGL_HEIGHT, 2, EGL_NONE};
  43. static const EGLint ctx_config_attribs[] = {EGL_STENCIL_SIZE,
  44. 0,
  45. EGL_DEPTH_SIZE,
  46. 0,
  47. EGL_BUFFER_SIZE,
  48. 32,
  49. EGL_ALPHA_SIZE,
  50. 8,
  51. EGL_RENDERABLE_TYPE,
  52. EGL_OPENGL_BIT,
  53. EGL_SURFACE_TYPE,
  54. EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
  55. EGL_NONE};
  56. struct gl_windowinfo {
  57. EGLConfig config;
  58. /* Windows in X11 are defined with integers (XID).
  59. * xcb_window_t is a define for this... they are
  60. * compatible with Xlib as well.
  61. */
  62. xcb_window_t window;
  63. EGLSurface surface;
  64. /* We can't fetch screen without a request so we cache it. */
  65. int screen;
  66. };
  67. struct gl_platform {
  68. Display *xdisplay;
  69. EGLDisplay edisplay;
  70. EGLConfig config;
  71. EGLContext context;
  72. EGLSurface pbuffer;
  73. };
  74. /* The following utility functions are copied verbatim from GLX code. */
  75. /*
  76. * Since we cannot take advantage of the asynchronous nature of xcb,
  77. * all of the helper functions are synchronous but thread-safe.
  78. *
  79. * They check for errors and will return 0 on problems
  80. * with the exception of when 0 is a valid return value... in which case
  81. * read the specific function comments.
  82. */
  83. /* Returns -1 on invalid screen. */
  84. static int get_screen_num_from_xcb_screen(xcb_connection_t *xcb_conn,
  85. xcb_screen_t *screen)
  86. {
  87. xcb_screen_iterator_t iter =
  88. xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
  89. int screen_num = 0;
  90. for (; iter.rem; xcb_screen_next(&iter), ++screen_num)
  91. if (iter.data == screen)
  92. return screen_num;
  93. return -1;
  94. }
  95. static xcb_screen_t *get_screen_from_root(xcb_connection_t *xcb_conn,
  96. xcb_window_t root)
  97. {
  98. xcb_screen_iterator_t iter =
  99. xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
  100. while (iter.rem) {
  101. if (iter.data->root == root)
  102. return iter.data;
  103. xcb_screen_next(&iter);
  104. }
  105. return 0;
  106. }
  107. static inline int get_screen_num_from_root(xcb_connection_t *xcb_conn,
  108. xcb_window_t root)
  109. {
  110. xcb_screen_t *screen = get_screen_from_root(xcb_conn, root);
  111. if (!screen)
  112. return -1;
  113. return get_screen_num_from_xcb_screen(xcb_conn, screen);
  114. }
  115. static xcb_get_geometry_reply_t *get_window_geometry(xcb_connection_t *xcb_conn,
  116. xcb_drawable_t drawable)
  117. {
  118. xcb_get_geometry_cookie_t cookie;
  119. xcb_generic_error_t *error;
  120. xcb_get_geometry_reply_t *reply;
  121. cookie = xcb_get_geometry(xcb_conn, drawable);
  122. reply = xcb_get_geometry_reply(xcb_conn, cookie, &error);
  123. if (error) {
  124. blog(LOG_ERROR, "Failed to fetch parent window geometry!");
  125. free(error);
  126. free(reply);
  127. return 0;
  128. }
  129. return reply;
  130. }
  131. static const char *get_egl_error_string2(const EGLint error)
  132. {
  133. switch (error) {
  134. #define OBS_EGL_CASE_ERROR(e) \
  135. case e: \
  136. return #e;
  137. OBS_EGL_CASE_ERROR(EGL_SUCCESS)
  138. OBS_EGL_CASE_ERROR(EGL_NOT_INITIALIZED)
  139. OBS_EGL_CASE_ERROR(EGL_BAD_ACCESS)
  140. OBS_EGL_CASE_ERROR(EGL_BAD_ALLOC)
  141. OBS_EGL_CASE_ERROR(EGL_BAD_ATTRIBUTE)
  142. OBS_EGL_CASE_ERROR(EGL_BAD_CONTEXT)
  143. OBS_EGL_CASE_ERROR(EGL_BAD_CONFIG)
  144. OBS_EGL_CASE_ERROR(EGL_BAD_CURRENT_SURFACE)
  145. OBS_EGL_CASE_ERROR(EGL_BAD_DISPLAY)
  146. OBS_EGL_CASE_ERROR(EGL_BAD_SURFACE)
  147. OBS_EGL_CASE_ERROR(EGL_BAD_MATCH)
  148. OBS_EGL_CASE_ERROR(EGL_BAD_PARAMETER)
  149. OBS_EGL_CASE_ERROR(EGL_BAD_NATIVE_PIXMAP)
  150. OBS_EGL_CASE_ERROR(EGL_BAD_NATIVE_WINDOW)
  151. OBS_EGL_CASE_ERROR(EGL_CONTEXT_LOST)
  152. #undef OBS_EGL_CASE_ERROR
  153. default:
  154. return "Unknown";
  155. }
  156. }
  157. static const char *get_egl_error_string()
  158. {
  159. return get_egl_error_string2(eglGetError());
  160. }
  161. static EGLDisplay get_egl_display(struct gl_platform *plat)
  162. {
  163. Display *display = plat->xdisplay;
  164. EGLDisplay edisplay = EGL_NO_DISPLAY;
  165. const char *egl_client_extensions = NULL;
  166. egl_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  167. PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
  168. (PFNEGLGETPLATFORMDISPLAYEXTPROC)(strstr(egl_client_extensions,
  169. "EGL_EXT_platform_base")
  170. ? eglGetProcAddress(
  171. "eglGetPlatformDisplayEXT")
  172. : NULL);
  173. if (eglGetPlatformDisplayEXT) {
  174. edisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT,
  175. display, NULL);
  176. if (EGL_NO_DISPLAY == edisplay)
  177. blog(LOG_ERROR, "Failed to get EGL/X11 display");
  178. }
  179. if (EGL_NO_DISPLAY == edisplay)
  180. edisplay = eglGetDisplay(display);
  181. return edisplay;
  182. }
  183. static bool gl_context_create(struct gl_platform *plat)
  184. {
  185. Display *display = plat->xdisplay;
  186. int frame_buf_config_count = 0;
  187. EGLDisplay edisplay = EGL_NO_DISPLAY;
  188. EGLConfig config = NULL;
  189. EGLContext context = EGL_NO_CONTEXT;
  190. int egl_min = 0, egl_maj = 0;
  191. bool success = false;
  192. eglBindAPI(EGL_OPENGL_API);
  193. edisplay = get_egl_display(plat);
  194. if (EGL_NO_DISPLAY == edisplay) {
  195. blog(LOG_ERROR,
  196. "Failed to get EGL display using eglGetDisplay");
  197. return false;
  198. }
  199. if (!eglInitialize(edisplay, &egl_maj, &egl_min)) {
  200. blog(LOG_ERROR, "Failed to initialize EGL: %s",
  201. get_egl_error_string());
  202. return false;
  203. }
  204. if (!eglChooseConfig(edisplay, ctx_config_attribs, &config, 1,
  205. &frame_buf_config_count)) {
  206. blog(LOG_ERROR, "Unable to find suitable EGL config: %s",
  207. get_egl_error_string());
  208. goto error;
  209. }
  210. context =
  211. eglCreateContext(edisplay, config, EGL_NO_CONTEXT, ctx_attribs);
  212. #ifdef _DEBUG
  213. if (EGL_NO_CONTEXT == context) {
  214. const EGLint error = eglGetError();
  215. if (error == EGL_BAD_ATTRIBUTE) {
  216. /* Sometimes creation fails because debug gl is not supported */
  217. blog(LOG_ERROR,
  218. "Unable to create EGL context with DEBUG attrib, trying without");
  219. context = eglCreateContext(edisplay, config,
  220. EGL_NO_CONTEXT,
  221. ctx_attribs + 2);
  222. } else {
  223. blog(LOG_ERROR, "Unable to create EGL context: %s",
  224. get_egl_error_string2(error));
  225. goto error;
  226. }
  227. }
  228. #endif
  229. if (EGL_NO_CONTEXT == context) {
  230. blog(LOG_ERROR, "Unable to create EGL context: %s",
  231. get_egl_error_string());
  232. goto error;
  233. }
  234. plat->pbuffer =
  235. eglCreatePbufferSurface(edisplay, config, ctx_pbuffer_attribs);
  236. if (EGL_NO_SURFACE == plat->pbuffer) {
  237. blog(LOG_ERROR, "Failed to create OpenGL pbuffer: %s",
  238. get_egl_error_string());
  239. goto error;
  240. }
  241. plat->edisplay = edisplay;
  242. plat->config = config;
  243. plat->context = context;
  244. success = true;
  245. blog(LOG_DEBUG, "Created EGLDisplay %p", plat->edisplay);
  246. error:
  247. if (!success) {
  248. if (EGL_NO_CONTEXT != context)
  249. eglDestroyContext(edisplay, context);
  250. eglTerminate(edisplay);
  251. }
  252. XSync(display, false);
  253. return success;
  254. }
  255. static void gl_context_destroy(struct gl_platform *plat)
  256. {
  257. eglMakeCurrent(plat->edisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
  258. EGL_NO_CONTEXT);
  259. eglDestroyContext(plat->edisplay, plat->context);
  260. }
  261. static struct gl_windowinfo *
  262. gl_x11_egl_windowinfo_create(const struct gs_init_data *info)
  263. {
  264. UNUSED_PARAMETER(info);
  265. return bmalloc(sizeof(struct gl_windowinfo));
  266. }
  267. static void gl_x11_egl_windowinfo_destroy(struct gl_windowinfo *info)
  268. {
  269. UNUSED_PARAMETER(info);
  270. bfree(info);
  271. }
  272. static Display *open_windowless_display(Display *platform_display)
  273. {
  274. Display *display;
  275. xcb_connection_t *xcb_conn;
  276. xcb_screen_iterator_t screen_iterator;
  277. xcb_screen_t *screen;
  278. int screen_num;
  279. if (platform_display)
  280. display = platform_display;
  281. else
  282. display = XOpenDisplay(NULL);
  283. if (!display) {
  284. blog(LOG_ERROR, "Unable to open new X connection!");
  285. return NULL;
  286. }
  287. xcb_conn = XGetXCBConnection(display);
  288. if (!xcb_conn) {
  289. blog(LOG_ERROR, "Unable to get XCB connection to main display");
  290. goto error;
  291. }
  292. screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
  293. screen = screen_iterator.data;
  294. if (!screen) {
  295. blog(LOG_ERROR, "Unable to get screen root");
  296. goto error;
  297. }
  298. screen_num = get_screen_num_from_root(xcb_conn, screen->root);
  299. if (screen_num == -1) {
  300. blog(LOG_ERROR, "Unable to get screen number from root");
  301. goto error;
  302. }
  303. if (!gladLoadEGL()) {
  304. blog(LOG_ERROR, "Unable to load EGL entry functions.");
  305. goto error;
  306. }
  307. return display;
  308. error:
  309. XCloseDisplay(display);
  310. return NULL;
  311. }
  312. static int x_error_handler(Display *display, XErrorEvent *error)
  313. {
  314. char str1[512];
  315. char str2[512];
  316. char str3[512];
  317. XGetErrorText(display, error->error_code, str1, sizeof(str1));
  318. XGetErrorText(display, error->request_code, str2, sizeof(str2));
  319. XGetErrorText(display, error->minor_code, str3, sizeof(str3));
  320. blog(LOG_ERROR,
  321. "X Error: %s, Major opcode: %s, "
  322. "Minor opcode: %s, Serial: %lu",
  323. str1, str2, str3, error->serial);
  324. return 0;
  325. }
  326. static struct gl_platform *gl_x11_egl_platform_create(gs_device_t *device,
  327. uint32_t adapter)
  328. {
  329. /* There's some trickery here... we're mixing libX11, xcb, and EGL
  330. For an explanation see here: http://xcb.freedesktop.org/MixingCalls/
  331. Essentially, EGL requires Xlib. Everything else we use xcb. */
  332. struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
  333. Display *platform_display = obs_get_nix_platform_display();
  334. Display *display = open_windowless_display(platform_display);
  335. if (!display) {
  336. goto fail_display_open;
  337. }
  338. XSetEventQueueOwner(display, XCBOwnsEventQueue);
  339. XSetErrorHandler(x_error_handler);
  340. /* We assume later that cur_swap is already set. */
  341. device->plat = plat;
  342. plat->xdisplay = display;
  343. if (!gl_context_create(plat)) {
  344. blog(LOG_ERROR, "Failed to create context!");
  345. goto fail_context_create;
  346. }
  347. if (!eglMakeCurrent(plat->edisplay, plat->pbuffer, plat->pbuffer,
  348. plat->context)) {
  349. blog(LOG_ERROR, "Failed to make context current: %s",
  350. get_egl_error_string());
  351. goto fail_make_current;
  352. }
  353. if (!gladLoadGL()) {
  354. blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
  355. goto fail_load_gl;
  356. }
  357. goto success;
  358. fail_make_current:
  359. gl_context_destroy(plat);
  360. fail_context_create:
  361. fail_load_gl:
  362. XCloseDisplay(display);
  363. fail_display_open:
  364. bfree(plat);
  365. plat = NULL;
  366. success:
  367. UNUSED_PARAMETER(adapter);
  368. return plat;
  369. }
  370. static void gl_x11_egl_platform_destroy(struct gl_platform *plat)
  371. {
  372. if (!plat)
  373. return;
  374. gl_context_destroy(plat);
  375. eglTerminate(plat->edisplay);
  376. bfree(plat);
  377. }
  378. static bool gl_x11_egl_platform_init_swapchain(struct gs_swap_chain *swap)
  379. {
  380. const struct gl_platform *plat = swap->device->plat;
  381. Display *display = plat->xdisplay;
  382. xcb_connection_t *xcb_conn = XGetXCBConnection(display);
  383. xcb_window_t wid = xcb_generate_id(xcb_conn);
  384. xcb_window_t parent = swap->info.window.id;
  385. xcb_get_geometry_reply_t *geometry =
  386. get_window_geometry(xcb_conn, parent);
  387. bool status = false;
  388. int screen_num;
  389. int visual;
  390. if (!geometry)
  391. goto fail_geometry_request;
  392. screen_num = get_screen_num_from_root(xcb_conn, geometry->root);
  393. if (screen_num == -1) {
  394. goto fail_screen;
  395. }
  396. {
  397. if (!eglGetConfigAttrib(plat->edisplay, plat->config,
  398. EGL_NATIVE_VISUAL_ID,
  399. (EGLint *)&visual)) {
  400. blog(LOG_ERROR,
  401. "Cannot get visual id for EGL context: %s",
  402. get_egl_error_string());
  403. goto fail_visual_id;
  404. }
  405. }
  406. xcb_colormap_t colormap = xcb_generate_id(xcb_conn);
  407. uint32_t mask = XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP;
  408. uint32_t mask_values[] = {0, colormap, 0};
  409. xcb_create_colormap(xcb_conn, XCB_COLORMAP_ALLOC_NONE, colormap, parent,
  410. visual);
  411. xcb_create_window(xcb_conn, 24 /* Hardcoded? */, wid, parent, 0, 0,
  412. geometry->width, geometry->height, 0, 0, visual, mask,
  413. mask_values);
  414. const EGLSurface surface =
  415. eglCreateWindowSurface(plat->edisplay, plat->config, wid, 0);
  416. if (EGL_NO_SURFACE == surface) {
  417. blog(LOG_ERROR, "Cannot get window EGL surface: %s",
  418. get_egl_error_string());
  419. goto fail_window_surface;
  420. }
  421. swap->wi->config = plat->config;
  422. swap->wi->window = wid;
  423. swap->wi->surface = surface;
  424. swap->wi->screen = screen_num;
  425. xcb_map_window(xcb_conn, wid);
  426. status = true;
  427. goto success;
  428. fail_window_surface:
  429. fail_visual_id:
  430. fail_screen:
  431. fail_geometry_request:
  432. success:
  433. free(geometry);
  434. return status;
  435. }
  436. static void gl_x11_egl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
  437. {
  438. UNUSED_PARAMETER(swap);
  439. /* Really nothing to clean up? */
  440. }
  441. static void gl_x11_egl_device_enter_context(gs_device_t *device)
  442. {
  443. const EGLContext context = device->plat->context;
  444. const EGLDisplay display = device->plat->edisplay;
  445. const EGLSurface surface = (device->cur_swap)
  446. ? device->cur_swap->wi->surface
  447. : device->plat->pbuffer;
  448. if (!eglMakeCurrent(display, surface, surface, context))
  449. blog(LOG_ERROR, "Failed to make context current: %s",
  450. get_egl_error_string());
  451. }
  452. static void gl_x11_egl_device_leave_context(gs_device_t *device)
  453. {
  454. const EGLDisplay display = device->plat->edisplay;
  455. if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE,
  456. EGL_NO_CONTEXT)) {
  457. blog(LOG_ERROR, "Failed to reset current context: %s",
  458. get_egl_error_string());
  459. }
  460. }
  461. static void *gl_x11_egl_device_get_device_obj(gs_device_t *device)
  462. {
  463. return device->plat->context;
  464. }
  465. static void gl_x11_egl_getclientsize(const struct gs_swap_chain *swap,
  466. uint32_t *width, uint32_t *height)
  467. {
  468. xcb_connection_t *xcb_conn =
  469. XGetXCBConnection(swap->device->plat->xdisplay);
  470. xcb_window_t window = swap->wi->window;
  471. xcb_get_geometry_reply_t *geometry =
  472. get_window_geometry(xcb_conn, window);
  473. if (geometry) {
  474. *width = geometry->width;
  475. *height = geometry->height;
  476. }
  477. free(geometry);
  478. }
  479. static void gl_x11_egl_update(gs_device_t *device)
  480. {
  481. Display *display = device->plat->xdisplay;
  482. xcb_window_t window = device->cur_swap->wi->window;
  483. uint32_t values[] = {device->cur_swap->info.cx,
  484. device->cur_swap->info.cy};
  485. xcb_configure_window(XGetXCBConnection(display), window,
  486. XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
  487. values);
  488. }
  489. static void gl_x11_egl_clear_context(gs_device_t *device)
  490. {
  491. Display *display = device->plat->edisplay;
  492. if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE,
  493. EGL_NO_CONTEXT)) {
  494. blog(LOG_ERROR, "Failed to reset current context.");
  495. }
  496. }
  497. static void gl_x11_egl_device_load_swapchain(gs_device_t *device,
  498. gs_swapchain_t *swap)
  499. {
  500. if (device->cur_swap == swap)
  501. return;
  502. device->cur_swap = swap;
  503. device_enter_context(device);
  504. }
  505. enum swap_type {
  506. SWAP_TYPE_NORMAL,
  507. SWAP_TYPE_EXT,
  508. SWAP_TYPE_MESA,
  509. SWAP_TYPE_SGI,
  510. };
  511. static void gl_x11_egl_device_present(gs_device_t *device)
  512. {
  513. Display *display = device->plat->xdisplay;
  514. xcb_connection_t *xcb_conn = XGetXCBConnection(display);
  515. xcb_generic_event_t *xcb_event;
  516. while ((xcb_event = xcb_poll_for_event(xcb_conn))) {
  517. free(xcb_event);
  518. }
  519. if (!eglSwapBuffers(device->plat->edisplay,
  520. device->cur_swap->wi->surface))
  521. blog(LOG_ERROR, "Cannot swap EGL buffers: %s",
  522. get_egl_error_string());
  523. }
  524. static struct gs_texture *gl_x11_egl_device_texture_create_from_dmabuf(
  525. gs_device_t *device, unsigned int width, unsigned int height,
  526. uint32_t drm_format, enum gs_color_format color_format,
  527. uint32_t n_planes, const int *fds, const uint32_t *strides,
  528. const uint32_t *offsets, const uint64_t *modifiers)
  529. {
  530. struct gl_platform *plat = device->plat;
  531. return gl_egl_create_dmabuf_image(plat->edisplay, width, height,
  532. drm_format, color_format, n_planes,
  533. fds, strides, offsets, modifiers);
  534. }
  535. static bool gl_x11_egl_device_query_dmabuf_capabilities(
  536. gs_device_t *device, enum gs_dmabuf_flags *dmabuf_flags,
  537. uint32_t **drm_formats, size_t *n_formats)
  538. {
  539. struct gl_platform *plat = device->plat;
  540. return gl_egl_query_dmabuf_capabilities(plat->xdisplay, dmabuf_flags,
  541. drm_formats, n_formats);
  542. }
  543. static bool gl_x11_egl_device_query_dmabuf_modifiers_for_format(
  544. gs_device_t *device, uint32_t drm_format, uint64_t **modifiers,
  545. size_t *n_modifiers)
  546. {
  547. struct gl_platform *plat = device->plat;
  548. return gl_egl_query_dmabuf_modifiers_for_format(
  549. plat->xdisplay, drm_format, modifiers, n_modifiers);
  550. }
  551. static const struct gl_winsys_vtable egl_x11_winsys_vtable = {
  552. .windowinfo_create = gl_x11_egl_windowinfo_create,
  553. .windowinfo_destroy = gl_x11_egl_windowinfo_destroy,
  554. .platform_create = gl_x11_egl_platform_create,
  555. .platform_destroy = gl_x11_egl_platform_destroy,
  556. .platform_init_swapchain = gl_x11_egl_platform_init_swapchain,
  557. .platform_cleanup_swapchain = gl_x11_egl_platform_cleanup_swapchain,
  558. .device_enter_context = gl_x11_egl_device_enter_context,
  559. .device_leave_context = gl_x11_egl_device_leave_context,
  560. .device_get_device_obj = gl_x11_egl_device_get_device_obj,
  561. .getclientsize = gl_x11_egl_getclientsize,
  562. .clear_context = gl_x11_egl_clear_context,
  563. .update = gl_x11_egl_update,
  564. .device_load_swapchain = gl_x11_egl_device_load_swapchain,
  565. .device_present = gl_x11_egl_device_present,
  566. .device_texture_create_from_dmabuf =
  567. gl_x11_egl_device_texture_create_from_dmabuf,
  568. .device_query_dmabuf_capabilities =
  569. gl_x11_egl_device_query_dmabuf_capabilities,
  570. .device_query_dmabuf_modifiers_for_format =
  571. gl_x11_egl_device_query_dmabuf_modifiers_for_format,
  572. };
  573. const struct gl_winsys_vtable *gl_x11_egl_get_winsys_vtable(void)
  574. {
  575. return &egl_x11_winsys_vtable;
  576. }