SDL_egl.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288
  1. /*
  2. * Simple DirectMedia Layer
  3. * Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
  4. *
  5. * This software is provided 'as-is', without any express or implied
  6. * warranty. In no event will the authors be held liable for any damages
  7. * arising from the use of this software.
  8. *
  9. * Permission is granted to anyone to use this software for any purpose,
  10. * including commercial applications, and to alter it and redistribute it
  11. * freely, subject to the following restrictions:
  12. *
  13. * 1. The origin of this software must not be misrepresented; you must not
  14. * claim that you wrote the original software. If you use this software
  15. * in a product, an acknowledgment in the product documentation would be
  16. * appreciated but is not required.
  17. * 2. Altered source versions must be plainly marked as such, and must not be
  18. * misrepresented as being the original software.
  19. * 3. This notice may not be removed or altered from any source distribution.
  20. */
  21. #include "../SDL_internal.h"
  22. #if SDL_VIDEO_OPENGL_EGL
  23. #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
  24. #include "../core/windows/SDL_windows.h"
  25. #endif
  26. #if SDL_VIDEO_DRIVER_ANDROID
  27. #include <android/native_window.h>
  28. #include "../core/android/SDL_android.h"
  29. #include "../video/android/SDL_androidvideo.h"
  30. #endif
  31. #include "SDL_sysvideo.h"
  32. #include "SDL_egl_c.h"
  33. #include "SDL_loadso.h"
  34. #include "SDL_hints.h"
  35. #ifdef EGL_KHR_create_context
  36. /* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */
  37. #ifndef EGL_OPENGL_ES3_BIT_KHR
  38. #define EGL_OPENGL_ES3_BIT_KHR 0x00000040
  39. #endif
  40. #endif /* EGL_KHR_create_context */
  41. #ifndef EGL_EXT_present_opaque
  42. #define EGL_EXT_present_opaque 1
  43. #define EGL_PRESENT_OPAQUE_EXT 0x31DF
  44. #endif /* EGL_EXT_present_opaque */
  45. #if SDL_VIDEO_DRIVER_RPI
  46. /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */
  47. #define DEFAULT_EGL ( vc4 ? "libEGL.so.1" : "libbrcmEGL.so" )
  48. #define DEFAULT_OGL_ES2 ( vc4 ? "libGLESv2.so.2" : "libbrcmGLESv2.so" )
  49. #define ALT_EGL "libEGL.so"
  50. #define ALT_OGL_ES2 "libGLESv2.so"
  51. #define DEFAULT_OGL_ES_PVR ( vc4 ? "libGLES_CM.so.1" : "libbrcmGLESv2.so" )
  52. #define DEFAULT_OGL_ES ( vc4 ? "libGLESv1_CM.so.1" : "libbrcmGLESv2.so" )
  53. #elif SDL_VIDEO_DRIVER_ANDROID || SDL_VIDEO_DRIVER_VIVANTE
  54. /* Android */
  55. #define DEFAULT_EGL "libEGL.so"
  56. #define DEFAULT_OGL_ES2 "libGLESv2.so"
  57. #define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
  58. #define DEFAULT_OGL_ES "libGLESv1_CM.so"
  59. #elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
  60. /* EGL AND OpenGL ES support via ANGLE */
  61. #define DEFAULT_EGL "libEGL.dll"
  62. #define DEFAULT_OGL_ES2 "libGLESv2.dll"
  63. #define DEFAULT_OGL_ES_PVR "libGLES_CM.dll"
  64. #define DEFAULT_OGL_ES "libGLESv1_CM.dll"
  65. #elif SDL_VIDEO_DRIVER_COCOA
  66. /* EGL AND OpenGL ES support via ANGLE */
  67. #define DEFAULT_EGL "libEGL.dylib"
  68. #define DEFAULT_OGL_ES2 "libGLESv2.dylib"
  69. #define DEFAULT_OGL_ES_PVR "libGLES_CM.dylib" //???
  70. #define DEFAULT_OGL_ES "libGLESv1_CM.dylib" //???
  71. #elif defined(__OpenBSD__)
  72. /* OpenBSD */
  73. #define DEFAULT_OGL "libGL.so"
  74. #define DEFAULT_EGL "libEGL.so"
  75. #define DEFAULT_OGL_ES2 "libGLESv2.so"
  76. #define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
  77. #define DEFAULT_OGL_ES "libGLESv1_CM.so"
  78. #else
  79. /* Desktop Linux/Unix-like */
  80. #define DEFAULT_OGL "libGL.so.1"
  81. #define DEFAULT_EGL "libEGL.so.1"
  82. #define ALT_OGL "libOpenGL.so.0"
  83. #define DEFAULT_OGL_ES2 "libGLESv2.so.2"
  84. #define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
  85. #define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
  86. #endif /* SDL_VIDEO_DRIVER_RPI */
  87. #if SDL_VIDEO_OPENGL
  88. #include "SDL_opengl.h"
  89. #endif
  90. /** If we happen to not have this defined because of an older EGL version, just define it 0x0
  91. as eglGetPlatformDisplayEXT will most likely be NULL if this is missing
  92. */
  93. #ifndef EGL_PLATFORM_DEVICE_EXT
  94. #define EGL_PLATFORM_DEVICE_EXT 0x0
  95. #endif
  96. #if defined(SDL_VIDEO_STATIC_ANGLE) || defined(SDL_VIDEO_DRIVER_VITA)
  97. #define LOAD_FUNC(NAME) \
  98. _this->egl_data->NAME = (void *)NAME;
  99. #else
  100. #define LOAD_FUNC(NAME) \
  101. _this->egl_data->NAME = SDL_LoadFunction(_this->egl_data->dll_handle, #NAME); \
  102. if (!_this->egl_data->NAME) \
  103. { \
  104. return SDL_SetError("Could not retrieve EGL function " #NAME); \
  105. }
  106. #endif
  107. /* it is allowed to not have some of the EGL extensions on start - attempts to use them will fail later. */
  108. #define LOAD_FUNC_EGLEXT(NAME) \
  109. _this->egl_data->NAME = _this->egl_data->eglGetProcAddress(#NAME);
  110. static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
  111. {
  112. #define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
  113. switch (eglErrorCode) {
  114. SDL_EGL_ERROR_TRANSLATE(EGL_SUCCESS);
  115. SDL_EGL_ERROR_TRANSLATE(EGL_NOT_INITIALIZED);
  116. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ACCESS);
  117. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ALLOC);
  118. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_ATTRIBUTE);
  119. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONTEXT);
  120. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CONFIG);
  121. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_CURRENT_SURFACE);
  122. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_DISPLAY);
  123. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_SURFACE);
  124. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_MATCH);
  125. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_PARAMETER);
  126. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_PIXMAP);
  127. SDL_EGL_ERROR_TRANSLATE(EGL_BAD_NATIVE_WINDOW);
  128. SDL_EGL_ERROR_TRANSLATE(EGL_CONTEXT_LOST);
  129. }
  130. return "";
  131. }
  132. int SDL_EGL_SetErrorEx(const char * message, const char * eglFunctionName, EGLint eglErrorCode)
  133. {
  134. const char * errorText = SDL_EGL_GetErrorName(eglErrorCode);
  135. char altErrorText[32];
  136. if (errorText[0] == '\0') {
  137. /* An unknown-to-SDL error code was reported. Report its hexadecimal value, instead of its name. */
  138. SDL_snprintf(altErrorText, SDL_arraysize(altErrorText), "0x%x", (unsigned int)eglErrorCode);
  139. errorText = altErrorText;
  140. }
  141. return SDL_SetError("%s (call to %s failed, reporting an error of %s)", message, eglFunctionName, errorText);
  142. }
  143. /* EGL implementation of SDL OpenGL ES support */
  144. SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext)
  145. {
  146. size_t ext_len;
  147. const char *ext_override;
  148. const char *egl_extstr;
  149. const char *ext_start;
  150. /* Invalid extensions can be rejected early */
  151. if (ext == NULL || *ext == 0 || SDL_strchr(ext, ' ') != NULL) {
  152. /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension"); */
  153. return SDL_FALSE;
  154. }
  155. /* Extensions can be masked with an environment variable.
  156. * Unlike the OpenGL override, this will use the set bits of an integer
  157. * to disable the extension.
  158. * Bit Action
  159. * 0 If set, the display extension is masked and not present to SDL.
  160. * 1 If set, the client extension is masked and not present to SDL.
  161. */
  162. ext_override = SDL_getenv(ext);
  163. if (ext_override != NULL) {
  164. int disable_ext = SDL_atoi(ext_override);
  165. if (disable_ext & 0x01 && type == SDL_EGL_DISPLAY_EXTENSION) {
  166. return SDL_FALSE;
  167. } else if (disable_ext & 0x02 && type == SDL_EGL_CLIENT_EXTENSION) {
  168. return SDL_FALSE;
  169. }
  170. }
  171. ext_len = SDL_strlen(ext);
  172. switch (type) {
  173. case SDL_EGL_DISPLAY_EXTENSION:
  174. egl_extstr = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS);
  175. break;
  176. case SDL_EGL_CLIENT_EXTENSION:
  177. /* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
  178. * if EGL_NO_DISPLAY is passed. Implementations without it are required to return NULL.
  179. * This behavior is included in EGL 1.5.
  180. */
  181. egl_extstr = _this->egl_data->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
  182. break;
  183. default:
  184. /* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type"); */
  185. return SDL_FALSE;
  186. }
  187. if (egl_extstr != NULL) {
  188. ext_start = egl_extstr;
  189. while (*ext_start) {
  190. ext_start = SDL_strstr(ext_start, ext);
  191. if (ext_start == NULL) {
  192. return SDL_FALSE;
  193. }
  194. /* Check if the match is not just a substring of one of the extensions */
  195. if (ext_start == egl_extstr || *(ext_start - 1) == ' ') {
  196. if (ext_start[ext_len] == ' ' || ext_start[ext_len] == 0) {
  197. return SDL_TRUE;
  198. }
  199. }
  200. /* If the search stopped in the middle of an extension, skip to the end of it */
  201. ext_start += ext_len;
  202. while (*ext_start != ' ' && *ext_start != 0) {
  203. ext_start++;
  204. }
  205. }
  206. }
  207. return SDL_FALSE;
  208. }
  209. void *
  210. SDL_EGL_GetProcAddress(_THIS, const char *proc)
  211. {
  212. const Uint32 eglver = (((Uint32) _this->egl_data->egl_version_major) << 16) | ((Uint32) _this->egl_data->egl_version_minor);
  213. const SDL_bool is_egl_15_or_later = eglver >= ((((Uint32) 1) << 16) | 5);
  214. void *retval = NULL;
  215. /* EGL 1.5 can use eglGetProcAddress() for any symbol. 1.4 and earlier can't use it for core entry points. */
  216. if (!retval && is_egl_15_or_later && _this->egl_data->eglGetProcAddress) {
  217. retval = _this->egl_data->eglGetProcAddress(proc);
  218. }
  219. #if !defined(__EMSCRIPTEN__) && !defined(SDL_VIDEO_DRIVER_VITA) /* LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems. */
  220. /* Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5. */
  221. if (!retval) {
  222. static char procname[64];
  223. retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, proc);
  224. /* just in case you need an underscore prepended... */
  225. if (!retval && (SDL_strlen(proc) < (sizeof (procname) - 1))) {
  226. procname[0] = '_';
  227. SDL_strlcpy(procname + 1, proc, sizeof (procname) - 1);
  228. retval = SDL_LoadFunction(_this->egl_data->egl_dll_handle, procname);
  229. }
  230. }
  231. #endif
  232. /* Try eglGetProcAddress if we're on <= 1.4 and still searching... */
  233. if (!retval && !is_egl_15_or_later && _this->egl_data->eglGetProcAddress) {
  234. retval = _this->egl_data->eglGetProcAddress(proc);
  235. if (retval) {
  236. return retval;
  237. }
  238. }
  239. return retval;
  240. }
  241. void
  242. SDL_EGL_UnloadLibrary(_THIS)
  243. {
  244. if (_this->egl_data) {
  245. if (_this->egl_data->egl_display) {
  246. _this->egl_data->eglTerminate(_this->egl_data->egl_display);
  247. _this->egl_data->egl_display = NULL;
  248. }
  249. if (_this->egl_data->dll_handle) {
  250. SDL_UnloadObject(_this->egl_data->dll_handle);
  251. _this->egl_data->dll_handle = NULL;
  252. }
  253. if (_this->egl_data->egl_dll_handle) {
  254. SDL_UnloadObject(_this->egl_data->egl_dll_handle);
  255. _this->egl_data->egl_dll_handle = NULL;
  256. }
  257. SDL_free(_this->egl_data);
  258. _this->egl_data = NULL;
  259. }
  260. }
  261. int
  262. SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path)
  263. {
  264. void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
  265. const char *path = NULL;
  266. #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
  267. const char *d3dcompiler;
  268. #endif
  269. #if SDL_VIDEO_DRIVER_RPI
  270. SDL_bool vc4 = (0 == access("/sys/module/vc4/", F_OK));
  271. #endif
  272. if (_this->egl_data) {
  273. return SDL_SetError("EGL context already created");
  274. }
  275. _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
  276. if (!_this->egl_data) {
  277. return SDL_OutOfMemory();
  278. }
  279. #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
  280. d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
  281. if (d3dcompiler) {
  282. if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
  283. if (SDL_LoadObject(d3dcompiler) == NULL) {
  284. SDL_ClearError();
  285. }
  286. }
  287. } else {
  288. if (WIN_IsWindowsVistaOrGreater()) {
  289. /* Try the newer d3d compilers first */
  290. const char *d3dcompiler_list[] = {
  291. "d3dcompiler_47.dll", "d3dcompiler_46.dll",
  292. };
  293. int i;
  294. for (i = 0; i < SDL_arraysize(d3dcompiler_list); ++i) {
  295. if (SDL_LoadObject(d3dcompiler_list[i]) != NULL) {
  296. break;
  297. }
  298. SDL_ClearError();
  299. }
  300. } else {
  301. if (SDL_LoadObject("d3dcompiler_43.dll") == NULL) {
  302. SDL_ClearError();
  303. }
  304. }
  305. }
  306. #endif
  307. #if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
  308. /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
  309. path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
  310. if (path != NULL) {
  311. egl_dll_handle = SDL_LoadObject(path);
  312. }
  313. if (egl_dll_handle == NULL) {
  314. if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  315. if (_this->gl_config.major_version > 1) {
  316. path = DEFAULT_OGL_ES2;
  317. egl_dll_handle = SDL_LoadObject(path);
  318. #ifdef ALT_OGL_ES2
  319. if (egl_dll_handle == NULL && !vc4) {
  320. path = ALT_OGL_ES2;
  321. egl_dll_handle = SDL_LoadObject(path);
  322. }
  323. #endif
  324. } else {
  325. path = DEFAULT_OGL_ES;
  326. egl_dll_handle = SDL_LoadObject(path);
  327. if (egl_dll_handle == NULL) {
  328. path = DEFAULT_OGL_ES_PVR;
  329. egl_dll_handle = SDL_LoadObject(path);
  330. }
  331. #ifdef ALT_OGL_ES2
  332. if (egl_dll_handle == NULL && !vc4) {
  333. path = ALT_OGL_ES2;
  334. egl_dll_handle = SDL_LoadObject(path);
  335. }
  336. #endif
  337. }
  338. }
  339. #ifdef DEFAULT_OGL
  340. else {
  341. path = DEFAULT_OGL;
  342. egl_dll_handle = SDL_LoadObject(path);
  343. #ifdef ALT_OGL
  344. if (egl_dll_handle == NULL) {
  345. path = ALT_OGL;
  346. egl_dll_handle = SDL_LoadObject(path);
  347. }
  348. #endif
  349. }
  350. #endif
  351. }
  352. _this->egl_data->egl_dll_handle = egl_dll_handle;
  353. if (egl_dll_handle == NULL) {
  354. return SDL_SetError("Could not initialize OpenGL / GLES library");
  355. }
  356. /* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
  357. if (egl_path != NULL) {
  358. dll_handle = SDL_LoadObject(egl_path);
  359. }
  360. /* Try loading a EGL symbol, if it does not work try the default library paths */
  361. if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
  362. if (dll_handle != NULL) {
  363. SDL_UnloadObject(dll_handle);
  364. }
  365. path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
  366. if (path == NULL) {
  367. path = DEFAULT_EGL;
  368. }
  369. dll_handle = SDL_LoadObject(path);
  370. #ifdef ALT_EGL
  371. if (dll_handle == NULL && !vc4) {
  372. path = ALT_EGL;
  373. dll_handle = SDL_LoadObject(path);
  374. }
  375. #endif
  376. if (dll_handle == NULL || SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) {
  377. if (dll_handle != NULL) {
  378. SDL_UnloadObject(dll_handle);
  379. }
  380. return SDL_SetError("Could not load EGL library");
  381. }
  382. SDL_ClearError();
  383. }
  384. #endif
  385. _this->egl_data->dll_handle = dll_handle;
  386. #if SDL_VIDEO_DRIVER_VITA
  387. _this->egl_data->egl_dll_handle = egl_dll_handle;
  388. #endif
  389. /* Load new function pointers */
  390. LOAD_FUNC(eglGetDisplay);
  391. LOAD_FUNC(eglInitialize);
  392. LOAD_FUNC(eglTerminate);
  393. LOAD_FUNC(eglGetProcAddress);
  394. LOAD_FUNC(eglChooseConfig);
  395. LOAD_FUNC(eglGetConfigAttrib);
  396. LOAD_FUNC(eglCreateContext);
  397. LOAD_FUNC(eglDestroyContext);
  398. LOAD_FUNC(eglCreatePbufferSurface);
  399. LOAD_FUNC(eglCreateWindowSurface);
  400. LOAD_FUNC(eglDestroySurface);
  401. LOAD_FUNC(eglMakeCurrent);
  402. LOAD_FUNC(eglSwapBuffers);
  403. LOAD_FUNC(eglSwapInterval);
  404. LOAD_FUNC(eglWaitNative);
  405. LOAD_FUNC(eglWaitGL);
  406. LOAD_FUNC(eglBindAPI);
  407. LOAD_FUNC(eglQueryAPI);
  408. LOAD_FUNC(eglQueryString);
  409. LOAD_FUNC(eglGetError);
  410. LOAD_FUNC_EGLEXT(eglQueryDevicesEXT);
  411. LOAD_FUNC_EGLEXT(eglGetPlatformDisplayEXT);
  412. /* Atomic functions */
  413. LOAD_FUNC_EGLEXT(eglCreateSyncKHR);
  414. LOAD_FUNC_EGLEXT(eglDestroySyncKHR);
  415. LOAD_FUNC_EGLEXT(eglDupNativeFenceFDANDROID);
  416. LOAD_FUNC_EGLEXT(eglWaitSyncKHR);
  417. LOAD_FUNC_EGLEXT(eglClientWaitSyncKHR);
  418. /* Atomic functions end */
  419. if (path) {
  420. SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
  421. } else {
  422. *_this->gl_config.driver_path = '\0';
  423. }
  424. return 0;
  425. }
  426. static void
  427. SDL_EGL_GetVersion(_THIS) {
  428. if (_this->egl_data->eglQueryString) {
  429. const char *egl_version = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_VERSION);
  430. if (egl_version) {
  431. int major = 0, minor = 0;
  432. if (SDL_sscanf(egl_version, "%d.%d", &major, &minor) == 2) {
  433. _this->egl_data->egl_version_major = major;
  434. _this->egl_data->egl_version_minor = minor;
  435. } else {
  436. SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not parse EGL version string: %s", egl_version);
  437. }
  438. }
  439. }
  440. }
  441. int
  442. SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
  443. {
  444. int library_load_retcode = SDL_EGL_LoadLibraryOnly(_this, egl_path);
  445. if (library_load_retcode != 0) {
  446. return library_load_retcode;
  447. }
  448. _this->egl_data->egl_display = EGL_NO_DISPLAY;
  449. #if !defined(__WINRT__)
  450. #if !defined(SDL_VIDEO_DRIVER_VITA)
  451. if (platform) {
  452. /* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY
  453. * --
  454. * Khronos doc: "EGL_BAD_DISPLAY is generated if display is not an EGL display connection, unless display is EGL_NO_DISPLAY and name is EGL_EXTENSIONS."
  455. * Therefore SDL_EGL_GetVersion() shouldn't work with uninitialized display.
  456. * - it actually doesn't work on Android that has 1.5 egl client
  457. * - it works on desktop X11 (using SDL_VIDEO_X11_FORCE_EGL=1) */
  458. SDL_EGL_GetVersion(_this);
  459. if (_this->egl_data->egl_version_major == 1 && _this->egl_data->egl_version_minor == 5) {
  460. LOAD_FUNC(eglGetPlatformDisplay);
  461. }
  462. if (_this->egl_data->eglGetPlatformDisplay) {
  463. _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(uintptr_t)native_display, NULL);
  464. } else {
  465. if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
  466. _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
  467. if (_this->egl_data->eglGetPlatformDisplayEXT) {
  468. _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, (void *)(uintptr_t)native_display, NULL);
  469. }
  470. }
  471. }
  472. }
  473. #endif
  474. /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
  475. if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
  476. _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
  477. }
  478. if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
  479. _this->gl_config.driver_loaded = 0;
  480. *_this->gl_config.driver_path = '\0';
  481. return SDL_SetError("Could not get EGL display");
  482. }
  483. if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
  484. _this->gl_config.driver_loaded = 0;
  485. *_this->gl_config.driver_path = '\0';
  486. return SDL_SetError("Could not initialize EGL");
  487. }
  488. #endif
  489. /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */
  490. SDL_EGL_GetVersion(_this);
  491. _this->egl_data->is_offscreen = SDL_FALSE;
  492. return 0;
  493. }
  494. /**
  495. On multi GPU machines EGL device 0 is not always the first valid GPU.
  496. Container environments can restrict access to some GPUs that are still listed in the EGL
  497. device list. If the requested device is a restricted GPU and cannot be used
  498. (eglInitialize() will fail) then attempt to automatically and silently select the next
  499. valid available GPU for EGL to use.
  500. */
  501. int
  502. SDL_EGL_InitializeOffscreen(_THIS, int device)
  503. {
  504. void *egl_devices[SDL_EGL_MAX_DEVICES];
  505. EGLint num_egl_devices = 0;
  506. const char *egl_device_hint;
  507. if (_this->gl_config.driver_loaded != 1) {
  508. return SDL_SetError("SDL_EGL_LoadLibraryOnly() has not been called or has failed.");
  509. }
  510. /* Check for all extensions that are optional until used and fail if any is missing */
  511. if (_this->egl_data->eglQueryDevicesEXT == NULL) {
  512. return SDL_SetError("eglQueryDevicesEXT is missing (EXT_device_enumeration not supported by the drivers?)");
  513. }
  514. if (_this->egl_data->eglGetPlatformDisplayEXT == NULL) {
  515. return SDL_SetError("eglGetPlatformDisplayEXT is missing (EXT_platform_base not supported by the drivers?)");
  516. }
  517. if (_this->egl_data->eglQueryDevicesEXT(SDL_EGL_MAX_DEVICES, egl_devices, &num_egl_devices) != EGL_TRUE) {
  518. return SDL_SetError("eglQueryDevicesEXT() failed");
  519. }
  520. egl_device_hint = SDL_GetHint("SDL_HINT_EGL_DEVICE");
  521. if (egl_device_hint) {
  522. device = SDL_atoi(egl_device_hint);
  523. if (device >= num_egl_devices) {
  524. return SDL_SetError("Invalid EGL device is requested.");
  525. }
  526. _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[device], NULL);
  527. if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
  528. return SDL_SetError("eglGetPlatformDisplayEXT() failed.");
  529. }
  530. if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
  531. return SDL_SetError("Could not initialize EGL");
  532. }
  533. }
  534. else {
  535. int i;
  536. SDL_bool found = SDL_FALSE;
  537. EGLDisplay attempted_egl_display;
  538. /* If no hint is provided lets look for the first device/display that will allow us to eglInit */
  539. for (i = 0; i < num_egl_devices; i++) {
  540. attempted_egl_display = _this->egl_data->eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, egl_devices[i], NULL);
  541. if (attempted_egl_display == EGL_NO_DISPLAY) {
  542. continue;
  543. }
  544. if (_this->egl_data->eglInitialize(attempted_egl_display, NULL, NULL) != EGL_TRUE) {
  545. _this->egl_data->eglTerminate(attempted_egl_display);
  546. continue;
  547. }
  548. /* We did not fail, we'll pick this one! */
  549. _this->egl_data->egl_display = attempted_egl_display;
  550. found = SDL_TRUE;
  551. break;
  552. }
  553. if (!found) {
  554. return SDL_SetError("Could not find a valid EGL device to initialize");
  555. }
  556. }
  557. /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */
  558. SDL_EGL_GetVersion(_this);
  559. _this->egl_data->is_offscreen = SDL_TRUE;
  560. return 0;
  561. }
  562. void
  563. SDL_EGL_SetRequiredVisualId(_THIS, int visual_id)
  564. {
  565. _this->egl_data->egl_required_visual_id=visual_id;
  566. }
  567. #ifdef DUMP_EGL_CONFIG
  568. #define ATTRIBUTE(_attr) { _attr, #_attr }
  569. typedef struct {
  570. EGLint attribute;
  571. char const* name;
  572. } Attribute;
  573. static
  574. Attribute all_attributes[] = {
  575. ATTRIBUTE( EGL_BUFFER_SIZE ),
  576. ATTRIBUTE( EGL_ALPHA_SIZE ),
  577. ATTRIBUTE( EGL_BLUE_SIZE ),
  578. ATTRIBUTE( EGL_GREEN_SIZE ),
  579. ATTRIBUTE( EGL_RED_SIZE ),
  580. ATTRIBUTE( EGL_DEPTH_SIZE ),
  581. ATTRIBUTE( EGL_STENCIL_SIZE ),
  582. ATTRIBUTE( EGL_CONFIG_CAVEAT ),
  583. ATTRIBUTE( EGL_CONFIG_ID ),
  584. ATTRIBUTE( EGL_LEVEL ),
  585. ATTRIBUTE( EGL_MAX_PBUFFER_HEIGHT ),
  586. ATTRIBUTE( EGL_MAX_PBUFFER_WIDTH ),
  587. ATTRIBUTE( EGL_MAX_PBUFFER_PIXELS ),
  588. ATTRIBUTE( EGL_NATIVE_RENDERABLE ),
  589. ATTRIBUTE( EGL_NATIVE_VISUAL_ID ),
  590. ATTRIBUTE( EGL_NATIVE_VISUAL_TYPE ),
  591. ATTRIBUTE( EGL_SAMPLES ),
  592. ATTRIBUTE( EGL_SAMPLE_BUFFERS ),
  593. ATTRIBUTE( EGL_SURFACE_TYPE ),
  594. ATTRIBUTE( EGL_TRANSPARENT_TYPE ),
  595. ATTRIBUTE( EGL_TRANSPARENT_BLUE_VALUE ),
  596. ATTRIBUTE( EGL_TRANSPARENT_GREEN_VALUE ),
  597. ATTRIBUTE( EGL_TRANSPARENT_RED_VALUE ),
  598. ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGB ),
  599. ATTRIBUTE( EGL_BIND_TO_TEXTURE_RGBA ),
  600. ATTRIBUTE( EGL_MIN_SWAP_INTERVAL ),
  601. ATTRIBUTE( EGL_MAX_SWAP_INTERVAL ),
  602. ATTRIBUTE( EGL_LUMINANCE_SIZE ),
  603. ATTRIBUTE( EGL_ALPHA_MASK_SIZE ),
  604. ATTRIBUTE( EGL_COLOR_BUFFER_TYPE ),
  605. ATTRIBUTE( EGL_RENDERABLE_TYPE ),
  606. ATTRIBUTE( EGL_MATCH_NATIVE_PIXMAP ),
  607. ATTRIBUTE( EGL_CONFORMANT ),
  608. };
  609. static void dumpconfig(_THIS, EGLConfig config)
  610. {
  611. int attr;
  612. for (attr = 0 ; attr<sizeof(all_attributes)/sizeof(Attribute) ; attr++) {
  613. EGLint value;
  614. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, config, all_attributes[attr].attribute, &value);
  615. SDL_Log("\t%-32s: %10d (0x%08x)\n", all_attributes[attr].name, value, value);
  616. }
  617. }
  618. #endif /* DUMP_EGL_CONFIG */
  619. static int
  620. SDL_EGL_PrivateChooseConfig(_THIS, SDL_bool set_config_caveat_none)
  621. {
  622. /* 64 seems nice. */
  623. EGLint attribs[64];
  624. EGLint found_configs = 0, value;
  625. /* 128 seems even nicer here */
  626. EGLConfig configs[128];
  627. SDL_bool has_matching_format = SDL_FALSE;
  628. int i, j, best_bitdiff = -1, best_truecolor_bitdiff = -1;
  629. int truecolor_config_idx = -1;
  630. /* Get a valid EGL configuration */
  631. i = 0;
  632. attribs[i++] = EGL_RED_SIZE;
  633. attribs[i++] = _this->gl_config.red_size;
  634. attribs[i++] = EGL_GREEN_SIZE;
  635. attribs[i++] = _this->gl_config.green_size;
  636. attribs[i++] = EGL_BLUE_SIZE;
  637. attribs[i++] = _this->gl_config.blue_size;
  638. if (set_config_caveat_none) {
  639. attribs[i++] = EGL_CONFIG_CAVEAT;
  640. attribs[i++] = EGL_NONE;
  641. }
  642. if (_this->gl_config.alpha_size) {
  643. attribs[i++] = EGL_ALPHA_SIZE;
  644. attribs[i++] = _this->gl_config.alpha_size;
  645. }
  646. if (_this->gl_config.buffer_size) {
  647. attribs[i++] = EGL_BUFFER_SIZE;
  648. attribs[i++] = _this->gl_config.buffer_size;
  649. }
  650. if (_this->gl_config.depth_size) {
  651. attribs[i++] = EGL_DEPTH_SIZE;
  652. attribs[i++] = _this->gl_config.depth_size;
  653. }
  654. if (_this->gl_config.stencil_size) {
  655. attribs[i++] = EGL_STENCIL_SIZE;
  656. attribs[i++] = _this->gl_config.stencil_size;
  657. }
  658. if (_this->gl_config.multisamplebuffers) {
  659. attribs[i++] = EGL_SAMPLE_BUFFERS;
  660. attribs[i++] = _this->gl_config.multisamplebuffers;
  661. }
  662. if (_this->gl_config.multisamplesamples) {
  663. attribs[i++] = EGL_SAMPLES;
  664. attribs[i++] = _this->gl_config.multisamplesamples;
  665. }
  666. if (_this->egl_data->is_offscreen) {
  667. attribs[i++] = EGL_SURFACE_TYPE;
  668. attribs[i++] = EGL_PBUFFER_BIT;
  669. }
  670. attribs[i++] = EGL_RENDERABLE_TYPE;
  671. if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
  672. #ifdef EGL_KHR_create_context
  673. if (_this->gl_config.major_version >= 3 &&
  674. SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
  675. attribs[i++] = EGL_OPENGL_ES3_BIT_KHR;
  676. } else
  677. #endif
  678. if (_this->gl_config.major_version >= 2) {
  679. attribs[i++] = EGL_OPENGL_ES2_BIT;
  680. } else {
  681. attribs[i++] = EGL_OPENGL_ES_BIT;
  682. }
  683. _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
  684. } else {
  685. attribs[i++] = EGL_OPENGL_BIT;
  686. _this->egl_data->eglBindAPI(EGL_OPENGL_API);
  687. }
  688. if (_this->egl_data->egl_surfacetype) {
  689. attribs[i++] = EGL_SURFACE_TYPE;
  690. attribs[i++] = _this->egl_data->egl_surfacetype;
  691. }
  692. attribs[i++] = EGL_NONE;
  693. SDL_assert(i < SDL_arraysize(attribs));
  694. if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display,
  695. attribs,
  696. configs, SDL_arraysize(configs),
  697. &found_configs) == EGL_FALSE ||
  698. found_configs == 0) {
  699. return -1;
  700. }
  701. /* first ensure that a found config has a matching format, or the function will fall through. */
  702. if (_this->egl_data->egl_required_visual_id)
  703. {
  704. for (i = 0; i < found_configs; i++ ) {
  705. EGLint format;
  706. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
  707. configs[i],
  708. EGL_NATIVE_VISUAL_ID, &format);
  709. if (_this->egl_data->egl_required_visual_id == format) {
  710. has_matching_format = SDL_TRUE;
  711. break;
  712. }
  713. }
  714. }
  715. /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */
  716. /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */
  717. for (i = 0; i < found_configs; i++ ) {
  718. SDL_bool is_truecolor = SDL_FALSE;
  719. int bitdiff = 0;
  720. if (has_matching_format && _this->egl_data->egl_required_visual_id) {
  721. EGLint format;
  722. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
  723. configs[i],
  724. EGL_NATIVE_VISUAL_ID, &format);
  725. if (_this->egl_data->egl_required_visual_id != format) {
  726. continue;
  727. }
  728. }
  729. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_RED_SIZE, &value);
  730. if (value == 8) {
  731. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_GREEN_SIZE, &value);
  732. if (value == 8) {
  733. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], EGL_BLUE_SIZE, &value);
  734. if (value == 8) {
  735. is_truecolor = SDL_TRUE;
  736. }
  737. }
  738. }
  739. for (j = 0; j < SDL_arraysize(attribs) - 1; j += 2) {
  740. if (attribs[j] == EGL_NONE) {
  741. break;
  742. }
  743. if ( attribs[j+1] != EGL_DONT_CARE && (
  744. attribs[j] == EGL_RED_SIZE ||
  745. attribs[j] == EGL_GREEN_SIZE ||
  746. attribs[j] == EGL_BLUE_SIZE ||
  747. attribs[j] == EGL_ALPHA_SIZE ||
  748. attribs[j] == EGL_DEPTH_SIZE ||
  749. attribs[j] == EGL_STENCIL_SIZE)) {
  750. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, configs[i], attribs[j], &value);
  751. bitdiff += value - attribs[j + 1]; /* value is always >= attrib */
  752. }
  753. }
  754. if ((bitdiff < best_bitdiff) || (best_bitdiff == -1)) {
  755. _this->egl_data->egl_config = configs[i];
  756. best_bitdiff = bitdiff;
  757. }
  758. if (is_truecolor && ((bitdiff < best_truecolor_bitdiff) || (best_truecolor_bitdiff == -1))) {
  759. truecolor_config_idx = i;
  760. best_truecolor_bitdiff = bitdiff;
  761. }
  762. }
  763. #define FAVOR_TRUECOLOR 1
  764. #if FAVOR_TRUECOLOR
  765. /* Some apps request a low color depth, either because they _assume_
  766. they'll get a larger one but don't want to fail if only smaller ones
  767. are available, or they just never called SDL_GL_SetAttribute at all and
  768. got a tiny default. For these cases, a game that would otherwise run
  769. at 24-bit color might get dithered down to something smaller, which is
  770. worth avoiding. If the app requested <= 16 bit color and an exact 24-bit
  771. match is available, favor that. Otherwise, we look for the closest
  772. match. Note that while the API promises what you request _or better_,
  773. it's feasible this can be disastrous for performance for custom software
  774. on small hardware that all expected to actually get 16-bit color. In this
  775. case, turn off FAVOR_TRUECOLOR (and maybe send a patch to make this more
  776. flexible). */
  777. if ( ((_this->gl_config.red_size + _this->gl_config.blue_size + _this->gl_config.green_size) <= 16) ) {
  778. if (truecolor_config_idx != -1) {
  779. _this->egl_data->egl_config = configs[truecolor_config_idx];
  780. }
  781. }
  782. #endif
  783. #ifdef DUMP_EGL_CONFIG
  784. dumpconfig(_this, _this->egl_data->egl_config);
  785. #endif
  786. return 0;
  787. }
  788. int
  789. SDL_EGL_ChooseConfig(_THIS)
  790. {
  791. int ret;
  792. if (!_this->egl_data) {
  793. /* The EGL library wasn't loaded, SDL_GetError() should have info */
  794. return -1;
  795. }
  796. /* Try with EGL_CONFIG_CAVEAT set to EGL_NONE, to avoid any EGL_SLOW_CONFIG or EGL_NON_CONFORMANT_CONFIG */
  797. ret = SDL_EGL_PrivateChooseConfig(_this, SDL_TRUE);
  798. if (ret == 0) {
  799. return 0;
  800. }
  801. /* Fallback with all configs */
  802. ret = SDL_EGL_PrivateChooseConfig(_this, SDL_FALSE);
  803. if (ret == 0) {
  804. SDL_Log("SDL_EGL_ChooseConfig: found a slow EGL config");
  805. return 0;
  806. }
  807. return SDL_EGL_SetError("Couldn't find matching EGL config", "eglChooseConfig");
  808. }
  809. SDL_GLContext
  810. SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
  811. {
  812. /* max 14 values plus terminator. */
  813. EGLint attribs[15];
  814. int attr = 0;
  815. EGLContext egl_context, share_context = EGL_NO_CONTEXT;
  816. EGLint profile_mask = _this->gl_config.profile_mask;
  817. EGLint major_version = _this->gl_config.major_version;
  818. EGLint minor_version = _this->gl_config.minor_version;
  819. SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
  820. if (!_this->egl_data) {
  821. /* The EGL library wasn't loaded, SDL_GetError() should have info */
  822. return NULL;
  823. }
  824. if (_this->gl_config.share_with_current_context) {
  825. share_context = (EGLContext)SDL_GL_GetCurrentContext();
  826. }
  827. #if SDL_VIDEO_DRIVER_ANDROID
  828. if ((_this->gl_config.flags & SDL_GL_CONTEXT_DEBUG_FLAG) != 0) {
  829. /* If SDL_GL_CONTEXT_DEBUG_FLAG is set but EGL_KHR_debug unsupported, unset.
  830. * This is required because some Android devices like to complain about it
  831. * by "silently" failing, logging a hint which could be easily overlooked:
  832. * E/libEGL (26984): validate_display:255 error 3008 (EGL_BAD_DISPLAY)
  833. * The following explicitly checks for EGL_KHR_debug before EGL 1.5
  834. */
  835. int egl_version_major = _this->egl_data->egl_version_major;
  836. int egl_version_minor = _this->egl_data->egl_version_minor;
  837. if (((egl_version_major < 1) || (egl_version_major == 1 && egl_version_minor < 5)) &&
  838. !SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_debug")) {
  839. /* SDL profile bits match EGL profile bits. */
  840. _this->gl_config.flags &= ~SDL_GL_CONTEXT_DEBUG_FLAG;
  841. }
  842. }
  843. #endif
  844. /* Set the context version and other attributes. */
  845. if ((major_version < 3 || (minor_version == 0 && profile_es)) &&
  846. _this->gl_config.flags == 0 &&
  847. (profile_mask == 0 || profile_es)) {
  848. /* Create a context without using EGL_KHR_create_context attribs.
  849. * When creating a GLES context without EGL_KHR_create_context we can
  850. * only specify the major version. When creating a desktop GL context
  851. * we can't specify any version, so we only try in that case when the
  852. * version is less than 3.0 (matches SDL's GLX/WGL behavior.)
  853. */
  854. if (profile_es) {
  855. attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION;
  856. attribs[attr++] = SDL_max(major_version, 1);
  857. }
  858. } else {
  859. #ifdef EGL_KHR_create_context
  860. /* The Major/minor version, context profiles, and context flags can
  861. * only be specified when this extension is available.
  862. */
  863. if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context")) {
  864. attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
  865. attribs[attr++] = major_version;
  866. attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR;
  867. attribs[attr++] = minor_version;
  868. /* SDL profile bits match EGL profile bits. */
  869. if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
  870. attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
  871. attribs[attr++] = profile_mask;
  872. }
  873. /* SDL flags match EGL flags. */
  874. if (_this->gl_config.flags != 0) {
  875. attribs[attr++] = EGL_CONTEXT_FLAGS_KHR;
  876. attribs[attr++] = _this->gl_config.flags;
  877. }
  878. } else
  879. #endif /* EGL_KHR_create_context */
  880. {
  881. SDL_SetError("Could not create EGL context (context attributes are not supported)");
  882. return NULL;
  883. }
  884. }
  885. if (_this->gl_config.no_error) {
  886. #ifdef EGL_KHR_create_context_no_error
  887. if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_create_context_no_error")) {
  888. attribs[attr++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
  889. attribs[attr++] = _this->gl_config.no_error;
  890. } else
  891. #endif
  892. {
  893. SDL_SetError("EGL implementation does not support no_error contexts");
  894. return NULL;
  895. }
  896. }
  897. attribs[attr++] = EGL_NONE;
  898. /* Bind the API */
  899. if (profile_es) {
  900. _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API);
  901. } else {
  902. _this->egl_data->eglBindAPI(EGL_OPENGL_API);
  903. }
  904. egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display,
  905. _this->egl_data->egl_config,
  906. share_context, attribs);
  907. if (egl_context == EGL_NO_CONTEXT) {
  908. SDL_EGL_SetError("Could not create EGL context", "eglCreateContext");
  909. return NULL;
  910. }
  911. _this->egl_data->egl_swapinterval = 0;
  912. if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) {
  913. /* Save the SDL error set by SDL_EGL_MakeCurrent */
  914. char errorText[1024];
  915. SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText));
  916. /* Delete the context, which may alter the value returned by SDL_GetError() */
  917. SDL_EGL_DeleteContext(_this, egl_context);
  918. /* Restore the SDL error */
  919. SDL_SetError("%s", errorText);
  920. return NULL;
  921. }
  922. /* Check whether making contexts current without a surface is supported.
  923. * First condition: EGL must support it. That's the case for EGL 1.5
  924. * or later, or if the EGL_KHR_surfaceless_context extension is present. */
  925. if ((_this->egl_data->egl_version_major > 1) ||
  926. ((_this->egl_data->egl_version_major == 1) && (_this->egl_data->egl_version_minor >= 5)) ||
  927. SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_surfaceless_context"))
  928. {
  929. /* Secondary condition: The client API must support it. */
  930. if (profile_es) {
  931. /* On OpenGL ES, the GL_OES_surfaceless_context extension must be
  932. * present. */
  933. if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) {
  934. _this->gl_allow_no_surface = SDL_TRUE;
  935. }
  936. #if SDL_VIDEO_OPENGL
  937. } else {
  938. /* Desktop OpenGL supports it by default from version 3.0 on. */
  939. void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
  940. glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
  941. if (glGetIntegervFunc) {
  942. GLint v = 0;
  943. glGetIntegervFunc(GL_MAJOR_VERSION, &v);
  944. if (v >= 3) {
  945. _this->gl_allow_no_surface = SDL_TRUE;
  946. }
  947. }
  948. #endif
  949. }
  950. }
  951. return (SDL_GLContext) egl_context;
  952. }
  953. int
  954. SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
  955. {
  956. EGLContext egl_context = (EGLContext) context;
  957. if (!_this->egl_data) {
  958. return SDL_SetError("OpenGL not initialized");
  959. }
  960. if (!_this->egl_data->eglMakeCurrent) {
  961. if (!egl_surface && !context) {
  962. /* Can't do the nothing there is to do? Probably trying to cleanup a failed startup, just return. */
  963. return 0;
  964. } else {
  965. return SDL_SetError("OpenGL not initialized"); /* something clearly went wrong somewhere. */
  966. }
  967. }
  968. /* The android emulator crashes badly if you try to eglMakeCurrent
  969. * with a valid context and invalid surface, so we have to check for both here.
  970. */
  971. if (!egl_context || (!egl_surface && !_this->gl_allow_no_surface)) {
  972. _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  973. } else {
  974. if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
  975. egl_surface, egl_surface, egl_context)) {
  976. return SDL_EGL_SetError("Unable to make EGL context current", "eglMakeCurrent");
  977. }
  978. }
  979. return 0;
  980. }
  981. int
  982. SDL_EGL_SetSwapInterval(_THIS, int interval)
  983. {
  984. EGLBoolean status;
  985. if (!_this->egl_data) {
  986. return SDL_SetError("EGL not initialized");
  987. }
  988. /* FIXME: Revisit this check when EGL_EXT_swap_control_tear is published:
  989. * https://github.com/KhronosGroup/EGL-Registry/pull/113
  990. */
  991. if (interval < 0) {
  992. return SDL_SetError("Late swap tearing currently unsupported");
  993. }
  994. status = _this->egl_data->eglSwapInterval(_this->egl_data->egl_display, interval);
  995. if (status == EGL_TRUE) {
  996. _this->egl_data->egl_swapinterval = interval;
  997. return 0;
  998. }
  999. return SDL_EGL_SetError("Unable to set the EGL swap interval", "eglSwapInterval");
  1000. }
  1001. int
  1002. SDL_EGL_GetSwapInterval(_THIS)
  1003. {
  1004. if (!_this->egl_data) {
  1005. SDL_SetError("EGL not initialized");
  1006. return 0;
  1007. }
  1008. return _this->egl_data->egl_swapinterval;
  1009. }
  1010. int
  1011. SDL_EGL_SwapBuffers(_THIS, EGLSurface egl_surface)
  1012. {
  1013. if (!_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, egl_surface)) {
  1014. return SDL_EGL_SetError("unable to show color buffer in an OS-native window", "eglSwapBuffers");
  1015. }
  1016. return 0;
  1017. }
  1018. void
  1019. SDL_EGL_DeleteContext(_THIS, SDL_GLContext context)
  1020. {
  1021. EGLContext egl_context = (EGLContext) context;
  1022. /* Clean up GLES and EGL */
  1023. if (!_this->egl_data) {
  1024. return;
  1025. }
  1026. if (egl_context != NULL && egl_context != EGL_NO_CONTEXT) {
  1027. _this->egl_data->eglDestroyContext(_this->egl_data->egl_display, egl_context);
  1028. }
  1029. }
  1030. EGLSurface *
  1031. SDL_EGL_CreateSurface(_THIS, NativeWindowType nw)
  1032. {
  1033. #if SDL_VIDEO_DRIVER_ANDROID
  1034. EGLint format_wanted;
  1035. EGLint format_got;
  1036. #endif
  1037. /* max 2 key+value pairs, plus terminator. */
  1038. EGLint attribs[5];
  1039. int attr = 0;
  1040. EGLSurface * surface;
  1041. if (SDL_EGL_ChooseConfig(_this) != 0) {
  1042. return EGL_NO_SURFACE;
  1043. }
  1044. #if SDL_VIDEO_DRIVER_ANDROID
  1045. /* On Android, EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
  1046. * guaranteed to be accepted by ANativeWindow_setBuffersGeometry(). */
  1047. _this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
  1048. _this->egl_data->egl_config,
  1049. EGL_NATIVE_VISUAL_ID, &format_wanted);
  1050. /* Format based on selected egl config. */
  1051. ANativeWindow_setBuffersGeometry(nw, 0, 0, format_wanted);
  1052. #endif
  1053. if (_this->gl_config.framebuffer_srgb_capable) {
  1054. #ifdef EGL_KHR_gl_colorspace
  1055. if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
  1056. attribs[attr++] = EGL_GL_COLORSPACE_KHR;
  1057. attribs[attr++] = EGL_GL_COLORSPACE_SRGB_KHR;
  1058. } else
  1059. #endif
  1060. {
  1061. SDL_SetError("EGL implementation does not support sRGB system framebuffers");
  1062. return EGL_NO_SURFACE;
  1063. }
  1064. }
  1065. #ifdef EGL_EXT_present_opaque
  1066. if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_EXT_present_opaque")) {
  1067. const SDL_bool allow_transparent = SDL_GetHintBoolean(SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY, SDL_FALSE);
  1068. attribs[attr++] = EGL_PRESENT_OPAQUE_EXT;
  1069. attribs[attr++] = allow_transparent ? EGL_FALSE : EGL_TRUE;
  1070. }
  1071. #endif
  1072. attribs[attr++] = EGL_NONE;
  1073. surface = _this->egl_data->eglCreateWindowSurface(
  1074. _this->egl_data->egl_display,
  1075. _this->egl_data->egl_config,
  1076. nw, &attribs[0]);
  1077. if (surface == EGL_NO_SURFACE) {
  1078. SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
  1079. }
  1080. #if SDL_VIDEO_DRIVER_ANDROID
  1081. format_got = ANativeWindow_getFormat(nw);
  1082. Android_SetFormat(format_wanted, format_got);
  1083. #endif
  1084. return surface;
  1085. }
  1086. EGLSurface
  1087. SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height)
  1088. {
  1089. EGLint attributes[] = {
  1090. EGL_WIDTH, width,
  1091. EGL_HEIGHT, height,
  1092. EGL_NONE
  1093. };
  1094. if (SDL_EGL_ChooseConfig(_this) != 0) {
  1095. return EGL_NO_SURFACE;
  1096. }
  1097. return _this->egl_data->eglCreatePbufferSurface(
  1098. _this->egl_data->egl_display,
  1099. _this->egl_data->egl_config,
  1100. attributes);
  1101. }
  1102. void
  1103. SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface)
  1104. {
  1105. if (!_this->egl_data) {
  1106. return;
  1107. }
  1108. if (egl_surface != EGL_NO_SURFACE) {
  1109. _this->egl_data->eglDestroySurface(_this->egl_data->egl_display, egl_surface);
  1110. }
  1111. }
  1112. #endif /* SDL_VIDEO_OPENGL_EGL */
  1113. /* vi: set ts=4 sw=4 expandtab: */