2023-11-18 10:50:16 -05:00
/*
* Simple DirectMedia Layer
2025-04-12 04:38:19 -04:00
* Copyright ( C ) 1997 - 2025 Sam Lantinga < slouken @ libsdl . org >
2023-11-18 10:50:16 -05:00
*
* This software is provided ' as - is ' , without any express or implied
* warranty . In no event will the authors be held liable for any damages
* arising from the use of this software .
*
* Permission is granted to anyone to use this software for any purpose ,
* including commercial applications , and to alter it and redistribute it
* freely , subject to the following restrictions :
*
* 1. The origin of this software must not be misrepresented ; you must not
* claim that you wrote the original software . If you use this software
* in a product , an acknowledgment in the product documentation would be
* appreciated but is not required .
* 2. Altered source versions must be plainly marked as such , and must not be
* misrepresented as being the original software .
* 3. This notice may not be removed or altered from any source distribution .
*/
2025-04-12 04:38:19 -04:00
# include "SDL_internal.h"
2023-11-18 10:50:16 -05:00
# ifdef SDL_VIDEO_OPENGL_EGL
2025-04-12 04:38:19 -04:00
# if defined(SDL_VIDEO_DRIVER_WINDOWS)
2023-11-18 10:50:16 -05:00
# include "../core/windows/SDL_windows.h"
# endif
# ifdef SDL_VIDEO_DRIVER_ANDROID
# include <android/native_window.h>
# include "../video/android/SDL_androidvideo.h"
# endif
# ifdef SDL_VIDEO_DRIVER_RPI
# include <unistd.h>
# endif
2025-04-12 04:38:19 -04:00
# ifdef SDL_VIDEO_VITA_PVR_OGL
# include <GLES2/gl2.h>
# endif
2023-11-18 10:50:16 -05:00
# include "SDL_sysvideo.h"
# include "SDL_egl_c.h"
# ifdef EGL_KHR_create_context
2025-04-12 04:38:19 -04:00
// EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension.
2023-11-18 10:50:16 -05:00
# ifndef EGL_OPENGL_ES3_BIT_KHR
# define EGL_OPENGL_ES3_BIT_KHR 0x00000040
# endif
2025-04-12 04:38:19 -04:00
# endif // EGL_KHR_create_context
2023-11-18 10:50:16 -05:00
# ifndef EGL_EXT_pixel_format_float
# define EGL_EXT_pixel_format_float
# define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
# define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
# define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
# endif
# ifndef EGL_EXT_present_opaque
# define EGL_EXT_present_opaque 1
# define EGL_PRESENT_OPAQUE_EXT 0x31DF
2025-04-12 04:38:19 -04:00
# endif // EGL_EXT_present_opaque
2023-11-18 10:50:16 -05:00
# ifdef SDL_VIDEO_DRIVER_RPI
2025-04-12 04:38:19 -04:00
// Raspbian places the OpenGL ES/EGL binaries in a non standard path
2023-11-18 10:50:16 -05:00
# define DEFAULT_EGL (vc4 ? "libEGL.so.1" : "libbrcmEGL.so")
# define DEFAULT_OGL_ES2 (vc4 ? "libGLESv2.so.2" : "libbrcmGLESv2.so")
# define ALT_EGL "libEGL.so"
# define ALT_OGL_ES2 "libGLESv2.so"
# define DEFAULT_OGL_ES_PVR (vc4 ? "libGLES_CM.so.1" : "libbrcmGLESv2.so")
# define DEFAULT_OGL_ES (vc4 ? "libGLESv1_CM.so.1" : "libbrcmGLESv2.so")
# elif defined(SDL_VIDEO_DRIVER_ANDROID) || defined(SDL_VIDEO_DRIVER_VIVANTE)
2025-04-12 04:38:19 -04:00
// Android
2023-11-18 10:50:16 -05:00
# define DEFAULT_EGL "libEGL.so"
# define DEFAULT_OGL_ES2 "libGLESv2.so"
# define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
# define DEFAULT_OGL_ES "libGLESv1_CM.so"
2025-04-12 04:38:19 -04:00
# elif defined(SDL_VIDEO_DRIVER_WINDOWS)
// EGL AND OpenGL ES support via ANGLE
# define DEFAULT_EGL "libEGL.dll"
# define DEFAULT_OGL "opengl32.dll"
# define DEFAULT_OGL_ES2 "libGLESv2.dll"
2023-11-18 10:50:16 -05:00
# define DEFAULT_OGL_ES_PVR "libGLES_CM.dll"
# define DEFAULT_OGL_ES "libGLESv1_CM.dll"
# elif defined(SDL_VIDEO_DRIVER_COCOA)
2025-04-12 04:38:19 -04:00
// EGL AND OpenGL ES support via ANGLE
2023-11-18 10:50:16 -05:00
# define DEFAULT_EGL "libEGL.dylib"
# define DEFAULT_OGL_ES2 "libGLESv2.dylib"
# define DEFAULT_OGL_ES_PVR "libGLES_CM.dylib" //???
# define DEFAULT_OGL_ES "libGLESv1_CM.dylib" //???
2025-04-12 04:38:19 -04:00
# elif defined(SDL_PLATFORM_OPENBSD)
// OpenBSD
2023-11-18 10:50:16 -05:00
# define DEFAULT_OGL "libGL.so"
# define DEFAULT_EGL "libEGL.so"
# define DEFAULT_OGL_ES2 "libGLESv2.so"
# define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
# define DEFAULT_OGL_ES "libGLESv1_CM.so"
# else
2025-04-12 04:38:19 -04:00
// Desktop Linux/Unix-like
2023-11-18 10:50:16 -05:00
# define DEFAULT_OGL "libGL.so.1"
# define DEFAULT_EGL "libEGL.so.1"
# define ALT_OGL "libOpenGL.so.0"
# define DEFAULT_OGL_ES2 "libGLESv2.so.2"
# define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
# define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
2025-04-12 04:38:19 -04:00
# endif // SDL_VIDEO_DRIVER_RPI
2023-11-18 10:50:16 -05:00
# if defined(SDL_VIDEO_OPENGL) && !defined(SDL_VIDEO_VITA_PVR_OGL)
2025-04-12 04:38:19 -04:00
# include <SDL3/SDL_opengl.h>
2023-11-18 10:50:16 -05:00
# endif
/** If we happen to not have this defined because of an older EGL version, just define it 0x0
as eglGetPlatformDisplayEXT will most likely be NULL if this is missing
*/
# ifndef EGL_PLATFORM_DEVICE_EXT
# define EGL_PLATFORM_DEVICE_EXT 0x0
# endif
2025-04-12 04:38:19 -04:00
# ifdef SDL_VIDEO_OPENGL
typedef void ( APIENTRY * PFNGLGETINTEGERVPROC ) ( GLenum pname , GLint * params ) ;
# endif
2023-11-18 10:50:16 -05:00
# if defined(SDL_VIDEO_STATIC_ANGLE) || defined(SDL_VIDEO_DRIVER_VITA)
2025-04-12 04:38:19 -04:00
# define LOAD_FUNC(TYPE, NAME) \
_this - > egl_data - > NAME = NAME ;
2023-11-18 10:50:16 -05:00
# else
2025-04-12 04:38:19 -04:00
# define LOAD_FUNC(TYPE, NAME) \
_this - > egl_data - > NAME = ( TYPE ) SDL_LoadFunction ( _this - > egl_data - > egl_dll_handle , # NAME ) ; \
2023-11-18 10:50:16 -05:00
if ( ! _this - > egl_data - > NAME ) { \
return SDL_SetError ( " Could not retrieve EGL function " # NAME ) ; \
}
# endif
2025-04-12 04:38:19 -04:00
// it is allowed to not have some of the EGL extensions on start - attempts to use them will fail later.
# define LOAD_FUNC_EGLEXT(TYPE, NAME) \
_this - > egl_data - > NAME = ( TYPE ) _this - > egl_data - > eglGetProcAddress ( # NAME ) ;
2023-11-18 10:50:16 -05:00
static const char * SDL_EGL_GetErrorName ( EGLint eglErrorCode )
{
# define SDL_EGL_ERROR_TRANSLATE(e) \
case e : \
return # e ;
switch ( eglErrorCode ) {
SDL_EGL_ERROR_TRANSLATE ( EGL_SUCCESS ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_NOT_INITIALIZED ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_ACCESS ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_ALLOC ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_ATTRIBUTE ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_CONTEXT ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_CONFIG ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_CURRENT_SURFACE ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_DISPLAY ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_SURFACE ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_MATCH ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_PARAMETER ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_NATIVE_PIXMAP ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_BAD_NATIVE_WINDOW ) ;
SDL_EGL_ERROR_TRANSLATE ( EGL_CONTEXT_LOST ) ;
}
return " " ;
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_SetErrorEx ( const char * message , const char * eglFunctionName , EGLint eglErrorCode )
2023-11-18 10:50:16 -05:00
{
const char * errorText = SDL_EGL_GetErrorName ( eglErrorCode ) ;
char altErrorText [ 32 ] ;
if ( errorText [ 0 ] = = ' \0 ' ) {
2025-04-12 04:38:19 -04:00
// An unknown-to-SDL error code was reported. Report its hexadecimal value, instead of its name.
2023-11-18 10:50:16 -05:00
( void ) SDL_snprintf ( altErrorText , SDL_arraysize ( altErrorText ) , " 0x%x " , ( unsigned int ) eglErrorCode ) ;
errorText = altErrorText ;
}
return SDL_SetError ( " %s (call to %s failed, reporting an error of %s) " , message, eglFunctionName, errorText) ;
}
2025-04-12 04:38:19 -04:00
// EGL implementation of SDL OpenGL ES support
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
bool SDL_EGL_HasExtension ( SDL_VideoDevice * _this , SDL_EGL_ExtensionType type , const char * ext )
2023-11-18 10:50:16 -05:00
{
size_t ext_len ;
const char * ext_override ;
const char * egl_extstr ;
const char * ext_start ;
2025-04-12 04:38:19 -04:00
// Invalid extensions can be rejected early
2024-07-21 17:06:25 -04:00
if ( ! ext | | * ext = = 0 | | SDL_strchr ( ext , ' ' ) ! = NULL ) {
2025-04-12 04:38:19 -04:00
// SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid EGL extension");
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
/* Extensions can be masked with a hint or environment variable.
2023-11-18 10:50:16 -05:00
* Unlike the OpenGL override , this will use the set bits of an integer
* to disable the extension .
* Bit Action
* 0 If set , the display extension is masked and not present to SDL .
* 1 If set , the client extension is masked and not present to SDL .
*/
2025-04-12 04:38:19 -04:00
ext_override = SDL_GetHint ( ext ) ;
2024-07-21 17:06:25 -04:00
if ( ext_override ) {
2023-11-18 10:50:16 -05:00
int disable_ext = SDL_atoi ( ext_override ) ;
if ( disable_ext & 0x01 & & type = = SDL_EGL_DISPLAY_EXTENSION ) {
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
} else if ( disable_ext & 0x02 & & type = = SDL_EGL_CLIENT_EXTENSION ) {
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
}
ext_len = SDL_strlen ( ext ) ;
switch ( type ) {
case SDL_EGL_DISPLAY_EXTENSION :
egl_extstr = _this - > egl_data - > eglQueryString ( _this - > egl_data - > egl_display , EGL_EXTENSIONS ) ;
break ;
case SDL_EGL_CLIENT_EXTENSION :
/* EGL_EXT_client_extensions modifies eglQueryString to return client extensions
* if EGL_NO_DISPLAY is passed . Implementations without it are required to return NULL .
* This behavior is included in EGL 1.5 .
*/
egl_extstr = _this - > egl_data - > eglQueryString ( EGL_NO_DISPLAY , EGL_EXTENSIONS ) ;
break ;
default :
2025-04-12 04:38:19 -04:00
// SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SDL_EGL_HasExtension: Invalid extension type");
return false ;
2023-11-18 10:50:16 -05:00
}
2024-07-21 17:06:25 -04:00
if ( egl_extstr ) {
2023-11-18 10:50:16 -05:00
ext_start = egl_extstr ;
while ( * ext_start ) {
ext_start = SDL_strstr ( ext_start , ext ) ;
2024-07-21 17:06:25 -04:00
if ( ! ext_start ) {
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
// Check if the match is not just a substring of one of the extensions
2023-11-18 10:50:16 -05:00
if ( ext_start = = egl_extstr | | * ( ext_start - 1 ) = = ' ' ) {
if ( ext_start [ ext_len ] = = ' ' | | ext_start [ ext_len ] = = 0 ) {
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
}
2025-04-12 04:38:19 -04:00
// If the search stopped in the middle of an extension, skip to the end of it
2023-11-18 10:50:16 -05:00
ext_start + = ext_len ;
while ( * ext_start ! = ' ' & & * ext_start ! = 0 ) {
ext_start + + ;
}
}
}
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
SDL_FunctionPointer SDL_EGL_GetProcAddressInternal ( SDL_VideoDevice * _this , const char * proc )
2023-11-18 10:50:16 -05:00
{
2025-04-12 04:38:19 -04:00
SDL_FunctionPointer result = NULL ;
2024-07-21 17:06:25 -04:00
if ( _this - > egl_data ) {
2023-11-18 10:50:16 -05:00
const Uint32 eglver = ( ( ( Uint32 ) _this - > egl_data - > egl_version_major ) < < 16 ) | ( ( Uint32 ) _this - > egl_data - > egl_version_minor ) ;
2025-04-12 04:38:19 -04:00
const bool is_egl_15_or_later = eglver > = ( ( ( ( Uint32 ) 1 ) < < 16 ) | 5 ) ;
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
// EGL 1.5 can use eglGetProcAddress() for any symbol. 1.4 and earlier can't use it for core entry points.
if ( ! result & & is_egl_15_or_later & & _this - > egl_data - > eglGetProcAddress ) {
result = _this - > egl_data - > eglGetProcAddress ( proc ) ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
# if !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_VIDEO_DRIVER_VITA) // LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems.
// Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5.
if ( ! result ) {
result = SDL_LoadFunction ( _this - > egl_data - > opengl_dll_handle , proc ) ;
2023-11-18 10:50:16 -05:00
}
# endif
2025-04-12 04:38:19 -04:00
// Try eglGetProcAddress if we're on <= 1.4 and still searching...
if ( ! result & & ! is_egl_15_or_later & & _this - > egl_data - > eglGetProcAddress ) {
result = _this - > egl_data - > eglGetProcAddress ( proc ) ;
2023-11-18 10:50:16 -05:00
}
}
2025-04-12 04:38:19 -04:00
return result ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
void SDL_EGL_UnloadLibrary ( SDL_VideoDevice * _this )
2023-11-18 10:50:16 -05:00
{
if ( _this - > egl_data ) {
if ( _this - > egl_data - > egl_display ) {
_this - > egl_data - > eglTerminate ( _this - > egl_data - > egl_display ) ;
_this - > egl_data - > egl_display = NULL ;
}
if ( _this - > egl_data - > egl_dll_handle ) {
SDL_UnloadObject ( _this - > egl_data - > egl_dll_handle ) ;
_this - > egl_data - > egl_dll_handle = NULL ;
}
if ( _this - > egl_data - > opengl_dll_handle ) {
SDL_UnloadObject ( _this - > egl_data - > opengl_dll_handle ) ;
_this - > egl_data - > opengl_dll_handle = NULL ;
}
SDL_free ( _this - > egl_data ) ;
_this - > egl_data = NULL ;
}
}
2025-04-12 04:38:19 -04:00
static bool SDL_EGL_LoadLibraryInternal ( SDL_VideoDevice * _this , const char * egl_path )
2023-11-18 10:50:16 -05:00
{
2025-04-12 04:38:19 -04:00
SDL_SharedObject * egl_dll_handle = NULL ;
# if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
SDL_SharedObject * opengl_dll_handle = NULL ;
# endif
2023-11-18 10:50:16 -05:00
const char * path = NULL ;
2025-04-12 04:38:19 -04:00
# if defined(SDL_VIDEO_DRIVER_WINDOWS)
2023-11-18 10:50:16 -05:00
const char * d3dcompiler ;
# endif
# ifdef SDL_VIDEO_DRIVER_RPI
2025-04-12 04:38:19 -04:00
bool vc4 = ( 0 = = access ( " /sys/module/vc4/ " , F_OK ) ) ;
2023-11-18 10:50:16 -05:00
# endif
2025-04-12 04:38:19 -04:00
# if defined(SDL_VIDEO_DRIVER_WINDOWS)
2023-11-18 10:50:16 -05:00
d3dcompiler = SDL_GetHint ( SDL_HINT_VIDEO_WIN_D3DCOMPILER ) ;
if ( d3dcompiler ) {
if ( SDL_strcasecmp ( d3dcompiler , " none " ) ! = 0 ) {
if ( SDL_LoadObject ( d3dcompiler ) = = NULL ) {
SDL_ClearError ( ) ;
}
}
} else {
if ( WIN_IsWindowsVistaOrGreater ( ) ) {
2025-04-12 04:38:19 -04:00
// Try the newer d3d compilers first
2023-11-18 10:50:16 -05:00
const char * d3dcompiler_list [ ] = {
" d3dcompiler_47.dll " ,
" d3dcompiler_46.dll " ,
} ;
int i ;
for ( i = 0 ; i < SDL_arraysize ( d3dcompiler_list ) ; + + i ) {
if ( SDL_LoadObject ( d3dcompiler_list [ i ] ) ! = NULL ) {
break ;
}
SDL_ClearError ( ) ;
}
} else {
if ( SDL_LoadObject ( " d3dcompiler_43.dll " ) = = NULL ) {
SDL_ClearError ( ) ;
}
}
}
# endif
# if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
/* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
2025-04-12 04:38:19 -04:00
path = SDL_GetHint ( SDL_HINT_OPENGL_LIBRARY ) ;
2024-07-21 17:06:25 -04:00
if ( path ) {
2023-11-18 10:50:16 -05:00
opengl_dll_handle = SDL_LoadObject ( path ) ;
}
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle ) {
2023-11-18 10:50:16 -05:00
if ( _this - > gl_config . profile_mask = = SDL_GL_CONTEXT_PROFILE_ES ) {
if ( _this - > gl_config . major_version > 1 ) {
path = DEFAULT_OGL_ES2 ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
# ifdef ALT_OGL_ES2
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle & & ! vc4 ) {
2023-11-18 10:50:16 -05:00
path = ALT_OGL_ES2 ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
}
# endif
} else {
path = DEFAULT_OGL_ES ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle ) {
2023-11-18 10:50:16 -05:00
path = DEFAULT_OGL_ES_PVR ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
}
# ifdef ALT_OGL_ES2
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle & & ! vc4 ) {
2023-11-18 10:50:16 -05:00
path = ALT_OGL_ES2 ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
}
# endif
}
}
# ifdef DEFAULT_OGL
else {
path = DEFAULT_OGL ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
# ifdef ALT_OGL
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle ) {
2023-11-18 10:50:16 -05:00
path = ALT_OGL ;
opengl_dll_handle = SDL_LoadObject ( path ) ;
}
# endif
}
# endif
}
_this - > egl_data - > opengl_dll_handle = opengl_dll_handle ;
2024-07-21 17:06:25 -04:00
if ( ! opengl_dll_handle ) {
2023-11-18 10:50:16 -05:00
return SDL_SetError ( " Could not initialize OpenGL / GLES library " ) ;
}
/* Loading libGL* in the previous step took care of loading libEGL.so, but we future proof by double checking */
2024-07-21 17:06:25 -04:00
if ( egl_path ) {
2023-11-18 10:50:16 -05:00
egl_dll_handle = SDL_LoadObject ( egl_path ) ;
}
2025-04-12 04:38:19 -04:00
// Try loading a EGL symbol, if it does not work try the default library paths
2024-07-21 17:06:25 -04:00
if ( ! egl_dll_handle | | SDL_LoadFunction ( egl_dll_handle , " eglChooseConfig " ) = = NULL ) {
if ( egl_dll_handle ) {
2023-11-18 10:50:16 -05:00
SDL_UnloadObject ( egl_dll_handle ) ;
}
2025-04-12 04:38:19 -04:00
path = SDL_GetHint ( SDL_HINT_EGL_LIBRARY ) ;
2024-07-21 17:06:25 -04:00
if ( ! path ) {
2023-11-18 10:50:16 -05:00
path = DEFAULT_EGL ;
}
egl_dll_handle = SDL_LoadObject ( path ) ;
# ifdef ALT_EGL
2024-07-21 17:06:25 -04:00
if ( ! egl_dll_handle & & ! vc4 ) {
2023-11-18 10:50:16 -05:00
path = ALT_EGL ;
egl_dll_handle = SDL_LoadObject ( path ) ;
}
# endif
2024-07-21 17:06:25 -04:00
if ( ! egl_dll_handle | | SDL_LoadFunction ( egl_dll_handle , " eglChooseConfig " ) = = NULL ) {
if ( egl_dll_handle ) {
2023-11-18 10:50:16 -05:00
SDL_UnloadObject ( egl_dll_handle ) ;
}
return SDL_SetError ( " Could not load EGL library " ) ;
}
SDL_ClearError ( ) ;
}
# endif
_this - > egl_data - > egl_dll_handle = egl_dll_handle ;
2025-04-12 04:38:19 -04:00
// Load new function pointers
LOAD_FUNC ( PFNEGLGETDISPLAYPROC , eglGetDisplay ) ;
LOAD_FUNC ( PFNEGLINITIALIZEPROC , eglInitialize ) ;
LOAD_FUNC ( PFNEGLTERMINATEPROC , eglTerminate ) ;
LOAD_FUNC ( PFNEGLGETPROCADDRESSPROC , eglGetProcAddress ) ;
LOAD_FUNC ( PFNEGLCHOOSECONFIGPROC , eglChooseConfig ) ;
LOAD_FUNC ( PFNEGLCREATECONTEXTPROC , eglCreateContext ) ;
LOAD_FUNC ( PFNEGLDESTROYCONTEXTPROC , eglDestroyContext ) ;
LOAD_FUNC ( PFNEGLCREATEPBUFFERSURFACEPROC , eglCreatePbufferSurface ) ;
LOAD_FUNC ( PFNEGLCREATEWINDOWSURFACEPROC , eglCreateWindowSurface ) ;
LOAD_FUNC ( PFNEGLDESTROYSURFACEPROC , eglDestroySurface ) ;
LOAD_FUNC ( PFNEGLMAKECURRENTPROC , eglMakeCurrent ) ;
LOAD_FUNC ( PFNEGLSWAPBUFFERSPROC , eglSwapBuffers ) ;
LOAD_FUNC ( PFNEGLSWAPINTERVALPROC , eglSwapInterval ) ;
LOAD_FUNC ( PFNEGLQUERYSTRINGPROC , eglQueryString ) ;
LOAD_FUNC ( PFNEGLGETCONFIGATTRIBPROC , eglGetConfigAttrib ) ;
LOAD_FUNC ( PFNEGLWAITNATIVEPROC , eglWaitNative ) ;
LOAD_FUNC ( PFNEGLWAITGLPROC , eglWaitGL ) ;
LOAD_FUNC ( PFNEGLBINDAPIPROC , eglBindAPI ) ;
LOAD_FUNC ( PFNEGLGETERRORPROC , eglGetError ) ;
LOAD_FUNC_EGLEXT ( PFNEGLQUERYDEVICESEXTPROC , eglQueryDevicesEXT ) ;
LOAD_FUNC_EGLEXT ( PFNEGLGETPLATFORMDISPLAYEXTPROC , eglGetPlatformDisplayEXT ) ;
// Atomic functions
LOAD_FUNC_EGLEXT ( PFNEGLCREATESYNCKHRPROC , eglCreateSyncKHR ) ;
LOAD_FUNC_EGLEXT ( PFNEGLDESTROYSYNCKHRPROC , eglDestroySyncKHR ) ;
LOAD_FUNC_EGLEXT ( PFNEGLDUPNATIVEFENCEFDANDROIDPROC , eglDupNativeFenceFDANDROID ) ;
LOAD_FUNC_EGLEXT ( PFNEGLWAITSYNCKHRPROC , eglWaitSyncKHR ) ;
LOAD_FUNC_EGLEXT ( PFNEGLCLIENTWAITSYNCKHRPROC , eglClientWaitSyncKHR ) ;
// Atomic functions end
2023-11-18 10:50:16 -05:00
if ( path ) {
SDL_strlcpy ( _this - > gl_config . driver_path , path , sizeof ( _this - > gl_config . driver_path ) - 1 ) ;
} else {
* _this - > gl_config . driver_path = ' \0 ' ;
}
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_LoadLibraryOnly ( SDL_VideoDevice * _this , const char * egl_path )
2023-11-18 10:50:16 -05:00
{
if ( _this - > egl_data ) {
return SDL_SetError ( " EGL context already created " ) ;
}
_this - > egl_data = ( struct SDL_EGL_VideoData * ) SDL_calloc ( 1 , sizeof ( SDL_EGL_VideoData ) ) ;
if ( ! _this - > egl_data ) {
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
if ( ! SDL_EGL_LoadLibraryInternal ( _this , egl_path ) ) {
2023-11-18 10:50:16 -05:00
SDL_free ( _this - > egl_data ) ;
_this - > egl_data = NULL ;
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
static void SDL_EGL_GetVersion ( SDL_VideoDevice * _this )
2023-11-18 10:50:16 -05:00
{
if ( _this - > egl_data - > eglQueryString ) {
const char * egl_version = _this - > egl_data - > eglQueryString ( _this - > egl_data - > egl_display , EGL_VERSION ) ;
if ( egl_version ) {
int major = 0 , minor = 0 ;
if ( SDL_sscanf ( egl_version , " %d.%d " , & major , & minor ) = = 2 ) {
_this - > egl_data - > egl_version_major = major ;
_this - > egl_data - > egl_version_minor = minor ;
} else {
SDL_LogWarn ( SDL_LOG_CATEGORY_VIDEO , " Could not parse EGL version string: %s " , egl_version ) ;
}
}
}
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_LoadLibrary ( SDL_VideoDevice * _this , const char * egl_path , NativeDisplayType native_display , EGLenum platform )
2023-11-18 10:50:16 -05:00
{
2025-04-12 04:38:19 -04:00
if ( ! SDL_EGL_LoadLibraryOnly ( _this , egl_path ) ) {
return false ;
2023-11-18 10:50:16 -05:00
}
_this - > egl_data - > egl_display = EGL_NO_DISPLAY ;
2025-04-12 04:38:19 -04:00
# ifndef SDL_VIDEO_DRIVER_VITA
2023-11-18 10:50:16 -05:00
if ( platform ) {
/* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY
* - -
* 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. "
* Therefore SDL_EGL_GetVersion ( ) shouldn ' t work with uninitialized display .
* - it actually doesn ' t work on Android that has 1.5 egl client
2025-04-12 04:38:19 -04:00
* - it works on desktop X11 ( using SDL_VIDEO_FORCE_EGL = 1 ) */
2023-11-18 10:50:16 -05:00
SDL_EGL_GetVersion ( _this ) ;
if ( _this - > egl_data - > egl_version_major = = 1 & & _this - > egl_data - > egl_version_minor = = 5 ) {
2025-04-12 04:38:19 -04:00
LOAD_FUNC ( PFNEGLGETPLATFORMDISPLAYPROC , eglGetPlatformDisplay ) ;
2023-11-18 10:50:16 -05:00
}
if ( _this - > egl_data - > eglGetPlatformDisplay ) {
2025-04-12 04:38:19 -04:00
EGLAttrib * attribs = NULL ;
if ( _this - > egl_platformattrib_callback ) {
attribs = _this - > egl_platformattrib_callback ( _this - > egl_attrib_callback_userdata ) ;
if ( ! attribs ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
return SDL_SetError ( " EGL platform attribute callback returned NULL pointer " ) ;
}
}
_this - > egl_data - > egl_display = _this - > egl_data - > eglGetPlatformDisplay ( platform , ( void * ) ( uintptr_t ) native_display , attribs ) ;
SDL_free ( attribs ) ;
2023-11-18 10:50:16 -05:00
} else {
if ( SDL_EGL_HasExtension ( _this , SDL_EGL_CLIENT_EXTENSION , " EGL_EXT_platform_base " ) ) {
2025-04-12 04:38:19 -04:00
_this - > egl_data - > eglGetPlatformDisplayEXT = ( PFNEGLGETPLATFORMDISPLAYEXTPROC ) SDL_EGL_GetProcAddressInternal ( _this , " eglGetPlatformDisplayEXT " ) ;
2023-11-18 10:50:16 -05:00
if ( _this - > egl_data - > eglGetPlatformDisplayEXT ) {
_this - > egl_data - > egl_display = _this - > egl_data - > eglGetPlatformDisplayEXT ( platform , ( void * ) ( uintptr_t ) native_display , NULL ) ;
}
}
}
}
# endif
2025-04-12 04:38:19 -04:00
// Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails
if ( ( _this - > egl_data - > egl_display = = EGL_NO_DISPLAY ) & &
( _this - > egl_data - > eglGetDisplay ) & &
SDL_GetHintBoolean ( SDL_HINT_VIDEO_EGL_ALLOW_GETDISPLAY_FALLBACK , true ) ) {
2023-11-18 10:50:16 -05:00
_this - > egl_data - > egl_display = _this - > egl_data - > eglGetDisplay ( native_display ) ;
}
if ( _this - > egl_data - > egl_display = = EGL_NO_DISPLAY ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
return SDL_SetError ( " Could not get EGL display " ) ;
}
if ( _this - > egl_data - > eglInitialize ( _this - > egl_data - > egl_display , NULL , NULL ) ! = EGL_TRUE ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
return SDL_SetError ( " Could not initialize EGL " ) ;
}
2025-04-12 04:38:19 -04:00
// Get the EGL version with a valid egl_display, for EGL <= 1.4
2023-11-18 10:50:16 -05:00
SDL_EGL_GetVersion ( _this ) ;
2025-04-12 04:38:19 -04:00
_this - > egl_data - > is_offscreen = false ;
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
/**
On multi GPU machines EGL device 0 is not always the first valid GPU .
Container environments can restrict access to some GPUs that are still listed in the EGL
device list . If the requested device is a restricted GPU and cannot be used
( eglInitialize ( ) will fail ) then attempt to automatically and silently select the next
valid available GPU for EGL to use .
*/
2025-04-12 04:38:19 -04:00
bool SDL_EGL_InitializeOffscreen ( SDL_VideoDevice * _this , int device )
2023-11-18 10:50:16 -05:00
{
void * egl_devices [ SDL_EGL_MAX_DEVICES ] ;
EGLint num_egl_devices = 0 ;
const char * egl_device_hint ;
if ( _this - > gl_config . driver_loaded < = 0 ) {
return SDL_SetError ( " SDL_EGL_LoadLibraryOnly() has not been called or has failed . " ) ;
}
2025-04-12 04:38:19 -04:00
// Check for all extensions that are optional until used and fail if any is missing
2024-07-21 17:06:25 -04:00
if ( ! _this - > egl_data - > eglQueryDevicesEXT ) {
2023-11-18 10:50:16 -05:00
return SDL_SetError ( " eglQueryDevicesEXT is missing (EXT_device_enumeration not supported by the drivers?) " ) ;
}
2024-07-21 17:06:25 -04:00
if ( ! _this - > egl_data - > eglGetPlatformDisplayEXT ) {
2023-11-18 10:50:16 -05:00
return SDL_SetError ( " eglGetPlatformDisplayEXT is missing (EXT_platform_base not supported by the drivers?) " ) ;
}
if ( _this - > egl_data - > eglQueryDevicesEXT ( SDL_EGL_MAX_DEVICES , egl_devices , & num_egl_devices ) ! = EGL_TRUE ) {
return SDL_SetError ( " eglQueryDevicesEXT() failed " ) ;
}
egl_device_hint = SDL_GetHint ( " SDL_HINT_EGL_DEVICE " ) ;
if ( egl_device_hint ) {
device = SDL_atoi ( egl_device_hint ) ;
if ( device > = num_egl_devices ) {
return SDL_SetError ( " Invalid EGL device is requested. " ) ;
}
_this - > egl_data - > egl_display = _this - > egl_data - > eglGetPlatformDisplayEXT ( EGL_PLATFORM_DEVICE_EXT , egl_devices [ device ] , NULL ) ;
if ( _this - > egl_data - > egl_display = = EGL_NO_DISPLAY ) {
return SDL_SetError ( " eglGetPlatformDisplayEXT() failed . " ) ;
}
if ( _this - > egl_data - > eglInitialize ( _this - > egl_data - > egl_display , NULL , NULL ) ! = EGL_TRUE ) {
return SDL_SetError ( " Could not initialize EGL " ) ;
}
} else {
int i ;
2025-04-12 04:38:19 -04:00
bool found = false ;
2023-11-18 10:50:16 -05:00
EGLDisplay attempted_egl_display ;
2025-04-12 04:38:19 -04:00
// If no hint is provided lets look for the first device/display that will allow us to eglInit
2023-11-18 10:50:16 -05:00
for ( i = 0 ; i < num_egl_devices ; i + + ) {
attempted_egl_display = _this - > egl_data - > eglGetPlatformDisplayEXT ( EGL_PLATFORM_DEVICE_EXT , egl_devices [ i ] , NULL ) ;
if ( attempted_egl_display = = EGL_NO_DISPLAY ) {
continue ;
}
if ( _this - > egl_data - > eglInitialize ( attempted_egl_display , NULL , NULL ) ! = EGL_TRUE ) {
_this - > egl_data - > eglTerminate ( attempted_egl_display ) ;
continue ;
}
2025-04-12 04:38:19 -04:00
// We did not fail, we'll pick this one!
2023-11-18 10:50:16 -05:00
_this - > egl_data - > egl_display = attempted_egl_display ;
2025-04-12 04:38:19 -04:00
found = true ;
2023-11-18 10:50:16 -05:00
break ;
}
if ( ! found ) {
return SDL_SetError ( " Could not find a valid EGL device to initialize " ) ;
}
}
2025-04-12 04:38:19 -04:00
// Get the EGL version with a valid egl_display, for EGL <= 1.4
2023-11-18 10:50:16 -05:00
SDL_EGL_GetVersion ( _this ) ;
2025-04-12 04:38:19 -04:00
_this - > egl_data - > is_offscreen = true ;
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
void SDL_EGL_SetRequiredVisualId ( SDL_VideoDevice * _this , int visual_id )
2023-11-18 10:50:16 -05:00
{
_this - > egl_data - > egl_required_visual_id = visual_id ;
}
# ifdef DUMP_EGL_CONFIG
# define ATTRIBUTE(_attr) \
{ \
_attr , # _attr \
}
typedef struct
{
EGLint attribute ;
char const * name ;
} Attribute ;
static Attribute all_attributes [ ] = {
ATTRIBUTE ( EGL_BUFFER_SIZE ) ,
ATTRIBUTE ( EGL_ALPHA_SIZE ) ,
ATTRIBUTE ( EGL_BLUE_SIZE ) ,
ATTRIBUTE ( EGL_GREEN_SIZE ) ,
ATTRIBUTE ( EGL_RED_SIZE ) ,
ATTRIBUTE ( EGL_DEPTH_SIZE ) ,
ATTRIBUTE ( EGL_STENCIL_SIZE ) ,
ATTRIBUTE ( EGL_CONFIG_CAVEAT ) ,
ATTRIBUTE ( EGL_CONFIG_ID ) ,
ATTRIBUTE ( EGL_LEVEL ) ,
ATTRIBUTE ( EGL_MAX_PBUFFER_HEIGHT ) ,
ATTRIBUTE ( EGL_MAX_PBUFFER_WIDTH ) ,
ATTRIBUTE ( EGL_MAX_PBUFFER_PIXELS ) ,
ATTRIBUTE ( EGL_NATIVE_RENDERABLE ) ,
ATTRIBUTE ( EGL_NATIVE_VISUAL_ID ) ,
ATTRIBUTE ( EGL_NATIVE_VISUAL_TYPE ) ,
ATTRIBUTE ( EGL_SAMPLES ) ,
ATTRIBUTE ( EGL_SAMPLE_BUFFERS ) ,
ATTRIBUTE ( EGL_SURFACE_TYPE ) ,
ATTRIBUTE ( EGL_TRANSPARENT_TYPE ) ,
ATTRIBUTE ( EGL_TRANSPARENT_BLUE_VALUE ) ,
ATTRIBUTE ( EGL_TRANSPARENT_GREEN_VALUE ) ,
ATTRIBUTE ( EGL_TRANSPARENT_RED_VALUE ) ,
ATTRIBUTE ( EGL_BIND_TO_TEXTURE_RGB ) ,
ATTRIBUTE ( EGL_BIND_TO_TEXTURE_RGBA ) ,
ATTRIBUTE ( EGL_MIN_SWAP_INTERVAL ) ,
ATTRIBUTE ( EGL_MAX_SWAP_INTERVAL ) ,
ATTRIBUTE ( EGL_LUMINANCE_SIZE ) ,
ATTRIBUTE ( EGL_ALPHA_MASK_SIZE ) ,
ATTRIBUTE ( EGL_COLOR_BUFFER_TYPE ) ,
ATTRIBUTE ( EGL_RENDERABLE_TYPE ) ,
ATTRIBUTE ( EGL_MATCH_NATIVE_PIXMAP ) ,
ATTRIBUTE ( EGL_CONFORMANT ) ,
} ;
2025-04-12 04:38:19 -04:00
static void dumpconfig ( SDL_VideoDevice * _this , EGLConfig config )
2023-11-18 10:50:16 -05:00
{
int attr ;
for ( attr = 0 ; attr < sizeof ( all_attributes ) / sizeof ( Attribute ) ; attr + + ) {
EGLint value ;
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display , config , all_attributes [ attr ] . attribute , & value ) ;
2025-04-12 04:38:19 -04:00
SDL_Log ( " \t %-32s: %10d (0x%08x) " , all_attributes [ attr ] . name , value , value ) ;
2023-11-18 10:50:16 -05:00
}
}
2025-04-12 04:38:19 -04:00
# endif // DUMP_EGL_CONFIG
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
static bool SDL_EGL_PrivateChooseConfig ( SDL_VideoDevice * _this , bool set_config_caveat_none )
2023-11-18 10:50:16 -05:00
{
2025-04-12 04:38:19 -04:00
// 64 seems nice.
2023-11-18 10:50:16 -05:00
EGLint attribs [ 64 ] ;
EGLint found_configs = 0 , value ;
2025-04-12 04:38:19 -04:00
// 128 seems even nicer here
2023-11-18 10:50:16 -05:00
EGLConfig configs [ 128 ] ;
2025-04-12 04:38:19 -04:00
bool has_matching_format = false ;
2023-11-18 10:50:16 -05:00
int i , j , best_bitdiff = - 1 , best_truecolor_bitdiff = - 1 ;
int truecolor_config_idx = - 1 ;
2025-04-12 04:38:19 -04:00
// Get a valid EGL configuration
2023-11-18 10:50:16 -05:00
i = 0 ;
attribs [ i + + ] = EGL_RED_SIZE ;
attribs [ i + + ] = _this - > gl_config . red_size ;
attribs [ i + + ] = EGL_GREEN_SIZE ;
attribs [ i + + ] = _this - > gl_config . green_size ;
attribs [ i + + ] = EGL_BLUE_SIZE ;
attribs [ i + + ] = _this - > gl_config . blue_size ;
if ( set_config_caveat_none ) {
attribs [ i + + ] = EGL_CONFIG_CAVEAT ;
attribs [ i + + ] = EGL_NONE ;
}
if ( _this - > gl_config . alpha_size ) {
attribs [ i + + ] = EGL_ALPHA_SIZE ;
attribs [ i + + ] = _this - > gl_config . alpha_size ;
}
if ( _this - > gl_config . buffer_size ) {
attribs [ i + + ] = EGL_BUFFER_SIZE ;
attribs [ i + + ] = _this - > gl_config . buffer_size ;
}
if ( _this - > gl_config . depth_size ) {
attribs [ i + + ] = EGL_DEPTH_SIZE ;
attribs [ i + + ] = _this - > gl_config . depth_size ;
}
if ( _this - > gl_config . stencil_size ) {
attribs [ i + + ] = EGL_STENCIL_SIZE ;
attribs [ i + + ] = _this - > gl_config . stencil_size ;
}
if ( _this - > gl_config . multisamplebuffers ) {
attribs [ i + + ] = EGL_SAMPLE_BUFFERS ;
attribs [ i + + ] = _this - > gl_config . multisamplebuffers ;
}
if ( _this - > gl_config . multisamplesamples ) {
attribs [ i + + ] = EGL_SAMPLES ;
attribs [ i + + ] = _this - > gl_config . multisamplesamples ;
}
if ( _this - > gl_config . floatbuffers ) {
attribs [ i + + ] = EGL_COLOR_COMPONENT_TYPE_EXT ;
attribs [ i + + ] = EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT ;
}
if ( _this - > egl_data - > is_offscreen ) {
attribs [ i + + ] = EGL_SURFACE_TYPE ;
attribs [ i + + ] = EGL_PBUFFER_BIT ;
}
attribs [ i + + ] = EGL_RENDERABLE_TYPE ;
if ( _this - > gl_config . profile_mask = = SDL_GL_CONTEXT_PROFILE_ES ) {
# ifdef EGL_KHR_create_context
if ( _this - > gl_config . major_version > = 3 & &
SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_create_context " ) ) {
attribs [ i + + ] = EGL_OPENGL_ES3_BIT_KHR ;
} else
# endif
if ( _this - > gl_config . major_version > = 2 ) {
attribs [ i + + ] = EGL_OPENGL_ES2_BIT ;
} else {
attribs [ i + + ] = EGL_OPENGL_ES_BIT ;
}
_this - > egl_data - > eglBindAPI ( EGL_OPENGL_ES_API ) ;
} else {
attribs [ i + + ] = EGL_OPENGL_BIT ;
_this - > egl_data - > eglBindAPI ( EGL_OPENGL_API ) ;
}
if ( _this - > egl_data - > egl_surfacetype ) {
attribs [ i + + ] = EGL_SURFACE_TYPE ;
attribs [ i + + ] = _this - > egl_data - > egl_surfacetype ;
}
attribs [ i + + ] = EGL_NONE ;
SDL_assert ( i < SDL_arraysize ( attribs ) ) ;
if ( _this - > egl_data - > eglChooseConfig ( _this - > egl_data - > egl_display ,
attribs ,
configs , SDL_arraysize ( configs ) ,
& found_configs ) = = EGL_FALSE | |
found_configs = = 0 ) {
2025-04-12 04:38:19 -04:00
return false ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
// first ensure that a found config has a matching format, or the function will fall through.
2023-11-18 10:50:16 -05:00
if ( _this - > egl_data - > egl_required_visual_id ) {
for ( i = 0 ; i < found_configs ; i + + ) {
EGLint format ;
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display ,
configs [ i ] ,
EGL_NATIVE_VISUAL_ID , & format ) ;
if ( _this - > egl_data - > egl_required_visual_id = = format ) {
2025-04-12 04:38:19 -04:00
has_matching_format = true ;
2023-11-18 10:50:16 -05:00
break ;
}
}
}
2025-04-12 04:38:19 -04:00
// eglChooseConfig returns a number of configurations that match or exceed the requested attribs.
// From those, we select the one that matches our requirements more closely via a makeshift algorithm
2023-11-18 10:50:16 -05:00
for ( i = 0 ; i < found_configs ; i + + ) {
2025-04-12 04:38:19 -04:00
bool is_truecolor = false ;
2023-11-18 10:50:16 -05:00
int bitdiff = 0 ;
if ( has_matching_format & & _this - > egl_data - > egl_required_visual_id ) {
EGLint format ;
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display ,
configs [ i ] ,
EGL_NATIVE_VISUAL_ID , & format ) ;
if ( _this - > egl_data - > egl_required_visual_id ! = format ) {
continue ;
}
}
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display , configs [ i ] , EGL_RED_SIZE , & value ) ;
if ( value = = 8 ) {
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display , configs [ i ] , EGL_GREEN_SIZE , & value ) ;
if ( value = = 8 ) {
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display , configs [ i ] , EGL_BLUE_SIZE , & value ) ;
if ( value = = 8 ) {
2025-04-12 04:38:19 -04:00
is_truecolor = true ;
2023-11-18 10:50:16 -05:00
}
}
}
for ( j = 0 ; j < SDL_arraysize ( attribs ) - 1 ; j + = 2 ) {
if ( attribs [ j ] = = EGL_NONE ) {
break ;
}
if ( attribs [ j + 1 ] ! = EGL_DONT_CARE & & ( attribs [ j ] = = EGL_RED_SIZE | |
attribs [ j ] = = EGL_GREEN_SIZE | |
attribs [ j ] = = EGL_BLUE_SIZE | |
attribs [ j ] = = EGL_ALPHA_SIZE | |
attribs [ j ] = = EGL_DEPTH_SIZE | |
attribs [ j ] = = EGL_STENCIL_SIZE ) ) {
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display , configs [ i ] , attribs [ j ] , & value ) ;
2025-04-12 04:38:19 -04:00
bitdiff + = value - attribs [ j + 1 ] ; // value is always >= attrib
2023-11-18 10:50:16 -05:00
}
}
if ( ( bitdiff < best_bitdiff ) | | ( best_bitdiff = = - 1 ) ) {
_this - > egl_data - > egl_config = configs [ i ] ;
best_bitdiff = bitdiff ;
}
if ( is_truecolor & & ( ( bitdiff < best_truecolor_bitdiff ) | | ( best_truecolor_bitdiff = = - 1 ) ) ) {
truecolor_config_idx = i ;
best_truecolor_bitdiff = bitdiff ;
}
}
# define FAVOR_TRUECOLOR 1
# if FAVOR_TRUECOLOR
/* Some apps request a low color depth, either because they _assume_
they ' ll get a larger one but don ' t want to fail if only smaller ones
are available , or they just never called SDL_GL_SetAttribute at all and
got a tiny default . For these cases , a game that would otherwise run
at 24 - bit color might get dithered down to something smaller , which is
worth avoiding . If the app requested < = 16 bit color and an exact 24 - bit
match is available , favor that . Otherwise , we look for the closest
match . Note that while the API promises what you request _or better_ ,
it ' s feasible this can be disastrous for performance for custom software
on small hardware that all expected to actually get 16 - bit color . In this
case , turn off FAVOR_TRUECOLOR ( and maybe send a patch to make this more
flexible ) . */
if ( ( ( _this - > gl_config . red_size + _this - > gl_config . blue_size + _this - > gl_config . green_size ) < = 16 ) ) {
if ( truecolor_config_idx ! = - 1 ) {
_this - > egl_data - > egl_config = configs [ truecolor_config_idx ] ;
}
}
# endif
# ifdef DUMP_EGL_CONFIG
dumpconfig ( _this , _this - > egl_data - > egl_config ) ;
# endif
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_ChooseConfig ( SDL_VideoDevice * _this )
2023-11-18 10:50:16 -05:00
{
if ( ! _this - > egl_data ) {
return SDL_SetError ( " EGL not initialized " ) ;
}
2025-04-12 04:38:19 -04:00
// Try with EGL_CONFIG_CAVEAT set to EGL_NONE, to avoid any EGL_SLOW_CONFIG or EGL_NON_CONFORMANT_CONFIG
if ( SDL_EGL_PrivateChooseConfig ( _this , true ) ) {
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
// Fallback with all configs
if ( SDL_EGL_PrivateChooseConfig ( _this , false ) ) {
2023-11-18 10:50:16 -05:00
SDL_Log ( " SDL_EGL_ChooseConfig: found a slow EGL config " ) ;
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
return SDL_EGL_SetError ( " Couldn't find matching EGL config " , " eglChooseConfig " ) ;
}
2025-04-12 04:38:19 -04:00
SDL_GLContext SDL_EGL_CreateContext ( SDL_VideoDevice * _this , EGLSurface egl_surface )
2023-11-18 10:50:16 -05:00
{
2025-04-12 04:38:19 -04:00
// max 16 key+value pairs plus terminator.
EGLint attribs [ 33 ] ;
2023-11-18 10:50:16 -05:00
int attr = 0 ;
EGLContext egl_context , share_context = EGL_NO_CONTEXT ;
EGLint profile_mask = _this - > gl_config . profile_mask ;
EGLint major_version = _this - > gl_config . major_version ;
EGLint minor_version = _this - > gl_config . minor_version ;
2025-04-12 04:38:19 -04:00
bool profile_es = ( profile_mask = = SDL_GL_CONTEXT_PROFILE_ES ) ;
2023-11-18 10:50:16 -05:00
if ( ! _this - > egl_data ) {
SDL_SetError ( " EGL not initialized " ) ;
return NULL ;
}
if ( _this - > gl_config . share_with_current_context ) {
share_context = ( EGLContext ) SDL_GL_GetCurrentContext ( ) ;
}
# ifdef SDL_VIDEO_DRIVER_ANDROID
if ( _this - > gl_config . flags & SDL_GL_CONTEXT_DEBUG_FLAG ) {
/* If SDL_GL_CONTEXT_DEBUG_FLAG is set but EGL_KHR_debug unsupported, unset.
* This is required because some Android devices like to complain about it
* by " silently " failing , logging a hint which could be easily overlooked :
* E / libEGL ( 26984 ) : validate_display : 255 error 3008 ( EGL_BAD_DISPLAY )
* The following explicitly checks for EGL_KHR_debug before EGL 1.5
*/
int egl_version_major = _this - > egl_data - > egl_version_major ;
int egl_version_minor = _this - > egl_data - > egl_version_minor ;
if ( ( ( egl_version_major < 1 ) | | ( egl_version_major = = 1 & & egl_version_minor < 5 ) ) & &
! SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_debug " ) ) {
2025-04-12 04:38:19 -04:00
// SDL profile bits match EGL profile bits.
2023-11-18 10:50:16 -05:00
_this - > gl_config . flags & = ~ SDL_GL_CONTEXT_DEBUG_FLAG ;
}
}
# endif
2025-04-12 04:38:19 -04:00
// Set the context version and other attributes.
2023-11-18 10:50:16 -05:00
if ( ( major_version < 3 | | ( minor_version = = 0 & & profile_es ) ) & &
_this - > gl_config . flags = = 0 & &
( profile_mask = = 0 | | profile_es ) ) {
/* Create a context without using EGL_KHR_create_context attribs.
* When creating a GLES context without EGL_KHR_create_context we can
* only specify the major version . When creating a desktop GL context
* we can ' t specify any version , so we only try in that case when the
* version is less than 3.0 ( matches SDL ' s GLX / WGL behavior . )
*/
if ( profile_es ) {
attribs [ attr + + ] = EGL_CONTEXT_CLIENT_VERSION ;
attribs [ attr + + ] = SDL_max ( major_version , 1 ) ;
}
} else {
# ifdef EGL_KHR_create_context
/* The Major/minor version, context profiles, and context flags can
* only be specified when this extension is available .
*/
if ( SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_create_context " ) ) {
attribs [ attr + + ] = EGL_CONTEXT_MAJOR_VERSION_KHR ;
attribs [ attr + + ] = major_version ;
attribs [ attr + + ] = EGL_CONTEXT_MINOR_VERSION_KHR ;
attribs [ attr + + ] = minor_version ;
2025-04-12 04:38:19 -04:00
// SDL profile bits match EGL profile bits.
2023-11-18 10:50:16 -05:00
if ( profile_mask ! = 0 & & profile_mask ! = SDL_GL_CONTEXT_PROFILE_ES ) {
attribs [ attr + + ] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR ;
attribs [ attr + + ] = profile_mask ;
}
2025-04-12 04:38:19 -04:00
// SDL flags match EGL flags.
2023-11-18 10:50:16 -05:00
if ( _this - > gl_config . flags ! = 0 ) {
attribs [ attr + + ] = EGL_CONTEXT_FLAGS_KHR ;
attribs [ attr + + ] = _this - > gl_config . flags ;
}
} else
2025-04-12 04:38:19 -04:00
# endif // EGL_KHR_create_context
2023-11-18 10:50:16 -05:00
{
SDL_SetError ( " Could not create EGL context (context attributes are not supported) " ) ;
return NULL ;
}
}
# ifdef EGL_KHR_create_context_no_error
if ( _this - > gl_config . no_error ) {
if ( SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_create_context_no_error " ) ) {
attribs [ attr + + ] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR ;
attribs [ attr + + ] = _this - > gl_config . no_error ;
}
}
# endif
2025-04-12 04:38:19 -04:00
if ( _this - > egl_contextattrib_callback ) {
const int maxAttribs = sizeof ( attribs ) / sizeof ( attribs [ 0 ] ) ;
EGLint * userAttribs , * userAttribP ;
userAttribs = _this - > egl_contextattrib_callback ( _this - > egl_attrib_callback_userdata , _this - > egl_data - > egl_display , _this - > egl_data - > egl_config ) ;
if ( ! userAttribs ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
SDL_SetError ( " EGL context attribute callback returned NULL pointer " ) ;
return NULL ;
}
for ( userAttribP = userAttribs ; * userAttribP ! = EGL_NONE ; ) {
if ( attr + 3 > = maxAttribs ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
SDL_SetError ( " EGL context attribute callback returned too many attributes " ) ;
return NULL ;
}
attribs [ attr + + ] = * userAttribP + + ;
attribs [ attr + + ] = * userAttribP + + ;
}
SDL_free ( userAttribs ) ;
}
2023-11-18 10:50:16 -05:00
attribs [ attr + + ] = EGL_NONE ;
2025-04-12 04:38:19 -04:00
// Bind the API
2023-11-18 10:50:16 -05:00
if ( profile_es ) {
_this - > egl_data - > apitype = EGL_OPENGL_ES_API ;
} else {
_this - > egl_data - > apitype = EGL_OPENGL_API ;
}
_this - > egl_data - > eglBindAPI ( _this - > egl_data - > apitype ) ;
egl_context = _this - > egl_data - > eglCreateContext ( _this - > egl_data - > egl_display ,
_this - > egl_data - > egl_config ,
share_context , attribs ) ;
if ( egl_context = = EGL_NO_CONTEXT ) {
SDL_EGL_SetError ( " Could not create EGL context " , " eglCreateContext " ) ;
return NULL ;
}
_this - > egl_data - > egl_swapinterval = 0 ;
2025-04-12 04:38:19 -04:00
if ( ! SDL_EGL_MakeCurrent ( _this , egl_surface , ( SDL_GLContext ) egl_context ) ) {
// Delete the context
SDL_EGL_DestroyContext ( _this , ( SDL_GLContext ) egl_context ) ;
2023-11-18 10:50:16 -05:00
return NULL ;
}
/* Check whether making contexts current without a surface is supported.
* First condition : EGL must support it . That ' s the case for EGL 1.5
* or later , or if the EGL_KHR_surfaceless_context extension is present . */
if ( ( _this - > egl_data - > egl_version_major > 1 ) | |
( ( _this - > egl_data - > egl_version_major = = 1 ) & & ( _this - > egl_data - > egl_version_minor > = 5 ) ) | |
SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_surfaceless_context " ) ) {
2025-04-12 04:38:19 -04:00
// Secondary condition: The client API must support it.
2023-11-18 10:50:16 -05:00
if ( profile_es ) {
/* On OpenGL ES, the GL_OES_surfaceless_context extension must be
* present . */
if ( SDL_GL_ExtensionSupported ( " GL_OES_surfaceless_context " ) ) {
2025-04-12 04:38:19 -04:00
_this - > gl_allow_no_surface = true ;
2023-11-18 10:50:16 -05:00
}
# if defined(SDL_VIDEO_OPENGL) && !defined(SDL_VIDEO_DRIVER_VITA)
} else {
2025-04-12 04:38:19 -04:00
// Desktop OpenGL supports it by default from version 3.0 on.
PFNGLGETINTEGERVPROC glGetIntegervFunc = ( PFNGLGETINTEGERVPROC ) SDL_GL_GetProcAddress ( " glGetIntegerv " ) ;
2023-11-18 10:50:16 -05:00
if ( glGetIntegervFunc ) {
GLint v = 0 ;
glGetIntegervFunc ( GL_MAJOR_VERSION , & v ) ;
if ( v > = 3 ) {
2025-04-12 04:38:19 -04:00
_this - > gl_allow_no_surface = true ;
2023-11-18 10:50:16 -05:00
}
}
# endif
}
}
return ( SDL_GLContext ) egl_context ;
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_MakeCurrent ( SDL_VideoDevice * _this , EGLSurface egl_surface , SDL_GLContext context )
2023-11-18 10:50:16 -05:00
{
EGLContext egl_context = ( EGLContext ) context ;
if ( ! _this - > egl_data ) {
return SDL_SetError ( " EGL not initialized " ) ;
}
if ( ! _this - > egl_data - > eglMakeCurrent ) {
if ( ! egl_surface & & ! context ) {
2025-04-12 04:38:19 -04:00
// Can't do the nothing there is to do? Probably trying to cleanup a failed startup, just return.
return true ;
2023-11-18 10:50:16 -05:00
} else {
2025-04-12 04:38:19 -04:00
return SDL_SetError ( " EGL not initialized " ) ; // something clearly went wrong somewhere.
2023-11-18 10:50:16 -05:00
}
}
2025-04-12 04:38:19 -04:00
// Make sure current thread has a valid API bound to it.
2023-11-18 10:50:16 -05:00
if ( _this - > egl_data - > eglBindAPI ) {
_this - > egl_data - > eglBindAPI ( _this - > egl_data - > apitype ) ;
}
/* The android emulator crashes badly if you try to eglMakeCurrent
* with a valid context and invalid surface , so we have to check for both here .
*/
if ( ! egl_context | | ( ! egl_surface & & ! _this - > gl_allow_no_surface ) ) {
_this - > egl_data - > eglMakeCurrent ( _this - > egl_data - > egl_display , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
} else {
if ( ! _this - > egl_data - > eglMakeCurrent ( _this - > egl_data - > egl_display ,
egl_surface , egl_surface , egl_context ) ) {
return SDL_EGL_SetError ( " Unable to make EGL context current " , " eglMakeCurrent " ) ;
}
}
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_SetSwapInterval ( SDL_VideoDevice * _this , int interval )
2023-11-18 10:50:16 -05:00
{
EGLBoolean status ;
if ( ! _this - > egl_data ) {
return SDL_SetError ( " EGL not initialized " ) ;
}
/* FIXME: Revisit this check when EGL_EXT_swap_control_tear is published:
* https : //github.com/KhronosGroup/EGL-Registry/pull/113
*/
if ( interval < 0 ) {
return SDL_SetError ( " Late swap tearing currently unsupported " ) ;
}
status = _this - > egl_data - > eglSwapInterval ( _this - > egl_data - > egl_display , interval ) ;
if ( status = = EGL_TRUE ) {
_this - > egl_data - > egl_swapinterval = interval ;
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
return SDL_EGL_SetError ( " Unable to set the EGL swap interval " , " eglSwapInterval " ) ;
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_GetSwapInterval ( SDL_VideoDevice * _this , int * interval )
2023-11-18 10:50:16 -05:00
{
if ( ! _this - > egl_data ) {
2025-04-12 04:38:19 -04:00
return SDL_SetError ( " EGL not initialized " ) ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
* interval = _this - > egl_data - > egl_swapinterval ;
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_SwapBuffers ( SDL_VideoDevice * _this , EGLSurface egl_surface )
2023-11-18 10:50:16 -05:00
{
if ( ! _this - > egl_data - > eglSwapBuffers ( _this - > egl_data - > egl_display , egl_surface ) ) {
return SDL_EGL_SetError ( " unable to show color buffer in an OS-native window " , " eglSwapBuffers " ) ;
}
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
bool SDL_EGL_DestroyContext ( SDL_VideoDevice * _this , SDL_GLContext context )
2023-11-18 10:50:16 -05:00
{
EGLContext egl_context = ( EGLContext ) context ;
2025-04-12 04:38:19 -04:00
// Clean up GLES and EGL
2023-11-18 10:50:16 -05:00
if ( ! _this - > egl_data ) {
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
if ( egl_context ! = NULL & & egl_context ! = EGL_NO_CONTEXT ) {
_this - > egl_data - > eglDestroyContext ( _this - > egl_data - > egl_display , egl_context ) ;
}
2025-04-12 04:38:19 -04:00
return true ;
2023-11-18 10:50:16 -05:00
}
2025-04-12 04:38:19 -04:00
EGLSurface SDL_EGL_CreateSurface ( SDL_VideoDevice * _this , SDL_Window * window , NativeWindowType nw )
2023-11-18 10:50:16 -05:00
{
# ifdef SDL_VIDEO_DRIVER_ANDROID
EGLint format_wanted ;
EGLint format_got ;
# endif
2025-04-12 04:38:19 -04:00
// max 16 key+value pairs, plus terminator.
EGLint attribs [ 33 ] ;
2023-11-18 10:50:16 -05:00
int attr = 0 ;
2025-04-12 04:38:19 -04:00
EGLSurface surface ;
2023-11-18 10:50:16 -05:00
2025-04-12 04:38:19 -04:00
if ( ! SDL_EGL_ChooseConfig ( _this ) ) {
2023-11-18 10:50:16 -05:00
return EGL_NO_SURFACE ;
}
# ifdef SDL_VIDEO_DRIVER_ANDROID
/* On Android, EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry ( ) . */
_this - > egl_data - > eglGetConfigAttrib ( _this - > egl_data - > egl_display ,
_this - > egl_data - > egl_config ,
EGL_NATIVE_VISUAL_ID , & format_wanted ) ;
2025-04-12 04:38:19 -04:00
// Format based on selected egl config.
2023-11-18 10:50:16 -05:00
ANativeWindow_setBuffersGeometry ( nw , 0 , 0 , format_wanted ) ;
# endif
if ( _this - > gl_config . framebuffer_srgb_capable ) {
# ifdef EGL_KHR_gl_colorspace
if ( SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_KHR_gl_colorspace " ) ) {
attribs [ attr + + ] = EGL_GL_COLORSPACE_KHR ;
attribs [ attr + + ] = EGL_GL_COLORSPACE_SRGB_KHR ;
} else
# endif
{
SDL_SetError ( " EGL implementation does not support sRGB system framebuffers " ) ;
return EGL_NO_SURFACE ;
}
}
# ifdef EGL_EXT_present_opaque
if ( SDL_EGL_HasExtension ( _this , SDL_EGL_DISPLAY_EXTENSION , " EGL_EXT_present_opaque " ) ) {
2025-04-12 04:38:19 -04:00
bool allow_transparent = false ;
if ( window & & ( window - > flags & SDL_WINDOW_TRANSPARENT ) ) {
allow_transparent = true ;
}
2023-11-18 10:50:16 -05:00
attribs [ attr + + ] = EGL_PRESENT_OPAQUE_EXT ;
attribs [ attr + + ] = allow_transparent ? EGL_FALSE : EGL_TRUE ;
}
# endif
2025-04-12 04:38:19 -04:00
if ( _this - > egl_surfaceattrib_callback ) {
const int maxAttribs = sizeof ( attribs ) / sizeof ( attribs [ 0 ] ) ;
EGLint * userAttribs , * userAttribP ;
userAttribs = _this - > egl_surfaceattrib_callback ( _this - > egl_attrib_callback_userdata , _this - > egl_data - > egl_display , _this - > egl_data - > egl_config ) ;
if ( ! userAttribs ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
SDL_SetError ( " EGL surface attribute callback returned NULL pointer " ) ;
return EGL_NO_SURFACE ;
}
for ( userAttribP = userAttribs ; * userAttribP ! = EGL_NONE ; ) {
if ( attr + 3 > = maxAttribs ) {
_this - > gl_config . driver_loaded = 0 ;
* _this - > gl_config . driver_path = ' \0 ' ;
SDL_SetError ( " EGL surface attribute callback returned too many attributes " ) ;
return EGL_NO_SURFACE ;
}
attribs [ attr + + ] = * userAttribP + + ;
attribs [ attr + + ] = * userAttribP + + ;
}
SDL_free ( userAttribs ) ;
}
2023-11-18 10:50:16 -05:00
attribs [ attr + + ] = EGL_NONE ;
surface = _this - > egl_data - > eglCreateWindowSurface (
_this - > egl_data - > egl_display ,
_this - > egl_data - > egl_config ,
nw , & attribs [ 0 ] ) ;
if ( surface = = EGL_NO_SURFACE ) {
SDL_EGL_SetError ( " unable to create an EGL window surface " , " eglCreateWindowSurface " ) ;
}
# ifdef SDL_VIDEO_DRIVER_ANDROID
format_got = ANativeWindow_getFormat ( nw ) ;
Android_SetFormat ( format_wanted , format_got ) ;
# endif
return surface ;
}
EGLSurface
2025-04-12 04:38:19 -04:00
SDL_EGL_CreateOffscreenSurface ( SDL_VideoDevice * _this , int width , int height )
2023-11-18 10:50:16 -05:00
{
EGLint attributes [ ] = {
EGL_WIDTH , 0 ,
EGL_HEIGHT , 0 ,
EGL_NONE
} ;
attributes [ 1 ] = width ;
attributes [ 3 ] = height ;
2025-04-12 04:38:19 -04:00
if ( ! SDL_EGL_ChooseConfig ( _this ) ) {
2023-11-18 10:50:16 -05:00
return EGL_NO_SURFACE ;
}
return _this - > egl_data - > eglCreatePbufferSurface (
_this - > egl_data - > egl_display ,
_this - > egl_data - > egl_config ,
attributes ) ;
}
2025-04-12 04:38:19 -04:00
void SDL_EGL_DestroySurface ( SDL_VideoDevice * _this , EGLSurface egl_surface )
2023-11-18 10:50:16 -05:00
{
if ( ! _this - > egl_data ) {
return ;
}
if ( egl_surface ! = EGL_NO_SURFACE ) {
_this - > egl_data - > eglDestroySurface ( _this - > egl_data - > egl_display , egl_surface ) ;
}
}
2025-04-12 04:38:19 -04:00
# endif // SDL_VIDEO_OPENGL_EGL