gl-wayland-egl.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /******************************************************************************
  2. Copyright (C) 2019 by Jason Francis <[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. #include "gl-wayland-egl.h"
  15. #include <wayland-client.h>
  16. #include <wayland-egl.h>
  17. #include "gl-egl-common.h"
  18. #include <glad/glad_egl.h>
  19. static const EGLint config_attribs_native[] = {EGL_SURFACE_TYPE,
  20. EGL_WINDOW_BIT,
  21. EGL_RENDERABLE_TYPE,
  22. EGL_OPENGL_BIT,
  23. EGL_STENCIL_SIZE,
  24. 0,
  25. EGL_DEPTH_SIZE,
  26. 0,
  27. EGL_BUFFER_SIZE,
  28. 32,
  29. EGL_ALPHA_SIZE,
  30. 8,
  31. EGL_NATIVE_RENDERABLE,
  32. EGL_TRUE,
  33. EGL_NONE};
  34. static const EGLint config_attribs[] = {EGL_SURFACE_TYPE,
  35. EGL_WINDOW_BIT,
  36. EGL_RENDERABLE_TYPE,
  37. EGL_OPENGL_BIT,
  38. EGL_STENCIL_SIZE,
  39. 0,
  40. EGL_DEPTH_SIZE,
  41. 0,
  42. EGL_BUFFER_SIZE,
  43. 32,
  44. EGL_ALPHA_SIZE,
  45. 8,
  46. EGL_NONE};
  47. static const EGLint ctx_attribs[] = {
  48. #ifdef _DEBUG
  49. EGL_CONTEXT_OPENGL_DEBUG,
  50. EGL_TRUE,
  51. #endif
  52. EGL_CONTEXT_OPENGL_PROFILE_MASK,
  53. EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
  54. EGL_CONTEXT_MAJOR_VERSION,
  55. 3,
  56. EGL_CONTEXT_MINOR_VERSION,
  57. 3,
  58. EGL_NONE};
  59. static const EGLint khr_ctx_attribs[] = {
  60. #ifdef _DEBUG
  61. EGL_CONTEXT_FLAGS_KHR,
  62. EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
  63. #endif
  64. EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
  65. EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
  66. EGL_CONTEXT_MAJOR_VERSION_KHR,
  67. 3,
  68. EGL_CONTEXT_MINOR_VERSION_KHR,
  69. 3,
  70. EGL_NONE};
  71. struct gl_windowinfo {
  72. struct wl_egl_window *window;
  73. EGLSurface egl_surface;
  74. };
  75. struct gl_platform {
  76. struct wl_display *wl_display;
  77. EGLDisplay display;
  78. EGLConfig config;
  79. EGLContext context;
  80. int drm_fd;
  81. };
  82. struct gl_windowinfo *gl_wayland_egl_windowinfo_create(const struct gs_init_data *info)
  83. {
  84. struct wl_egl_window *window = wl_egl_window_create(info->window.display, info->cx, info->cy);
  85. if (window == NULL) {
  86. blog(LOG_ERROR, "wl_egl_window_create failed");
  87. return NULL;
  88. }
  89. struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo));
  90. wi->window = window;
  91. return wi;
  92. }
  93. static void gl_wayland_egl_windowinfo_destroy(struct gl_windowinfo *info)
  94. {
  95. wl_egl_window_destroy(info->window);
  96. bfree(info);
  97. }
  98. static bool egl_make_current(EGLDisplay display, EGLSurface surface, EGLContext context)
  99. {
  100. if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
  101. blog(LOG_ERROR, "eglBindAPI failed");
  102. }
  103. if (!eglMakeCurrent(display, surface, surface, context)) {
  104. blog(LOG_ERROR, "eglMakeCurrent failed");
  105. return false;
  106. }
  107. if (surface != EGL_NO_SURFACE)
  108. glDrawBuffer(GL_BACK);
  109. return true;
  110. }
  111. static bool egl_context_create(struct gl_platform *plat, const EGLint *attribs)
  112. {
  113. bool success = false;
  114. EGLint num_config;
  115. if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
  116. blog(LOG_ERROR, "eglBindAPI failed");
  117. }
  118. EGLBoolean result = eglChooseConfig(plat->display, config_attribs_native, &plat->config, 1, &num_config);
  119. if (result != EGL_TRUE || num_config == 0) {
  120. result = eglChooseConfig(plat->display, config_attribs, &plat->config, 1, &num_config);
  121. if (result != EGL_TRUE || num_config == 0) {
  122. blog(LOG_ERROR, "eglChooseConfig failed");
  123. goto error;
  124. }
  125. }
  126. plat->context = eglCreateContext(plat->display, plat->config, EGL_NO_CONTEXT, attribs);
  127. if (plat->context == EGL_NO_CONTEXT) {
  128. blog(LOG_ERROR, "eglCreateContext failed");
  129. goto error;
  130. }
  131. success = egl_make_current(plat->display, EGL_NO_SURFACE, plat->context);
  132. error:
  133. return success;
  134. }
  135. static void egl_context_destroy(struct gl_platform *plat)
  136. {
  137. egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  138. eglDestroyContext(plat->display, plat->context);
  139. }
  140. static bool extension_supported(const char *extensions, const char *search)
  141. {
  142. const char *result = strstr(extensions, search);
  143. unsigned long len = strlen(search);
  144. return result != NULL && (result == extensions || *(result - 1) == ' ') &&
  145. (result[len] == ' ' || result[len] == '\0');
  146. }
  147. static struct gl_platform *gl_wayland_egl_platform_create(gs_device_t *device, uint32_t adapter)
  148. {
  149. struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
  150. plat->wl_display = obs_get_nix_platform_display();
  151. device->plat = plat;
  152. const EGLAttrib plat_attribs[] = {EGL_NONE};
  153. plat->display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_EXT, plat->wl_display, plat_attribs);
  154. if (plat->display == EGL_NO_DISPLAY) {
  155. blog(LOG_ERROR, "eglGetDisplay failed");
  156. goto fail_display_init;
  157. }
  158. EGLint major;
  159. EGLint minor;
  160. if (eglInitialize(plat->display, &major, &minor) == EGL_FALSE) {
  161. blog(LOG_ERROR, "eglInitialize failed");
  162. goto fail_display_init;
  163. }
  164. blog(LOG_INFO, "Initialized EGL %d.%d", major, minor);
  165. const char *extensions = eglQueryString(plat->display, EGL_EXTENSIONS);
  166. blog(LOG_DEBUG, "Supported EGL Extensions: %s", extensions);
  167. const EGLint *attribs = ctx_attribs;
  168. if (major == 1 && minor == 4) {
  169. if (extension_supported(extensions, "EGL_KHR_create_context")) {
  170. attribs = khr_ctx_attribs;
  171. } else {
  172. blog(LOG_ERROR, "EGL_KHR_create_context extension is required to use EGL 1.4.");
  173. goto fail_context_create;
  174. }
  175. } else if (major < 1 || (major == 1 && minor < 4)) {
  176. blog(LOG_ERROR, "EGL 1.4 or higher is required.");
  177. goto fail_context_create;
  178. }
  179. if (!egl_context_create(plat, attribs)) {
  180. goto fail_context_create;
  181. }
  182. if (!gladLoadGL()) {
  183. blog(LOG_ERROR, "Failed to load OpenGL entry functions.");
  184. goto fail_load_gl;
  185. }
  186. if (!gladLoadEGL()) {
  187. blog(LOG_ERROR, "Unable to load EGL entry functions.");
  188. goto fail_load_egl;
  189. }
  190. plat->drm_fd = get_drm_render_node_fd(plat->display);
  191. if (plat->drm_fd < 0) {
  192. blog(LOG_WARNING, "Unable to open DRM render node.");
  193. }
  194. goto success;
  195. fail_load_egl:
  196. fail_load_gl:
  197. egl_context_destroy(plat);
  198. fail_context_create:
  199. eglTerminate(plat->display);
  200. fail_display_init:
  201. bfree(plat);
  202. plat = NULL;
  203. success:
  204. UNUSED_PARAMETER(adapter);
  205. return plat;
  206. }
  207. static void gl_wayland_egl_platform_destroy(struct gl_platform *plat)
  208. {
  209. if (plat) {
  210. egl_context_destroy(plat);
  211. eglTerminate(plat->display);
  212. close_drm_render_node_fd(plat->drm_fd);
  213. bfree(plat);
  214. }
  215. }
  216. static bool gl_wayland_egl_platform_init_swapchain(struct gs_swap_chain *swap)
  217. {
  218. struct gl_platform *plat = swap->device->plat;
  219. EGLSurface egl_surface = eglCreateWindowSurface(plat->display, plat->config, swap->wi->window, NULL);
  220. if (egl_surface == EGL_NO_SURFACE) {
  221. blog(LOG_ERROR, "eglCreateWindowSurface failed");
  222. return false;
  223. }
  224. swap->wi->egl_surface = egl_surface;
  225. return true;
  226. }
  227. static void gl_wayland_egl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
  228. {
  229. struct gl_platform *plat = swap->device->plat;
  230. eglDestroySurface(plat->display, swap->wi->egl_surface);
  231. }
  232. static void gl_wayland_egl_device_enter_context(gs_device_t *device)
  233. {
  234. struct gl_platform *plat = device->plat;
  235. EGLSurface surface = EGL_NO_SURFACE;
  236. if (device->cur_swap != NULL)
  237. surface = device->cur_swap->wi->egl_surface;
  238. egl_make_current(plat->display, surface, plat->context);
  239. }
  240. static void gl_wayland_egl_device_leave_context(gs_device_t *device)
  241. {
  242. struct gl_platform *plat = device->plat;
  243. egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  244. }
  245. static void *gl_wayland_egl_device_get_device_obj(gs_device_t *device)
  246. {
  247. return device->plat->context;
  248. }
  249. static void gl_wayland_egl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width, uint32_t *height)
  250. {
  251. wl_egl_window_get_attached_size(swap->wi->window, (void *)width, (void *)height);
  252. }
  253. static void gl_wayland_egl_clear_context(gs_device_t *device)
  254. {
  255. struct gl_platform *plat = device->plat;
  256. egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  257. }
  258. static void gl_wayland_egl_update(gs_device_t *device)
  259. {
  260. wl_egl_window_resize(device->cur_swap->wi->window, device->cur_swap->info.cx, device->cur_swap->info.cy, 0, 0);
  261. }
  262. static void gl_wayland_egl_device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
  263. {
  264. if (device->cur_swap == swap)
  265. return;
  266. device->cur_swap = swap;
  267. struct gl_platform *plat = device->plat;
  268. if (swap == NULL) {
  269. egl_make_current(plat->display, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  270. } else {
  271. egl_make_current(plat->display, swap->wi->egl_surface, plat->context);
  272. }
  273. }
  274. static void gl_wayland_egl_device_present(gs_device_t *device)
  275. {
  276. struct gl_platform *plat = device->plat;
  277. struct gl_windowinfo *wi = device->cur_swap->wi;
  278. if (eglSwapInterval(plat->display, 0) == EGL_FALSE) {
  279. blog(LOG_ERROR, "eglSwapInterval failed");
  280. }
  281. if (eglSwapBuffers(plat->display, wi->egl_surface) == EGL_FALSE) {
  282. blog(LOG_ERROR, "eglSwapBuffers failed");
  283. }
  284. }
  285. static struct gs_texture *
  286. gl_wayland_egl_device_texture_create_from_dmabuf(gs_device_t *device, unsigned int width, unsigned int height,
  287. uint32_t drm_format, enum gs_color_format color_format,
  288. uint32_t n_planes, const int *fds, const uint32_t *strides,
  289. const uint32_t *offsets, const uint64_t *modifiers)
  290. {
  291. struct gl_platform *plat = device->plat;
  292. return gl_egl_create_dmabuf_image(plat->display, width, height, drm_format, color_format, n_planes, fds,
  293. strides, offsets, modifiers);
  294. }
  295. static bool gl_wayland_egl_device_query_dmabuf_capabilities(gs_device_t *device, enum gs_dmabuf_flags *dmabuf_flags,
  296. uint32_t **drm_formats, size_t *n_formats)
  297. {
  298. struct gl_platform *plat = device->plat;
  299. return gl_egl_query_dmabuf_capabilities(plat->display, dmabuf_flags, drm_formats, n_formats);
  300. }
  301. static bool gl_wayland_egl_device_query_dmabuf_modifiers_for_format(gs_device_t *device, uint32_t drm_format,
  302. uint64_t **modifiers, size_t *n_modifiers)
  303. {
  304. struct gl_platform *plat = device->plat;
  305. return gl_egl_query_dmabuf_modifiers_for_format(plat->display, drm_format, modifiers, n_modifiers);
  306. }
  307. static struct gs_texture *gl_wayland_egl_device_texture_create_from_pixmap(gs_device_t *device, uint32_t width,
  308. uint32_t height,
  309. enum gs_color_format color_format,
  310. uint32_t target, void *pixmap)
  311. {
  312. UNUSED_PARAMETER(device);
  313. UNUSED_PARAMETER(width);
  314. UNUSED_PARAMETER(height);
  315. UNUSED_PARAMETER(color_format);
  316. UNUSED_PARAMETER(target);
  317. UNUSED_PARAMETER(pixmap);
  318. return NULL;
  319. }
  320. static bool gl_wayland_egl_enum_adapters(gs_device_t *device,
  321. bool (*callback)(void *param, const char *name, uint32_t id), void *param)
  322. {
  323. return gl_egl_enum_adapters(device->plat->display, callback, param);
  324. }
  325. static bool gl_wayland_egl_device_query_sync_capabilities(gs_device_t *device)
  326. {
  327. struct gl_platform *plat = device->plat;
  328. return gl_egl_query_sync_capabilities(plat->drm_fd);
  329. }
  330. static gs_sync_t *gl_wayland_egl_device_sync_create(gs_device_t *device)
  331. {
  332. struct gl_platform *plat = device->plat;
  333. return gl_egl_create_sync(plat->display);
  334. }
  335. static gs_sync_t *gl_wayland_egl_device_sync_create_from_syncobj_timeline_point(gs_device_t *device, int syncobj_fd,
  336. uint64_t timeline_point)
  337. {
  338. struct gl_platform *plat = device->plat;
  339. return gl_egl_create_sync_from_syncobj_timeline_point(plat->display, plat->drm_fd, syncobj_fd, timeline_point);
  340. }
  341. static void gl_wayland_egl_device_sync_destroy(gs_device_t *device, gs_sync_t *sync)
  342. {
  343. struct gl_platform *plat = device->plat;
  344. gl_egl_device_sync_destroy(plat->display, sync);
  345. }
  346. static bool gl_wayland_egl_device_sync_export_syncobj_timeline_point(gs_device_t *device, gs_sync_t *sync,
  347. int syncobj_fd, uint64_t timeline_point)
  348. {
  349. struct gl_platform *plat = device->plat;
  350. return gl_egl_sync_export_syncobj_timeline_point(plat->display, sync, plat->drm_fd, syncobj_fd, timeline_point);
  351. }
  352. static bool gl_wayland_egl_device_sync_signal_syncobj_timeline_point(gs_device_t *device, int syncobj_fd,
  353. uint64_t timeline_point)
  354. {
  355. struct gl_platform *plat = device->plat;
  356. return gl_egl_sync_signal_syncobj_timeline_point(plat->drm_fd, syncobj_fd, timeline_point);
  357. }
  358. static bool gl_wayland_egl_device_sync_wait(gs_device_t *device, gs_sync_t *sync)
  359. {
  360. struct gl_platform *plat = device->plat;
  361. return gl_egl_sync_wait(plat->display, sync);
  362. }
  363. static const struct gl_winsys_vtable egl_wayland_winsys_vtable = {
  364. .windowinfo_create = gl_wayland_egl_windowinfo_create,
  365. .windowinfo_destroy = gl_wayland_egl_windowinfo_destroy,
  366. .platform_create = gl_wayland_egl_platform_create,
  367. .platform_destroy = gl_wayland_egl_platform_destroy,
  368. .platform_init_swapchain = gl_wayland_egl_platform_init_swapchain,
  369. .platform_cleanup_swapchain = gl_wayland_egl_platform_cleanup_swapchain,
  370. .device_enter_context = gl_wayland_egl_device_enter_context,
  371. .device_leave_context = gl_wayland_egl_device_leave_context,
  372. .device_get_device_obj = gl_wayland_egl_device_get_device_obj,
  373. .getclientsize = gl_wayland_egl_getclientsize,
  374. .clear_context = gl_wayland_egl_clear_context,
  375. .update = gl_wayland_egl_update,
  376. .device_load_swapchain = gl_wayland_egl_device_load_swapchain,
  377. .device_present = gl_wayland_egl_device_present,
  378. .device_texture_create_from_dmabuf = gl_wayland_egl_device_texture_create_from_dmabuf,
  379. .device_query_dmabuf_capabilities = gl_wayland_egl_device_query_dmabuf_capabilities,
  380. .device_query_dmabuf_modifiers_for_format = gl_wayland_egl_device_query_dmabuf_modifiers_for_format,
  381. .device_texture_create_from_pixmap = gl_wayland_egl_device_texture_create_from_pixmap,
  382. .device_enum_adapters = gl_wayland_egl_enum_adapters,
  383. .device_query_sync_capabilities = gl_wayland_egl_device_query_sync_capabilities,
  384. .device_sync_create = gl_wayland_egl_device_sync_create,
  385. .device_sync_create_from_syncobj_timeline_point = gl_wayland_egl_device_sync_create_from_syncobj_timeline_point,
  386. .device_sync_destroy = gl_wayland_egl_device_sync_destroy,
  387. .device_sync_export_syncobj_timeline_point = gl_wayland_egl_device_sync_export_syncobj_timeline_point,
  388. .device_sync_signal_syncobj_timeline_point = gl_wayland_egl_device_sync_signal_syncobj_timeline_point,
  389. .device_sync_wait = gl_wayland_egl_device_sync_wait,
  390. };
  391. const struct gl_winsys_vtable *gl_wayland_egl_get_winsys_vtable(void)
  392. {
  393. return &egl_wayland_winsys_vtable;
  394. }