|
@@ -94,6 +94,11 @@ if (!_this->egl_data->NAME) \
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/* it is allowed to not have some of the EGL extensions on start - attempts to use them will fail later. */
|
|
|
+#define LOAD_FUNC_EGLEXT(NAME) \
|
|
|
+ _this->egl_data->NAME = _this->egl_data->eglGetProcAddress(#NAME);
|
|
|
+
|
|
|
+
|
|
|
static const char * SDL_EGL_GetErrorName(EGLint eglErrorCode)
|
|
|
{
|
|
|
#define SDL_EGL_ERROR_TRANSLATE(e) case e: return #e;
|
|
@@ -256,11 +261,10 @@ SDL_EGL_UnloadLibrary(_THIS)
|
|
|
}
|
|
|
|
|
|
int
|
|
|
-SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
|
|
|
+SDL_EGL_LoadLibraryOnly(_THIS, const char *egl_path)
|
|
|
{
|
|
|
void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */
|
|
|
const char *path = NULL;
|
|
|
- int egl_version_major = 0, egl_version_minor = 0;
|
|
|
#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
|
|
|
const char *d3dcompiler;
|
|
|
#endif
|
|
@@ -406,8 +410,31 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
|
|
|
LOAD_FUNC(eglWaitNative);
|
|
|
LOAD_FUNC(eglWaitGL);
|
|
|
LOAD_FUNC(eglBindAPI);
|
|
|
+ LOAD_FUNC(eglQueryAPI);
|
|
|
LOAD_FUNC(eglQueryString);
|
|
|
LOAD_FUNC(eglGetError);
|
|
|
+ LOAD_FUNC_EGLEXT(eglQueryDevicesEXT);
|
|
|
+ LOAD_FUNC_EGLEXT(eglGetPlatformDisplayEXT);
|
|
|
+
|
|
|
+ _this->gl_config.driver_loaded = 1;
|
|
|
+
|
|
|
+ if (path) {
|
|
|
+ SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
|
|
|
+ } else {
|
|
|
+ *_this->gl_config.driver_path = '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display, EGLenum platform)
|
|
|
+{
|
|
|
+ int egl_version_major = 0, egl_version_minor = 0;
|
|
|
+ int library_load_retcode = SDL_EGL_LoadLibraryOnly(_this, egl_path);
|
|
|
+ if (library_load_retcode != 0) {
|
|
|
+ return library_load_retcode;
|
|
|
+ }
|
|
|
|
|
|
if (_this->egl_data->eglQueryString) {
|
|
|
/* EGL 1.5 allows querying for client version */
|
|
@@ -447,20 +474,105 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
|
|
|
_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");
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- if (path) {
|
|
|
- SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
|
|
|
- } else {
|
|
|
- *_this->gl_config.driver_path = '\0';
|
|
|
+ _this->egl_data->is_offscreen = 0;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ 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.
|
|
|
+*/
|
|
|
+
|
|
|
+int
|
|
|
+SDL_EGL_InitializeOffscreen(_THIS, int device)
|
|
|
+{
|
|
|
+ EGLDeviceEXT egl_devices[SDL_EGL_MAX_DEVICES];
|
|
|
+ EGLint num_egl_devices = 0;
|
|
|
+ const char *egl_device_hint;
|
|
|
+
|
|
|
+ if (_this->gl_config.driver_loaded != 1) {
|
|
|
+ return SDL_SetError("SDL_EGL_LoadLibraryOnly() has not been called or has failed.");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /* Check for all extensions that are optional until used and fail if any is missing */
|
|
|
+ if (_this->egl_data->eglQueryDevicesEXT == NULL) {
|
|
|
+ return SDL_SetError("eglQueryDevicesEXT is missing (EXT_device_enumeration not supported by the drivers?)");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_this->egl_data->eglGetPlatformDisplayEXT == NULL) {
|
|
|
+ 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;
|
|
|
+ SDL_bool found = SDL_FALSE;
|
|
|
+ EGLDisplay attempted_egl_display;
|
|
|
+
|
|
|
+ /* If no hint is provided lets look for the first device/display that will allow us to eglInit */
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* We did not fail, we'll pick this one! */
|
|
|
+ _this->egl_data->egl_display = attempted_egl_display;
|
|
|
+ found = SDL_TRUE;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!found) {
|
|
|
+ return SDL_SetError("Could not find a valid EGL device to initialize");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _this->egl_data->is_offscreen = 1;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -580,6 +692,11 @@ SDL_EGL_ChooseConfig(_THIS)
|
|
|
attribs[i++] = _this->gl_config.multisamplesamples;
|
|
|
}
|
|
|
|
|
|
+ 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
|
|
@@ -931,6 +1048,25 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw)
|
|
|
return surface;
|
|
|
}
|
|
|
|
|
|
+EGLSurface
|
|
|
+SDL_EGL_CreateOffscreenSurface(_THIS, int width, int height)
|
|
|
+{
|
|
|
+ EGLint attributes[] = {
|
|
|
+ EGL_WIDTH, width,
|
|
|
+ EGL_HEIGHT, height,
|
|
|
+ EGL_NONE
|
|
|
+ };
|
|
|
+
|
|
|
+ if (SDL_EGL_ChooseConfig(_this) != 0) {
|
|
|
+ return EGL_NO_SURFACE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return _this->egl_data->eglCreatePbufferSurface(
|
|
|
+ _this->egl_data->egl_display,
|
|
|
+ _this->egl_data->egl_config,
|
|
|
+ attributes);
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
SDL_EGL_DestroySurface(_THIS, EGLSurface egl_surface)
|
|
|
{
|