From 5b1a187f713a896f244cb48fdac7e9ca3e406c56 Mon Sep 17 00:00:00 2001 From: Kamal Date: Wed, 15 Jun 2016 15:53:00 +0530 Subject: [PATCH] Add EGLDevice backend to GLFW This adds interface to graphics application to create EGLDisplay directly over GPU device as enabled by EGLDevice extensions Fixes #786. --- CMakeLists.txt | 13 ++ src/CMakeLists.txt | 6 + src/egl_context.c | 16 ++ src/egl_context.h | 2 + src/egldevice_init.c | 301 +++++++++++++++++++++++++++++ src/egldevice_monitor.c | 177 +++++++++++++++++ src/egldevice_platform.h | 119 ++++++++++++ src/egldevice_window.c | 396 +++++++++++++++++++++++++++++++++++++++ src/glfw_config.h.in | 2 + src/internal.h | 2 + 10 files changed, 1034 insertions(+) create mode 100644 src/egldevice_init.c create mode 100644 src/egldevice_monitor.c create mode 100644 src/egldevice_platform.h create mode 100644 src/egldevice_window.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 56c1f386..467fc7ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,9 @@ elseif (GLFW_USE_MIR) elseif (GLFW_USE_OSMESA) set(_GLFW_OSMESA 1) message(STATUS "Using OSMesa for headless context creation") +elseif (GLFW_USE_EGLDEVICE) + set(_GLFW_EGLDEVICE 1) + message(STATUS "Using EGLDevice for window creation") elseif (WIN32) set(_GLFW_WIN32 1) message(STATUS "Using Win32 for window creation") @@ -291,6 +294,16 @@ if (_GLFW_WAYLAND) list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") endif() +#-------------------------------------------------------------------- +# Use EGLDevice for window creation +#-------------------------------------------------------------------- +if (_GLFW_EGLDEVICE) + + list(APPEND glfw_LIBRARIES "-ldrm") + list(APPEND glfw_LIBRARIES "-lpthread") + +endif() + #-------------------------------------------------------------------- # Use Mir for window creation #-------------------------------------------------------------------- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b14512cc..7be4a074 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,12 @@ elseif (_GLFW_WAYLAND) PROTOCOL "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" BASENAME pointer-constraints-unstable-v1) +elseif(_GLFW_EGLDEVICE) + set(glfw_HEADERS ${common_HEADERS} egldevice_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h egl_context.h) + set(glfw_SOURCES ${common_SOURCES} egldevice_init.c egldevice_monitor.c egldevice_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c + egl_context.c) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h posix_time.h posix_thread.h xkb_unicode.h egl_context.h diff --git a/src/egl_context.c b/src/egl_context.c index 54257f25..bef7525c 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -116,10 +116,18 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER) continue; +#if defined(_GLFW_EGLDEVICE) + // Only consider stream EGLConfigs + if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_STREAM_BIT_KHR)) + continue; + +#else // Only consider window EGLConfigs if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) continue; +#endif + #if defined(_GLFW_X11) // Only consider EGLConfigs with associated Visuals if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) @@ -376,6 +384,9 @@ GLFWbool _glfwInitEGL(void) return GLFW_FALSE; } +// For EGLDevice backend the display gets initialized +// in _glfwPlatformInit() +#if !defined(_GLFW_EGLDEVICE) _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); if (_glfw.egl.display == EGL_NO_DISPLAY) { @@ -396,6 +407,7 @@ GLFWbool _glfwInitEGL(void) _glfwTerminateEGL(); return GLFW_FALSE; } +#endif _glfw.egl.KHR_create_context = extensionSupportedEGL("EGL_KHR_create_context"); @@ -581,6 +593,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, setAttrib(EGL_NONE, EGL_NONE); } +// The surface for EGLDevice backened is created in _glfwPlatformCreateWindow +// +#if !defined (_GLFW_EGLDEVICE) window->context.egl.surface = eglCreateWindowSurface(_glfw.egl.display, config, @@ -593,6 +608,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, getEGLErrorString(eglGetError())); return GLFW_FALSE; } +#endif window->context.egl.config = config; diff --git a/src/egl_context.h b/src/egl_context.h index bfab5111..b27cac96 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -47,6 +47,8 @@ typedef struct wl_egl_window* EGLNativeWindowType; #define EGLAPIENTRY typedef MirEGLNativeDisplayType EGLNativeDisplayType; typedef MirEGLNativeWindowType EGLNativeWindowType; +#elif defined(_GLFW_EGLDEVICE) + #include #else #error "No supported EGL platform selected" #endif diff --git a/src/egldevice_init.c b/src/egldevice_init.c new file mode 100644 index 00000000..6940573c --- /dev/null +++ b/src/egldevice_init.c @@ -0,0 +1,301 @@ +//======================================================================== +// GLFW 3.2 EGLDevice - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +// +// 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. +// +//======================================================================== + +#include "internal.h" + +#include +#include "egl_context.h" + +static GLFWbool initializeExtensions() +{ + _glfw.egldevice.eglQueryDevicesEXT = + (PFNEGLQUERYDEVICESEXTPROC) + _glfw.egl.GetProcAddress("eglQueryDevicesEXT"); + _glfw.egldevice.eglQueryDeviceStringEXT = + (PFNEGLQUERYDEVICESTRINGEXTPROC) + _glfw.egl.GetProcAddress("eglQueryDeviceStringEXT"); + _glfw.egldevice.eglGetPlatformDisplayEXT = + (PFNEGLGETPLATFORMDISPLAYEXTPROC) + _glfw.egl.GetProcAddress("eglGetPlatformDisplayEXT"); + _glfw.egldevice.eglGetOutputLayersEXT = + (PFNEGLGETOUTPUTLAYERSEXTPROC) + _glfw.egl.GetProcAddress("eglGetOutputLayersEXT"); + _glfw.egldevice.eglCreateStreamKHR = + (PFNEGLCREATESTREAMKHRPROC) + _glfw.egl.GetProcAddress("eglCreateStreamKHR"); + _glfw.egldevice.eglDestroyStreamKHR = + (PFNEGLDESTROYSTREAMKHRPROC) + _glfw.egl.GetProcAddress("eglDestroyStreamKHR"); + _glfw.egldevice.eglStreamConsumerOutputEXT = + (PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) + _glfw.egl.GetProcAddress("eglStreamConsumerOutputEXT"); + _glfw.egldevice.eglCreateStreamProducerSurfaceKHR = + (PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) + _glfw.egl.GetProcAddress("eglCreateStreamProducerSurfaceKHR"); + + if(!_glfw.egldevice.eglQueryDevicesEXT || + !_glfw.egldevice.eglQueryDeviceStringEXT || + !_glfw.egldevice.eglGetPlatformDisplayEXT || + !_glfw.egldevice.eglGetOutputLayersEXT || + !_glfw.egldevice.eglCreateStreamKHR || + !_glfw.egldevice.eglDestroyStreamKHR || + !_glfw.egldevice.eglStreamConsumerOutputEXT || + !_glfw.egldevice.eglCreateStreamProducerSurfaceKHR) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required function(s)"); + return GLFW_FALSE; + } + return GLFW_TRUE; +} + +static EGLDeviceEXT getEGLDevice(void) +{ + int i, num_devs; + EGLDeviceEXT* egl_devs, eglDevice; + const char *clientExtensionString; + + eglDevice = EGL_NO_DEVICE_EXT; + clientExtensionString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!_glfwStringInExtensionString("EGL_EXT_device_base", + clientExtensionString) && + (!_glfwStringInExtensionString("EGL_EXT_device_enumeration", + clientExtensionString) || + !_glfwStringInExtensionString("EGL_EXT_device_query", + clientExtensionString))) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: EGL_EXT_device base extensions not found"); + } + + if (!_glfw.egldevice.eglQueryDevicesEXT(0, NULL, &num_devs)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Falied to query EGLDevice"); + } + if (num_devs < 1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: No Devices Found"); + } + + egl_devs = calloc(sizeof(EGLDeviceEXT), num_devs); + if (egl_devs == NULL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to allocate memory for device storage"); + } + + // Select suitable device + if (!_glfw.egldevice.eglQueryDevicesEXT(num_devs, egl_devs, &num_devs)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Failed to query EGL devices"); + } + + for (i = 0; i <= num_devs; i++) + { + const char* deviceExtensionString; + + deviceExtensionString = + _glfw.egldevice.eglQueryDeviceStringEXT(egl_devs[i], EGL_EXTENSIONS); + if (_glfwStringInExtensionString("EGL_EXT_device_drm", + deviceExtensionString)) + { + eglDevice = egl_devs[i]; + break; + } + } + + free(egl_devs); + + if (eglDevice == EGL_NO_DEVICE_EXT) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_EXT_device_drm"); + } + return eglDevice; +} + +static int getDRMFd(EGLDeviceEXT eglDevice) +{ + int drm_fd; + const char* drmName; + + drmName = _glfw.egldevice.eglQueryDeviceStringEXT(eglDevice, + EGL_DRM_DEVICE_FILE_EXT); + if (!drmName || (strnlen(drmName, PATH_MAX) == 0)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Couldn't obtain device file from 0x%p", + (void*)(uintptr_t)eglDevice); + } + + drm_fd = drmOpen(drmName, NULL); + if (drm_fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Couldn't open device file '%s'", drmName); + } + + return drm_fd; +} + +static GLFWbool initEGLDisplay(EGLDeviceEXT egl_dev, int drm_fd) +{ + const char* displayExtensionString; + EGLint displayAttribs[] = { + EGL_DRM_MASTER_FD_EXT, + drm_fd, + EGL_NONE + }; + + _glfw.egl.display = + _glfw.egldevice.eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, + (void*)egl_dev, + displayAttribs); + if (_glfw.egl.display == EGL_NO_DISPLAY) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Couldn't obtain EGLDisplay for device"); + return GLFW_FALSE; + } + + if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to initialize EGL: %s", + eglGetError()); + + return GLFW_FALSE; + } + + // Check for stream_consumer_egloutput + output_drm support + displayExtensionString = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (!_glfwStringInExtensionString("EGL_EXT_output_base", + displayExtensionString)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_EXT_output_base"); + return GLFW_FALSE; + } + + if (!_glfwStringInExtensionString("EGL_EXT_output_drm", + displayExtensionString)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_EXT_output_drm"); + return GLFW_FALSE; + } + + if (!_glfwStringInExtensionString("EGL_KHR_stream", + displayExtensionString)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_KHR_stream"); + return GLFW_FALSE; + } + + if (!_glfwStringInExtensionString("EGL_KHR_stream_producer_eglsurface", + displayExtensionString)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_KHR_stream_producer_eglsurface"); + return GLFW_FALSE; + } + if (!_glfwStringInExtensionString("EGL_EXT_stream_consumer_egloutput", + displayExtensionString)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Missing required extension:" + " EGL_EXT_stream_consumer_egloutput"); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + EGLDeviceEXT egl_dev; + int drm_fd; + + if (!_glfwInitThreadLocalStoragePOSIX()) + return GLFW_FALSE; + + // Initialize EGL + if (!_glfwInitEGL()) + return GLFW_FALSE; + + // Initialize global data and extension function pointers + if (!initializeExtensions()) + return GLFW_FALSE; + + // Query and Obtain EGLDevice + egl_dev = getEGLDevice(); + + // Obtain and open DRM device file + drm_fd = getDRMFd(egl_dev); + + // Store for use later + _glfw.egldevice.drmFd = drm_fd; + + // Obtain EGLDisplay + if (!initEGLDisplay(egl_dev, drm_fd)) + return GLFW_FALSE; + + _glfwInitTimerPOSIX(); + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateEGL(); + _glfwTerminateJoysticksLinux(); + _glfwTerminateThreadLocalStoragePOSIX(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + return _GLFW_VERSION_NUMBER "EGLDEVICE" +#if defined(_GLFW_EGL) + " EGL" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; +} diff --git a/src/egldevice_monitor.c b/src/egldevice_monitor.c new file mode 100644 index 00000000..388b23db --- /dev/null +++ b/src/egldevice_monitor.c @@ -0,0 +1,177 @@ +//======================================================================== +// GLFW 3.2 EGLDevice - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +// +// 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. +// +//======================================================================== + +#include "internal.h" + +static GLFWbool pickConnector(_GLFWmonitor* monitor, int drm_fd, drmModeRes* res_info) +{ + int i, j; + + // Getting suitable connector, encoder and crtc + for (i = 0; i < res_info->count_connectors; i++) + { + monitor->egldevice.connId = res_info->connectors[i]; + + drmModeConnector* conn_info; + + conn_info = + drmModeGetConnector(drm_fd, monitor->egldevice.connId); + if (!conn_info) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to obtain info for connector (%d)", + monitor->egldevice.connId); + return GLFW_FALSE; + } + if (conn_info->connection == DRM_MODE_CONNECTED && + conn_info->count_modes > 0 && + conn_info->count_encoders > 0) + { + monitor->egldevice.encId = conn_info->encoders[0]; + + drmModeEncoder* enc_info; + + enc_info = + drmModeGetEncoder(drm_fd, monitor->egldevice.encId); + if (!enc_info) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to query DRM-KMS" + " information for connector index %d", i); + } + + // Select the modesize + monitor->currentMode.width = (int)conn_info->modes[0].hdisplay; + monitor->currentMode.height = (int)conn_info->modes[0].vdisplay; + monitor->currentMode.refreshRate = (int)conn_info->modes[0].vrefresh; + monitor->modeCount = (int)conn_info->count_modes; + monitor->name = conn_info->modes[0].name; + + for (j = 0; j < res_info->count_crtcs; j++) + { + if ((enc_info->possible_crtcs & (1 << j)) == 0) + continue; + + monitor->egldevice.crtcId = res_info->crtcs[j]; + monitor->egldevice.crtcIndex = j; + + if (res_info->crtcs[i] == enc_info->crtc_id) + break; + } + if (monitor->egldevice.crtcId == 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to select suitable CRTC"); + return GLFW_FALSE; + } + drmModeFreeEncoder(enc_info); + } + drmModeFreeConnector(conn_info); + } + return GLFW_TRUE; +} + +static GLFWbool initDRMResources(_GLFWmonitor* monitor, int drm_fd) +{ + drmModeRes* res_info; + + res_info = drmModeGetResources(drm_fd); + if (!res_info) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Couldn't obtain DRM-KMS resources"); + return GLFW_FALSE; + } + + if(!pickConnector(monitor, drm_fd, res_info)) + return GLFW_FALSE; + + drmModeFreeResources(res_info); + + return GLFW_TRUE; +} + +///////////////////////////////////////////////////////////////////////////// +/////////// GLFW platform API ////////////// +///////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + _GLFWmonitor** monitors; + _GLFWmonitor* monitor; + int monitorsCount = 1; + + monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*)); + monitor = calloc(1, sizeof(_GLFWmonitor)); + + *count = 1; + // Obtain DRM resource info + if (!initDRMResources(monitor, _glfw.egldevice.drmFd)) + return GLFW_FALSE; + + monitors[0] = monitor; + + return monitors; +} + +GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformIsSameMonitor not implemented"); + return 0; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetMonitorPos not implemented"); +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetVideoModes not implemented"); + *found = 0; + + return NULL; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetVideoMode not implemented"); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetGammaRamp not implemented"); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetGammaRamp not implemented"); +} diff --git a/src/egldevice_platform.h b/src/egldevice_platform.h new file mode 100644 index 00000000..39ce2852 --- /dev/null +++ b/src/egldevice_platform.h @@ -0,0 +1,119 @@ +//======================================================================== +// GLFW 3.2 EGLDevice - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +// +// 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. +// +//======================================================================== + +#ifndef _glfw3_egldevice_h_ +#define _glfw3_egldevice_h_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include "posix_time.h" +#include "linux_joystick.h" +#include "posix_tls.h" + +#include "egl_context.h" + +#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) +#define _glfw_dlclose(handle) dlclose(handle) +#define _glfw_dlsym(handle, name) dlsym(handle, name) + +#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY +#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType)window->egldevice.handle) + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowEgldevice egldevice +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryEgldevice egldevice +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorEgldevice egldevice +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorEgldevice egldevice + +#define _GLFW_PLATFORM_CONTEXT_STATE +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE + +// EGLDEVICE-specific per-window data +// +typedef struct _GLFWwindowEgldevice +{ + int xsurfsize, ysurfsize; + int xoffset, yoffset; + int fifo; + + uint32_t planeId; + + EGLDisplay handle; + EGLOutputLayerEXT eglLayer; + EGLStreamKHR eglStream; +} _GLFWwindowEgldevice; + +// EGLDEVICE-specific global data +// +typedef struct _GLFWlibraryEgldevice +{ + int drmFd; + + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT; + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT; + PFNEGLGETOUTPUTLAYERSEXTPROC eglGetOutputLayersEXT; + PFNEGLCREATESTREAMKHRPROC eglCreateStreamKHR; + PFNEGLDESTROYSTREAMKHRPROC eglDestroyStreamKHR; + PFNEGLSTREAMCONSUMEROUTPUTEXTPROC eglStreamConsumerOutputEXT; + PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC eglCreateStreamProducerSurfaceKHR; + PFNEGLSTREAMATTRIBKHRPROC eglStreamAttribKHR; + PFNEGLSTREAMCONSUMERACQUIREATTRIBEXTPROC eglStreamConsumerAcquireAttribEXT; +} _GLFWlibraryEgldevice; + +// EGLDEVICE-specific per-monitor data +// +typedef struct _GLFWmonitorEgldevice { + int crtcIndex; + uint32_t connId, encId, crtcId; +} _GLFWmonitorEgldevice; + +// EGLDEVICE-specific per-cursor data +// +typedef struct _GLFWcursorEgldevice { +} _GLFWcursorEgldevice; + +#endif // _glfw3_egldevice_platform_h_ diff --git a/src/egldevice_window.c b/src/egldevice_window.c new file mode 100644 index 00000000..71255df4 --- /dev/null +++ b/src/egldevice_window.c @@ -0,0 +1,396 @@ +//======================================================================== +// GLFW 3.2 EGLDevice - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +// +// 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. +// +//======================================================================== + +#include "internal.h" + +/////////////////////////////////////////////////////////////////////////// +//////// GLFW platform API ///////////// +/////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + int n; + _GLFWmonitor* monitor; + EGLAttrib layerAttribs[] = { EGL_NONE, EGL_NONE, EGL_NONE }; + EGLint streamAttribs[] = { EGL_STREAM_FIFO_LENGTH_KHR, + window->egldevice.fifo, EGL_NONE }; + EGLint surfaceAttribs[] = { EGL_WIDTH, 0, EGL_HEIGHT, 0, EGL_NONE }; + + if (window->monitor) + monitor = window->monitor; + else + monitor = _glfw.monitors[0]; + + window->egldevice.xsurfsize = wndconfig->width; + window->egldevice.ysurfsize = wndconfig->height; + + if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + + // Get the layer for this crtc/plane + layerAttribs[0] = EGL_DRM_CRTC_EXT; + layerAttribs[1] = (EGLAttrib)monitor->egldevice.crtcId; + + if (!_glfw.egldevice.eglGetOutputLayersEXT(_glfw.egl.display, layerAttribs, + &window->egldevice.eglLayer, + 1, &n) || !n) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to obtain EGLOutputLayer"); + return GLFW_FALSE; + } + + // Create a stream and connect to the output + window->egldevice.eglStream = + _glfw.egldevice.eglCreateStreamKHR(_glfw.egl.display, streamAttribs); + if (window->egldevice.eglStream == EGL_NO_STREAM_KHR) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to create stream (error 0x%x)", + eglGetError()); + return GLFW_FALSE; + } + if (!_glfw.egldevice.eglStreamConsumerOutputEXT(_glfw.egl.display, + window->egldevice.eglStream, + window->egldevice.eglLayer)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to connect stream (error 0x%x)", + eglGetError()); + return GLFW_FALSE; + } + + // Create a surface to feed the stream + surfaceAttribs[1] = window->egldevice.xsurfsize; + surfaceAttribs[3] = window->egldevice.ysurfsize; + window->context.egl.surface = + _glfw.egldevice.eglCreateStreamProducerSurfaceKHR(_glfw.egl.display, + window->context.egl.config, + window->egldevice.eglStream, + surfaceAttribs); + if (window->context.egl.surface == EGL_NO_SURFACE) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Unable to create rendering" + " surface (error 0x%x)", eglGetError()); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->context.client != GLFW_NO_API) + window->context.destroy(window); + + if (window->egldevice.eglStream != EGL_NO_STREAM_KHR) + { + _glfw.egldevice.eglDestroyStreamKHR(_glfw.egl.display, + window->egldevice.eglStream); + } +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowTitle is not supported"); +} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, + int count, const GLFWimage* images) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowIcon is not supported"); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + if (xpos) + *xpos = window->egldevice.xoffset; + if (ypos) + *ypos = window->egldevice.yoffset; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + window->egldevice.xoffset = xpos; + window->egldevice.yoffset = ypos; + + drmModeRes* res_info; + _GLFWmonitor* monitor; + + if (window->monitor) + monitor = window->monitor; + else + monitor = _glfw.monitors[0]; + + res_info = drmModeGetResources(_glfw.egldevice.drmFd); + if (drmModeSetCrtc(_glfw.egldevice.drmFd, + res_info->crtcs[monitor->egldevice.crtcIndex], + -1, window->egldevice.xoffset, window->egldevice.yoffset, + &res_info->connectors[monitor->egldevice.crtcIndex], 1, NULL)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: Setting window pos failed"); + } + drmModeFreeResources(res_info); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->egldevice.xsurfsize; + if (height) + *height = window->egldevice.ysurfsize; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowSize not implemented"); +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowSizeLimits not implemented"); +} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowAspectRatio not implemented"); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetWindowFrameSize not implemented"); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformIconifyWindow not implemented"); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformRestoreWindow not implemented"); +} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformMaximizeWindow not implemented"); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + return; +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformUnhideWindow not implemented"); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformHideWindow not implemented"); +} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) +{ + return; +} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetWindowMonitor not implemented"); +} +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWindowFocused not implemented"); + return GLFW_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWindowIconified not implemented"); + return GLFW_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWindowVisible not implemented"); + return GLFW_FALSE; +} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWindowMaximized not implemented"); + return 0; +} + +void _glfwPlatformPollEvents(void) +{ + return; +} + +void _glfwPlatformWaitEvents(void) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWaitEvents not supported"); +} + +void _glfwPlatformWaitEventsTimeout(double timeout) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformWaitEventsTimeout not supported"); +} + +void _glfwPlatformPostEmptyEvent(void) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformPostEmptyEvent not supported"); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetCursorPos not supported"); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetCursorPos not supported"); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetCursorMode not supported"); +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetKeyName not supported"); + return NULL; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformCreateCursor not supported"); + return GLFW_FALSE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformCreateStandardCursor not supported"); + return GLFW_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + return; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetCursor not supported"); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformSetClipboardString not supported"); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetClipboardString not supported"); + return NULL; +} + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetRequiredInstanceExtensions not supported"); + return NULL; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformGetPhysicalDevicePresentationSupport not supported"); + return 0; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGLDevice: _glfwPlatformCreateWindowSurface not supported"); + return (VkResult)NULL; +} diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index bc9f5d3e..9fbea75b 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -46,6 +46,8 @@ #cmakedefine _GLFW_MIR // Define this to 1 if building GLFW for OSMesa #cmakedefine _GLFW_OSMESA +// Define this to 1 if building GLFW for EGLDevice +#cmakedefine _GLFW_EGLDEVICE // Define this to 1 if building as a shared library / dynamic library / DLL #cmakedefine _GLFW_BUILD_DLL diff --git a/src/internal.h b/src/internal.h index a95d1f86..668fee08 100644 --- a/src/internal.h +++ b/src/internal.h @@ -190,6 +190,8 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); #include "mir_platform.h" #elif defined(_GLFW_OSMESA) #include "null_platform.h" +#elif defined(_GLFW_EGLDEVICE) + #include "egldevice_platform.h" #else #error "No supported window creation API selected" #endif