SDL_egl.c 48 KB

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