egl_context.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. //========================================================================
  2. // GLFW 3.4 EGL - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2002-2006 Marcus Geelnard
  5. // Copyright (c) 2006-2019 Camilla Löwy <[email protected]>
  6. //
  7. // This software is provided 'as-is', without any express or implied
  8. // warranty. In no event will the authors be held liable for any damages
  9. // arising from the use of this software.
  10. //
  11. // Permission is granted to anyone to use this software for any purpose,
  12. // including commercial applications, and to alter it and redistribute it
  13. // freely, subject to the following restrictions:
  14. //
  15. // 1. The origin of this software must not be misrepresented; you must not
  16. // claim that you wrote the original software. If you use this software
  17. // in a product, an acknowledgment in the product documentation would
  18. // be appreciated but is not required.
  19. //
  20. // 2. Altered source versions must be plainly marked as such, and must not
  21. // be misrepresented as being the original software.
  22. //
  23. // 3. This notice may not be removed or altered from any source
  24. // distribution.
  25. //
  26. //========================================================================
  27. // Please use C89 style variable declarations in this file because VS 2010
  28. //========================================================================
  29. #include "internal.h"
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <assert.h>
  34. // Return a description of the specified EGL error
  35. //
  36. static const char* getEGLErrorString(EGLint error)
  37. {
  38. switch (error)
  39. {
  40. case EGL_SUCCESS:
  41. return "Success";
  42. case EGL_NOT_INITIALIZED:
  43. return "EGL is not or could not be initialized";
  44. case EGL_BAD_ACCESS:
  45. return "EGL cannot access a requested resource";
  46. case EGL_BAD_ALLOC:
  47. return "EGL failed to allocate resources for the requested operation";
  48. case EGL_BAD_ATTRIBUTE:
  49. return "An unrecognized attribute or attribute value was passed in the attribute list";
  50. case EGL_BAD_CONTEXT:
  51. return "An EGLContext argument does not name a valid EGL rendering context";
  52. case EGL_BAD_CONFIG:
  53. return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
  54. case EGL_BAD_CURRENT_SURFACE:
  55. return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
  56. case EGL_BAD_DISPLAY:
  57. return "An EGLDisplay argument does not name a valid EGL display connection";
  58. case EGL_BAD_SURFACE:
  59. return "An EGLSurface argument does not name a valid surface configured for GL rendering";
  60. case EGL_BAD_MATCH:
  61. return "Arguments are inconsistent";
  62. case EGL_BAD_PARAMETER:
  63. return "One or more argument values are invalid";
  64. case EGL_BAD_NATIVE_PIXMAP:
  65. return "A NativePixmapType argument does not refer to a valid native pixmap";
  66. case EGL_BAD_NATIVE_WINDOW:
  67. return "A NativeWindowType argument does not refer to a valid native window";
  68. case EGL_CONTEXT_LOST:
  69. return "The application must destroy all contexts and reinitialise";
  70. default:
  71. return "ERROR: UNKNOWN EGL ERROR";
  72. }
  73. }
  74. // Returns the specified attribute of the specified EGLConfig
  75. //
  76. static int getEGLConfigAttrib(EGLConfig config, int attrib)
  77. {
  78. int value;
  79. eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
  80. return value;
  81. }
  82. // Return the EGLConfig most closely matching the specified hints
  83. //
  84. static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
  85. const _GLFWfbconfig* fbconfig,
  86. EGLConfig* result)
  87. {
  88. EGLConfig* nativeConfigs;
  89. _GLFWfbconfig* usableConfigs;
  90. const _GLFWfbconfig* closest;
  91. int i, nativeCount, usableCount, apiBit;
  92. GLFWbool wrongApiAvailable = GLFW_FALSE;
  93. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  94. {
  95. if (ctxconfig->major == 1)
  96. apiBit = EGL_OPENGL_ES_BIT;
  97. else
  98. apiBit = EGL_OPENGL_ES2_BIT;
  99. }
  100. else
  101. apiBit = EGL_OPENGL_BIT;
  102. if (fbconfig->stereo)
  103. {
  104. _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");
  105. return GLFW_FALSE;
  106. }
  107. eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
  108. if (!nativeCount)
  109. {
  110. _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
  111. return GLFW_FALSE;
  112. }
  113. nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig));
  114. eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
  115. usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
  116. usableCount = 0;
  117. for (i = 0; i < nativeCount; i++)
  118. {
  119. const EGLConfig n = nativeConfigs[i];
  120. _GLFWfbconfig* u = usableConfigs + usableCount;
  121. // Only consider RGB(A) EGLConfigs
  122. if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
  123. continue;
  124. // Only consider window EGLConfigs
  125. if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
  126. continue;
  127. #if defined(_GLFW_X11)
  128. if (_glfw.platform.platformID == GLFW_PLATFORM_X11)
  129. {
  130. XVisualInfo vi = {0};
  131. // Only consider EGLConfigs with associated Visuals
  132. vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
  133. if (!vi.visualid)
  134. continue;
  135. if (fbconfig->transparent)
  136. {
  137. int count;
  138. XVisualInfo* vis =
  139. XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
  140. if (vis)
  141. {
  142. u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
  143. XFree(vis);
  144. }
  145. }
  146. }
  147. #endif // _GLFW_X11
  148. if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit))
  149. {
  150. wrongApiAvailable = GLFW_TRUE;
  151. continue;
  152. }
  153. u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
  154. u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
  155. u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
  156. u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
  157. u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
  158. u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
  159. #if defined(_GLFW_WAYLAND)
  160. if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
  161. {
  162. // NOTE: The wl_surface opaque region is no guarantee that its buffer
  163. // is presented as opaque, if it also has an alpha channel
  164. // HACK: If EGL_EXT_present_opaque is unavailable, ignore any config
  165. // with an alpha channel to ensure the buffer is opaque
  166. if (!_glfw.egl.EXT_present_opaque)
  167. {
  168. if (!fbconfig->transparent && u->alphaBits > 0)
  169. continue;
  170. }
  171. }
  172. #endif // _GLFW_WAYLAND
  173. u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
  174. u->doublebuffer = fbconfig->doublebuffer;
  175. u->handle = (uintptr_t) n;
  176. usableCount++;
  177. }
  178. closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
  179. if (closest)
  180. *result = (EGLConfig) closest->handle;
  181. else
  182. {
  183. if (wrongApiAvailable)
  184. {
  185. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  186. {
  187. if (ctxconfig->major == 1)
  188. {
  189. _glfwInputError(GLFW_API_UNAVAILABLE,
  190. "EGL: Failed to find support for OpenGL ES 1.x");
  191. }
  192. else
  193. {
  194. _glfwInputError(GLFW_API_UNAVAILABLE,
  195. "EGL: Failed to find support for OpenGL ES 2 or later");
  196. }
  197. }
  198. else
  199. {
  200. _glfwInputError(GLFW_API_UNAVAILABLE,
  201. "EGL: Failed to find support for OpenGL");
  202. }
  203. }
  204. else
  205. {
  206. _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
  207. "EGL: Failed to find a suitable EGLConfig");
  208. }
  209. }
  210. _glfw_free(nativeConfigs);
  211. _glfw_free(usableConfigs);
  212. return closest != NULL;
  213. }
  214. static void makeContextCurrentEGL(_GLFWwindow* window)
  215. {
  216. if (window)
  217. {
  218. if (!eglMakeCurrent(_glfw.egl.display,
  219. window->context.egl.surface,
  220. window->context.egl.surface,
  221. window->context.egl.handle))
  222. {
  223. _glfwInputError(GLFW_PLATFORM_ERROR,
  224. "EGL: Failed to make context current: %s",
  225. getEGLErrorString(eglGetError()));
  226. return;
  227. }
  228. }
  229. else
  230. {
  231. if (!eglMakeCurrent(_glfw.egl.display,
  232. EGL_NO_SURFACE,
  233. EGL_NO_SURFACE,
  234. EGL_NO_CONTEXT))
  235. {
  236. _glfwInputError(GLFW_PLATFORM_ERROR,
  237. "EGL: Failed to clear current context: %s",
  238. getEGLErrorString(eglGetError()));
  239. return;
  240. }
  241. }
  242. _glfwPlatformSetTls(&_glfw.contextSlot, window);
  243. }
  244. static void swapBuffersEGL(_GLFWwindow* window)
  245. {
  246. if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
  247. {
  248. _glfwInputError(GLFW_PLATFORM_ERROR,
  249. "EGL: The context must be current on the calling thread when swapping buffers");
  250. return;
  251. }
  252. #if defined(_GLFW_WAYLAND)
  253. if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
  254. {
  255. // NOTE: Swapping buffers on a hidden window on Wayland makes it visible
  256. if (!window->wl.visible)
  257. return;
  258. }
  259. #endif
  260. eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
  261. }
  262. static void swapIntervalEGL(int interval)
  263. {
  264. eglSwapInterval(_glfw.egl.display, interval);
  265. }
  266. static int extensionSupportedEGL(const char* extension)
  267. {
  268. const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
  269. if (extensions)
  270. {
  271. if (_glfwStringInExtensionString(extension, extensions))
  272. return GLFW_TRUE;
  273. }
  274. return GLFW_FALSE;
  275. }
  276. static GLFWglproc getProcAddressEGL(const char* procname)
  277. {
  278. _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
  279. assert(window != NULL);
  280. if (window->context.egl.client)
  281. {
  282. GLFWglproc proc = (GLFWglproc)
  283. _glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
  284. if (proc)
  285. return proc;
  286. }
  287. return eglGetProcAddress(procname);
  288. }
  289. static void destroyContextEGL(_GLFWwindow* window)
  290. {
  291. // NOTE: Do not unload libGL.so.1 while the X11 display is still open,
  292. // as it will make XCloseDisplay segfault
  293. if (_glfw.platform.platformID != GLFW_PLATFORM_X11 ||
  294. window->context.client != GLFW_OPENGL_API)
  295. {
  296. if (window->context.egl.client)
  297. {
  298. _glfwPlatformFreeModule(window->context.egl.client);
  299. window->context.egl.client = NULL;
  300. }
  301. }
  302. if (window->context.egl.surface)
  303. {
  304. eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
  305. window->context.egl.surface = EGL_NO_SURFACE;
  306. }
  307. if (window->context.egl.handle)
  308. {
  309. eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
  310. window->context.egl.handle = EGL_NO_CONTEXT;
  311. }
  312. }
  313. //////////////////////////////////////////////////////////////////////////
  314. ////// GLFW internal API //////
  315. //////////////////////////////////////////////////////////////////////////
  316. // Initialize EGL
  317. //
  318. GLFWbool _glfwInitEGL(void)
  319. {
  320. int i;
  321. EGLint* attribs = NULL;
  322. const char* extensions;
  323. const char* sonames[] =
  324. {
  325. #if defined(_GLFW_EGL_LIBRARY)
  326. _GLFW_EGL_LIBRARY,
  327. #elif defined(_GLFW_WIN32)
  328. "libEGL.dll",
  329. "EGL.dll",
  330. #elif defined(_GLFW_COCOA)
  331. "libEGL.dylib",
  332. #elif defined(__CYGWIN__)
  333. "libEGL-1.so",
  334. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  335. "libEGL.so",
  336. #else
  337. "libEGL.so.1",
  338. #endif
  339. NULL
  340. };
  341. if (_glfw.egl.handle)
  342. return GLFW_TRUE;
  343. for (i = 0; sonames[i]; i++)
  344. {
  345. _glfw.egl.handle = _glfwPlatformLoadModule(sonames[i]);
  346. if (_glfw.egl.handle)
  347. break;
  348. }
  349. if (!_glfw.egl.handle)
  350. {
  351. _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
  352. return GLFW_FALSE;
  353. }
  354. _glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
  355. _glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
  356. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigAttrib");
  357. _glfw.egl.GetConfigs = (PFN_eglGetConfigs)
  358. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigs");
  359. _glfw.egl.GetDisplay = (PFN_eglGetDisplay)
  360. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetDisplay");
  361. _glfw.egl.GetError = (PFN_eglGetError)
  362. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetError");
  363. _glfw.egl.Initialize = (PFN_eglInitialize)
  364. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglInitialize");
  365. _glfw.egl.Terminate = (PFN_eglTerminate)
  366. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglTerminate");
  367. _glfw.egl.BindAPI = (PFN_eglBindAPI)
  368. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglBindAPI");
  369. _glfw.egl.CreateContext = (PFN_eglCreateContext)
  370. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateContext");
  371. _glfw.egl.DestroySurface = (PFN_eglDestroySurface)
  372. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroySurface");
  373. _glfw.egl.DestroyContext = (PFN_eglDestroyContext)
  374. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext");
  375. _glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
  376. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface");
  377. _glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
  378. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent");
  379. _glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
  380. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapBuffers");
  381. _glfw.egl.SwapInterval = (PFN_eglSwapInterval)
  382. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapInterval");
  383. _glfw.egl.QueryString = (PFN_eglQueryString)
  384. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString");
  385. _glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
  386. _glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress");
  387. if (!_glfw.egl.GetConfigAttrib ||
  388. !_glfw.egl.GetConfigs ||
  389. !_glfw.egl.GetDisplay ||
  390. !_glfw.egl.GetError ||
  391. !_glfw.egl.Initialize ||
  392. !_glfw.egl.Terminate ||
  393. !_glfw.egl.BindAPI ||
  394. !_glfw.egl.CreateContext ||
  395. !_glfw.egl.DestroySurface ||
  396. !_glfw.egl.DestroyContext ||
  397. !_glfw.egl.CreateWindowSurface ||
  398. !_glfw.egl.MakeCurrent ||
  399. !_glfw.egl.SwapBuffers ||
  400. !_glfw.egl.SwapInterval ||
  401. !_glfw.egl.QueryString ||
  402. !_glfw.egl.GetProcAddress)
  403. {
  404. _glfwInputError(GLFW_PLATFORM_ERROR,
  405. "EGL: Failed to load required entry points");
  406. _glfwTerminateEGL();
  407. return GLFW_FALSE;
  408. }
  409. extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  410. if (extensions && eglGetError() == EGL_SUCCESS)
  411. _glfw.egl.EXT_client_extensions = GLFW_TRUE;
  412. if (_glfw.egl.EXT_client_extensions)
  413. {
  414. _glfw.egl.EXT_platform_base =
  415. _glfwStringInExtensionString("EGL_EXT_platform_base", extensions);
  416. _glfw.egl.EXT_platform_x11 =
  417. _glfwStringInExtensionString("EGL_EXT_platform_x11", extensions);
  418. _glfw.egl.EXT_platform_wayland =
  419. _glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions);
  420. _glfw.egl.ANGLE_platform_angle =
  421. _glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions);
  422. _glfw.egl.ANGLE_platform_angle_opengl =
  423. _glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions);
  424. _glfw.egl.ANGLE_platform_angle_d3d =
  425. _glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions);
  426. _glfw.egl.ANGLE_platform_angle_vulkan =
  427. _glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions);
  428. _glfw.egl.ANGLE_platform_angle_metal =
  429. _glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions);
  430. }
  431. if (_glfw.egl.EXT_platform_base)
  432. {
  433. _glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
  434. eglGetProcAddress("eglGetPlatformDisplayEXT");
  435. _glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
  436. eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
  437. }
  438. _glfw.egl.platform = _glfw.platform.getEGLPlatform(&attribs);
  439. if (_glfw.egl.platform)
  440. {
  441. _glfw.egl.display =
  442. eglGetPlatformDisplayEXT(_glfw.egl.platform,
  443. _glfw.platform.getEGLNativeDisplay(),
  444. attribs);
  445. }
  446. else
  447. _glfw.egl.display = eglGetDisplay(_glfw.platform.getEGLNativeDisplay());
  448. _glfw_free(attribs);
  449. if (_glfw.egl.display == EGL_NO_DISPLAY)
  450. {
  451. _glfwInputError(GLFW_API_UNAVAILABLE,
  452. "EGL: Failed to get EGL display: %s",
  453. getEGLErrorString(eglGetError()));
  454. _glfwTerminateEGL();
  455. return GLFW_FALSE;
  456. }
  457. if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
  458. {
  459. _glfwInputError(GLFW_API_UNAVAILABLE,
  460. "EGL: Failed to initialize EGL: %s",
  461. getEGLErrorString(eglGetError()));
  462. _glfwTerminateEGL();
  463. return GLFW_FALSE;
  464. }
  465. _glfw.egl.KHR_create_context =
  466. extensionSupportedEGL("EGL_KHR_create_context");
  467. _glfw.egl.KHR_create_context_no_error =
  468. extensionSupportedEGL("EGL_KHR_create_context_no_error");
  469. _glfw.egl.KHR_gl_colorspace =
  470. extensionSupportedEGL("EGL_KHR_gl_colorspace");
  471. _glfw.egl.KHR_get_all_proc_addresses =
  472. extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
  473. _glfw.egl.KHR_context_flush_control =
  474. extensionSupportedEGL("EGL_KHR_context_flush_control");
  475. _glfw.egl.EXT_present_opaque =
  476. extensionSupportedEGL("EGL_EXT_present_opaque");
  477. return GLFW_TRUE;
  478. }
  479. // Terminate EGL
  480. //
  481. void _glfwTerminateEGL(void)
  482. {
  483. if (_glfw.egl.display)
  484. {
  485. eglTerminate(_glfw.egl.display);
  486. _glfw.egl.display = EGL_NO_DISPLAY;
  487. }
  488. if (_glfw.egl.handle)
  489. {
  490. _glfwPlatformFreeModule(_glfw.egl.handle);
  491. _glfw.egl.handle = NULL;
  492. }
  493. }
  494. #define SET_ATTRIB(a, v) \
  495. { \
  496. assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
  497. attribs[index++] = a; \
  498. attribs[index++] = v; \
  499. }
  500. // Create the OpenGL or OpenGL ES context
  501. //
  502. GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
  503. const _GLFWctxconfig* ctxconfig,
  504. const _GLFWfbconfig* fbconfig)
  505. {
  506. EGLint attribs[40];
  507. EGLConfig config;
  508. EGLContext share = NULL;
  509. EGLNativeWindowType native;
  510. int index = 0;
  511. if (!_glfw.egl.display)
  512. {
  513. _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
  514. return GLFW_FALSE;
  515. }
  516. if (ctxconfig->share)
  517. share = ctxconfig->share->context.egl.handle;
  518. if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
  519. return GLFW_FALSE;
  520. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  521. {
  522. if (!eglBindAPI(EGL_OPENGL_ES_API))
  523. {
  524. _glfwInputError(GLFW_API_UNAVAILABLE,
  525. "EGL: Failed to bind OpenGL ES: %s",
  526. getEGLErrorString(eglGetError()));
  527. return GLFW_FALSE;
  528. }
  529. }
  530. else
  531. {
  532. if (!eglBindAPI(EGL_OPENGL_API))
  533. {
  534. _glfwInputError(GLFW_API_UNAVAILABLE,
  535. "EGL: Failed to bind OpenGL: %s",
  536. getEGLErrorString(eglGetError()));
  537. return GLFW_FALSE;
  538. }
  539. }
  540. if (_glfw.egl.KHR_create_context)
  541. {
  542. int mask = 0, flags = 0;
  543. if (ctxconfig->client == GLFW_OPENGL_API)
  544. {
  545. if (ctxconfig->forward)
  546. flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
  547. if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
  548. mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
  549. else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
  550. mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
  551. }
  552. if (ctxconfig->debug)
  553. flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
  554. if (ctxconfig->robustness)
  555. {
  556. if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
  557. {
  558. SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
  559. EGL_NO_RESET_NOTIFICATION_KHR);
  560. }
  561. else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
  562. {
  563. SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
  564. EGL_LOSE_CONTEXT_ON_RESET_KHR);
  565. }
  566. flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
  567. }
  568. if (ctxconfig->major != 1 || ctxconfig->minor != 0)
  569. {
  570. SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
  571. SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
  572. }
  573. if (ctxconfig->noerror)
  574. {
  575. if (_glfw.egl.KHR_create_context_no_error)
  576. SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
  577. }
  578. if (mask)
  579. SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
  580. if (flags)
  581. SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags);
  582. }
  583. else
  584. {
  585. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  586. SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
  587. }
  588. if (_glfw.egl.KHR_context_flush_control)
  589. {
  590. if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
  591. {
  592. SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
  593. EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
  594. }
  595. else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
  596. {
  597. SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
  598. EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
  599. }
  600. }
  601. SET_ATTRIB(EGL_NONE, EGL_NONE);
  602. window->context.egl.handle = eglCreateContext(_glfw.egl.display,
  603. config, share, attribs);
  604. if (window->context.egl.handle == EGL_NO_CONTEXT)
  605. {
  606. _glfwInputError(GLFW_VERSION_UNAVAILABLE,
  607. "EGL: Failed to create context: %s",
  608. getEGLErrorString(eglGetError()));
  609. return GLFW_FALSE;
  610. }
  611. // Set up attributes for surface creation
  612. index = 0;
  613. if (fbconfig->sRGB)
  614. {
  615. if (_glfw.egl.KHR_gl_colorspace)
  616. SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
  617. }
  618. if (!fbconfig->doublebuffer)
  619. SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
  620. if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
  621. {
  622. if (_glfw.egl.EXT_present_opaque)
  623. SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
  624. }
  625. SET_ATTRIB(EGL_NONE, EGL_NONE);
  626. native = _glfw.platform.getEGLNativeWindow(window);
  627. // HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
  628. // despite reporting EGL_EXT_platform_base
  629. if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
  630. {
  631. window->context.egl.surface =
  632. eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
  633. }
  634. else
  635. {
  636. window->context.egl.surface =
  637. eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
  638. }
  639. if (window->context.egl.surface == EGL_NO_SURFACE)
  640. {
  641. _glfwInputError(GLFW_PLATFORM_ERROR,
  642. "EGL: Failed to create window surface: %s",
  643. getEGLErrorString(eglGetError()));
  644. return GLFW_FALSE;
  645. }
  646. window->context.egl.config = config;
  647. // Load the appropriate client library
  648. if (!_glfw.egl.KHR_get_all_proc_addresses)
  649. {
  650. int i;
  651. const char** sonames;
  652. const char* es1sonames[] =
  653. {
  654. #if defined(_GLFW_GLESV1_LIBRARY)
  655. _GLFW_GLESV1_LIBRARY,
  656. #elif defined(_GLFW_WIN32)
  657. "GLESv1_CM.dll",
  658. "libGLES_CM.dll",
  659. #elif defined(_GLFW_COCOA)
  660. "libGLESv1_CM.dylib",
  661. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  662. "libGLESv1_CM.so",
  663. #else
  664. "libGLESv1_CM.so.1",
  665. "libGLES_CM.so.1",
  666. #endif
  667. NULL
  668. };
  669. const char* es2sonames[] =
  670. {
  671. #if defined(_GLFW_GLESV2_LIBRARY)
  672. _GLFW_GLESV2_LIBRARY,
  673. #elif defined(_GLFW_WIN32)
  674. "GLESv2.dll",
  675. "libGLESv2.dll",
  676. #elif defined(_GLFW_COCOA)
  677. "libGLESv2.dylib",
  678. #elif defined(__CYGWIN__)
  679. "libGLESv2-2.so",
  680. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  681. "libGLESv2.so",
  682. #else
  683. "libGLESv2.so.2",
  684. #endif
  685. NULL
  686. };
  687. const char* glsonames[] =
  688. {
  689. #if defined(_GLFW_OPENGL_LIBRARY)
  690. _GLFW_OPENGL_LIBRARY,
  691. #elif defined(_GLFW_WIN32)
  692. #elif defined(_GLFW_COCOA)
  693. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  694. "libGL.so",
  695. #else
  696. "libOpenGL.so.0",
  697. "libGL.so.1",
  698. #endif
  699. NULL
  700. };
  701. if (ctxconfig->client == GLFW_OPENGL_ES_API)
  702. {
  703. if (ctxconfig->major == 1)
  704. sonames = es1sonames;
  705. else
  706. sonames = es2sonames;
  707. }
  708. else
  709. sonames = glsonames;
  710. for (i = 0; sonames[i]; i++)
  711. {
  712. // HACK: Match presence of lib prefix to increase chance of finding
  713. // a matching pair in the jungle that is Win32 EGL/GLES
  714. if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
  715. continue;
  716. window->context.egl.client = _glfwPlatformLoadModule(sonames[i]);
  717. if (window->context.egl.client)
  718. break;
  719. }
  720. if (!window->context.egl.client)
  721. {
  722. _glfwInputError(GLFW_API_UNAVAILABLE,
  723. "EGL: Failed to load client library");
  724. return GLFW_FALSE;
  725. }
  726. }
  727. window->context.makeCurrent = makeContextCurrentEGL;
  728. window->context.swapBuffers = swapBuffersEGL;
  729. window->context.swapInterval = swapIntervalEGL;
  730. window->context.extensionSupported = extensionSupportedEGL;
  731. window->context.getProcAddress = getProcAddressEGL;
  732. window->context.destroy = destroyContextEGL;
  733. return GLFW_TRUE;
  734. }
  735. #undef SET_ATTRIB
  736. // Returns the Visual and depth of the chosen EGLConfig
  737. //
  738. #if defined(_GLFW_X11)
  739. GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
  740. const _GLFWctxconfig* ctxconfig,
  741. const _GLFWfbconfig* fbconfig,
  742. Visual** visual, int* depth)
  743. {
  744. XVisualInfo* result;
  745. XVisualInfo desired;
  746. EGLConfig native;
  747. EGLint visualID = 0, count = 0;
  748. const long vimask = VisualScreenMask | VisualIDMask;
  749. if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
  750. return GLFW_FALSE;
  751. eglGetConfigAttrib(_glfw.egl.display, native,
  752. EGL_NATIVE_VISUAL_ID, &visualID);
  753. desired.screen = _glfw.x11.screen;
  754. desired.visualid = visualID;
  755. result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
  756. if (!result)
  757. {
  758. _glfwInputError(GLFW_PLATFORM_ERROR,
  759. "EGL: Failed to retrieve Visual for EGLConfig");
  760. return GLFW_FALSE;
  761. }
  762. *visual = result->visual;
  763. *depth = result->depth;
  764. XFree(result);
  765. return GLFW_TRUE;
  766. }
  767. #endif // _GLFW_X11
  768. //////////////////////////////////////////////////////////////////////////
  769. ////// GLFW native API //////
  770. //////////////////////////////////////////////////////////////////////////
  771. GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
  772. {
  773. _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
  774. return _glfw.egl.display;
  775. }
  776. GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
  777. {
  778. _GLFWwindow* window = (_GLFWwindow*) handle;
  779. _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
  780. if (window->context.source != GLFW_EGL_CONTEXT_API)
  781. {
  782. _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
  783. return EGL_NO_CONTEXT;
  784. }
  785. return window->context.egl.handle;
  786. }
  787. GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
  788. {
  789. _GLFWwindow* window = (_GLFWwindow*) handle;
  790. _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
  791. if (window->context.source != GLFW_EGL_CONTEXT_API)
  792. {
  793. _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
  794. return EGL_NO_SURFACE;
  795. }
  796. return window->context.egl.surface;
  797. }