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