diff --git a/CMake/modules/Findosmesa.cmake b/CMake/modules/Findosmesa.cmake new file mode 100644 index 00000000..3194bd91 --- /dev/null +++ b/CMake/modules/Findosmesa.cmake @@ -0,0 +1,18 @@ +# Try to find OSMesa on a Unix system +# +# This will define: +# +# OSMESA_LIBRARIES - Link these to use OSMesa +# OSMESA_INCLUDE_DIR - Include directory for OSMesa +# +# Copyright (c) 2014 Brandon Schaefer + +if (NOT WIN32) + + find_package (PkgConfig) + pkg_check_modules (PKG_OSMESA QUIET osmesa) + + set (OSMESA_INCLUDE_DIR ${PKG_OSMESA_INCLUDE_DIRS}) + set (OSMESA_LIBRARIES ${PKG_OSMESA_LIBRARIES}) + +endif () diff --git a/CMakeLists.txt b/CMakeLists.txt index 388a555f..8f623bcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ endif() if (UNIX AND NOT APPLE) option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) option(GLFW_USE_MIR "Use Mir for window creation" OFF) + option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF) endif() if (MSVC) @@ -154,6 +155,9 @@ elseif (UNIX) elseif (GLFW_USE_MIR) set(_GLFW_MIR 1) message(STATUS "Using Mir for window creation") + elseif (GLFW_USE_OSMESA) + set(_GLFW_OSMESA 1) + message(STATUS "Using OSMesa for windowless context creation") else() set(_GLFW_X11 1) message(STATUS "Using X11 for window creation") @@ -318,6 +322,18 @@ if (_GLFW_MIR) list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") endif() +#-------------------------------------------------------------------- +# Use OSMesa for offscreen context creation +#-------------------------------------------------------------------- +if (_GLFW_OSMESA) + find_package(osmesa REQUIRED) + list(APPEND glfw_PKG_DEPS "osmesa") + + list(APPEND glfw_INCLUDE_DIRS "${OSMESA_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${OSMESA_LIBRARIES}" + "${CMAKE_THREAD_LIBS_INIT}") +endif() + #-------------------------------------------------------------------- # Use Cocoa for window creation and NSOpenGL for context creation #-------------------------------------------------------------------- diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index cf0bc8ce..6c9b87ac 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -448,6 +448,30 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); #endif +#if defined(GLFW_EXPOSE_NATIVE_OSMESA) +/*! @brief Returns the color buffer associated with the specified window. + * + * @param[out] width The width of the color buffer. + * @param[out] height The height of the color buffer. + * @param[out] format The pixel format of the color buffer (OSMESA_FORMAT_*). + * @param[out] buffer The buffer data. + * @return 1 if successful, or 0 if not. + */ +GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, + int* height, int* format, void** buffer); + +/*! @brief Returns the depth buffer associated with the specified window. + * + * @param[out] width The width of the depth buffer. + * @param[out] height The height of the depth buffer. + * @param[out] bytesPerValue The number of bytes per depth buffer element. + * @param[out] buffer The buffer data. + * @return 1 if successful, or 0 if not. + */ +GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, + int* height, int* bytesPerValue, void** buffer); +#endif + #ifdef __cplusplus } #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5042aba3..dd50d8d7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -45,6 +45,12 @@ elseif (_GLFW_MIR) set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c egl_context.c) +elseif (_GLFW_OSMESA) + set(glfw_HEADERS ${common_HEADERS} osmesa_platform.h + posix_time.h posix_tls.h osmesa_context.h) + set(glfw_SOURCES ${common_SOURCES} osmesa_init.c osmesa_monitor.c + osmesa_window.c posix_time.c posix_tls.c + osmesa_context.c) endif() if (APPLE) diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index f709726f..153979f5 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -44,6 +44,8 @@ #cmakedefine _GLFW_WAYLAND // Define this to 1 if building GLFW for Mir #cmakedefine _GLFW_MIR +// Define this to 1 if building GLFW for OSMesa +#cmakedefine _GLFW_OSMESA // 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 3dc33691..f4ad122b 100644 --- a/src/internal.h +++ b/src/internal.h @@ -172,6 +172,8 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void); #include "wl_platform.h" #elif defined(_GLFW_MIR) #include "mir_platform.h" +#elif defined(_GLFW_OSMESA) + #include "osmesa_platform.h" #else #error "No supported window creation API selected" #endif diff --git a/src/osmesa_context.c b/src/osmesa_context.c new file mode 100644 index 00000000..a04a7dc1 --- /dev/null +++ b/src/osmesa_context.c @@ -0,0 +1,213 @@ + +#include +#include + +#include "internal.h" +#include "osmesa_context.h" + +static void makeContextCurrentOSMesa(_GLFWwindow* window) +{ + if (window) + { + // Check to see if we need to allocate a new buffer. + if ((window->context.osmesa.buffer == NULL) || + (window->osmesa.width != window->context.osmesa.width) || + (window->osmesa.height != window->context.osmesa.height)) + { + // Free the current buffer, if necessary. + if (window->context.osmesa.buffer != NULL) + { + free(window->context.osmesa.buffer); + } + + // Allocate the new buffer (width * height * 1 byte per RGBA + // channel). + window->context.osmesa.buffer = (unsigned char *) malloc( + window->osmesa.width * window->osmesa.height * 4); + + // Update the context size. + window->context.osmesa.width = window->osmesa.width; + window->context.osmesa.height = window->osmesa.height; + } + + // Make the context current. + if (!OSMesaMakeCurrent(window->context.osmesa.handle, + window->context.osmesa.buffer, + 0x1401, // GL_UNSIGNED_BYTE + window->osmesa.width, window->osmesa.height)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to make context current."); + return; + } + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Releasing the current context is not supported."); + } + + _glfwPlatformSetCurrentContext(window); +} + +static GLFWglproc getProcAddressOSMesa(const char* procname) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->context.osmesa.handle) + { + return (GLFWglproc) OSMesaGetProcAddress(procname); + } + + return NULL; +} + +static void destroyContextOSMesa(_GLFWwindow* window) +{ + if (window->context.osmesa.handle != NULL) + { + OSMesaDestroyContext(window->context.osmesa.handle); + window->context.osmesa.handle = NULL; + } + + if (window->context.osmesa.buffer != NULL) + { + free(window->context.osmesa.buffer); + window->context.osmesa.width = 0; + window->context.osmesa.height = 0; + } +} + +static void swapBuffersOSMesa(_GLFWwindow* window) {} + +static void swapIntervalOSMesa(int interval) {} + +static int extensionSupportedOSMesa() +{ + return GLFW_FALSE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWbool _glfwInitOSMesa(void) +{ + int i; + const char* sonames[] = + { +#if defined(_GLFW_WIN32) + "libOSMesa.dll", + "OSMesa.dll", +#elif defined(_GLFW_COCOA) + "libOSMesa.dylib", +#else + "libOSMesa.so.6", +#endif + NULL + }; + + if (_glfw.osmesa.handle) + return GLFW_TRUE; + + for (i = 0; sonames[i]; i++) + { + _glfw.osmesa.handle = _glfw_dlopen(sonames[i]); + if (_glfw.osmesa.handle) + break; + } + + if (!_glfw.osmesa.handle) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found"); + return GLFW_FALSE; + } + + _glfw.osmesa.prefix = (strncmp(sonames[i], "lib", 3) == 0); + + _glfw.osmesa.CreateContext = (PFNOSMESACREATECONTEXTPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContext"); + _glfw.osmesa.DestroyContext = (PFNOSMESADESTROYCONTEXTPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext"); + _glfw.osmesa.MakeCurrent = (PFNOSMESAMAKECURRENTPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent"); + _glfw.osmesa.GetCurrentContext = (PFNOSMESAGETCURRENTCONTEXTPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetCurrentContext"); + _glfw.osmesa.PixelStore = (PFNOSMESAPIXELSTOREPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaPixelStore"); + _glfw.osmesa.GetIntegerv = (PFNOSMESAGETINTEGERVPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetIntegerv"); + _glfw.osmesa.GetColorBuffer = (PFNOSMESAGETCOLORBUFFERPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer"); + _glfw.osmesa.GetDepthBuffer = (PFNOSMESAGETDEPTHBUFFERPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer"); + _glfw.osmesa.GetProcAddress = (PFNOSMESAGETPROCADDRESSPROC) + _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress"); + + if (!_glfw.osmesa.CreateContext || + !_glfw.osmesa.DestroyContext || + !_glfw.osmesa.MakeCurrent || + !_glfw.osmesa.GetCurrentContext || + !_glfw.osmesa.PixelStore || + !_glfw.osmesa.GetIntegerv || + !_glfw.osmesa.GetColorBuffer || + !_glfw.osmesa.GetDepthBuffer || + !_glfw.osmesa.GetProcAddress) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "OSMesa: Failed to load required entry points"); + + _glfwTerminateOSMesa(); + return GLFW_FALSE; + } + + return GLFW_TRUE; +} + +void _glfwTerminateOSMesa(void) +{ + if (_glfw.osmesa.handle) + { + _glfw_dlclose(_glfw.osmesa.handle); + _glfw.osmesa.handle = NULL; + } +} + +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + OSMesaContext share; + + if (ctxconfig->share) + share = ctxconfig->share->context.osmesa.handle; + + // Initialize the context. + window->context.osmesa.buffer = NULL; + window->context.osmesa.width = 0; + window->context.osmesa.height = 0; + + // Create to create an OSMesa context. + window->context.osmesa.handle = OSMesaCreateContext(OSMESA_RGBA, share); + if (window->context.osmesa.handle == 0) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "OSMesa: Failed to create context."); + return GLFW_FALSE; + } + + // Set up the context API. + window->context.makeCurrent = makeContextCurrentOSMesa; + window->context.swapBuffers = swapBuffersOSMesa; + window->context.swapInterval = swapIntervalOSMesa; + window->context.extensionSupported = extensionSupportedOSMesa; + window->context.getProcAddress = getProcAddressOSMesa; + window->context.destroy = destroyContextOSMesa; + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + diff --git a/src/osmesa_context.h b/src/osmesa_context.h new file mode 100644 index 00000000..2283cf74 --- /dev/null +++ b/src/osmesa_context.h @@ -0,0 +1,87 @@ + +#ifndef _glfw3_osmesa_context_h_ +#define _glfw3_osmesa_context_h_ + +#define OSMESA_COLOR_INDEX GL_COLOR_INDEX +#define OSMESA_RGBA 0x1908 +#define OSMESA_BGRA 0x1 +#define OSMESA_ARGB 0x2 +#define OSMESA_RGB 0x1907 +#define OSMESA_BGR 0x4 +#define OSMESA_RGB_565 0x5 + +#define OSMESA_ROW_LENGTH 0x10 +#define OSMESA_Y_UP 0x11 + +#define OSMESA_WIDTH 0x20 +#define OSMESA_HEIGHT 0x21 +#define OSMESA_FORMAT 0x22 +#define OSMESA_TYPE 0x23 +#define OSMESA_MAX_WIDTH 0x24 +#define OSMESA_MAX_HEIGHT 0x25 + +typedef void* OSMesaContext; +typedef void (*OSMESAproc)(); + +typedef OSMesaContext (* PFNOSMESACREATECONTEXTPROC)(GLenum, OSMesaContext); +typedef void (* PFNOSMESADESTROYCONTEXTPROC)(OSMesaContext); +typedef int (* PFNOSMESAMAKECURRENTPROC)(OSMesaContext, void*, int, int, int); +typedef OSMesaContext (* PFNOSMESAGETCURRENTCONTEXTPROC)(); +typedef void (* PFNOSMESAPIXELSTOREPROC)(int, int); +typedef void (* PFNOSMESAGETINTEGERVPROC)(int, int*); +typedef int (* PFNOSMESAGETCOLORBUFFERPROC)(OSMesaContext, int*, int*, int*, void**); +typedef int (* PFNOSMESAGETDEPTHBUFFERPROC)(OSMesaContext, int*, int*, int*, void**); +typedef GLFWglproc (* PFNOSMESAGETPROCADDRESSPROC)(const char*); +#define OSMesaCreateContext _glfw.osmesa.CreateContext +#define OSMesaDestroyContext _glfw.osmesa.DestroyContext +#define OSMesaMakeCurrent _glfw.osmesa.MakeCurrent +#define OSMesaGetCurrentContext _glfw.osmesa.GetCurrentContext +#define OSMesaPixelStore _glfw.osmesa.PixelStore +#define OSMesaGetIntegerv _glfw.osmesa.GetIntegerv +#define OSMesaGetColorBuffer _glfw.osmesa.GetColorBuffer +#define OSMesaGetDepthBuffer _glfw.osmesa.GetDepthBuffer +#define OSMesaGetProcAddress _glfw.osmesa.GetProcAddress + +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextOSMesa osmesa +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWctxlibraryOSMesa osmesa + + +// OSMesa-specific per-context data +// +typedef struct _GLFWcontextOSMesa +{ + OSMesaContext handle; + int width; + int height; + void * buffer; + +} _GLFWcontextOSMesa; + +// OSMesa-specific global data +// +typedef struct _GLFWctxlibraryOSMesa +{ + GLFWbool prefix; + + void* handle; + + PFNOSMESACREATECONTEXTPROC CreateContext; + PFNOSMESADESTROYCONTEXTPROC DestroyContext; + PFNOSMESAMAKECURRENTPROC MakeCurrent; + PFNOSMESAGETCURRENTCONTEXTPROC GetCurrentContext; + PFNOSMESAPIXELSTOREPROC PixelStore; + PFNOSMESAGETINTEGERVPROC GetIntegerv; + PFNOSMESAGETCOLORBUFFERPROC GetColorBuffer; + PFNOSMESAGETDEPTHBUFFERPROC GetDepthBuffer; + PFNOSMESAGETPROCADDRESSPROC GetProcAddress; + +} _GLFWctxlibraryOSMesa; + + +GLFWbool _glfwInitOSMesa(void); +void _glfwTerminateOSMesa(void); +GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + +#endif // _glfw3_osmesa_context_h_ diff --git a/src/osmesa_init.c b/src/osmesa_init.c new file mode 100644 index 00000000..46f2458d --- /dev/null +++ b/src/osmesa_init.c @@ -0,0 +1,35 @@ + +#include "internal.h" + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + if (!_glfwInitThreadLocalStoragePOSIX()) { + return GLFW_FALSE; + } + + _glfwInitTimerPOSIX(); + + return GLFW_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateOSMesa(); + _glfwTerminateThreadLocalStoragePOSIX(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_NUMBER " OSMESA"; + return version; +} + diff --git a/src/osmesa_monitor.c b/src/osmesa_monitor.c new file mode 100644 index 00000000..fb9ede25 --- /dev/null +++ b/src/osmesa_monitor.c @@ -0,0 +1,43 @@ + +#include "internal.h" + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + // OSMesa is headless, so no monitors. + _GLFWmonitor** monitors = NULL; + if (count != NULL) { + *count = 0; + } + return monitors; +} + +int _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return GLFW_FALSE; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) {} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + return NULL; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) {} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) {} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, + const GLFWgammaramp* ramp) {} + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// diff --git a/src/osmesa_platform.h b/src/osmesa_platform.h new file mode 100644 index 00000000..f5e114e3 --- /dev/null +++ b/src/osmesa_platform.h @@ -0,0 +1,61 @@ + +#ifndef _osmesa_platform_h_ +#define _osmesa_platform_h_ + +#include + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowOSMesa osmesa +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorOSMesa osmesa +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorOSMesa osmesa + +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWwinlibraryOSMesa osmesawin + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE +#define _GLFW_EGL_CONTEXT_STATE +#define _GLFW_EGL_LIBRARY_CONTEXT_STATE + +#include "osmesa_context.h" +#include "posix_time.h" +#include "posix_tls.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) + +// TODO(dalyj) "PLACEHOLDER" variables are there to silence "empty struct" +// warnings + +// OSMesa-specific per-window data +// +typedef struct _GLFWwindowOSMesa +{ + int width; + int height; +} _GLFWwindowOSMesa; + + +// OSMesa-specific global data +// +typedef struct _GLFWwinlibraryOSMesa +{ + int PLACEHOLDER; +} _GLFWwinlibraryOSMesa; + + +// OSMesa-specific per-monitor data +// +typedef struct _GLFWmonitorOSMesa +{ + int PLACEHOLDER; +} _GLFWmonitorOSMesa; + + +// OSMesa-specific per-cursor data +// +typedef struct _GLFWcursorOSMesa +{ + int PLACEHOLDER; +} _GLFWcursorOSMesa; + + +#endif // _osmesa_platform_h_ diff --git a/src/osmesa_window.c b/src/osmesa_window.c new file mode 100644 index 00000000..c171d629 --- /dev/null +++ b/src/osmesa_window.c @@ -0,0 +1,259 @@ + +#include "internal.h" + +#include + +int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) +{ + window->osmesa.width = wndconfig->width; + window->osmesa.height = wndconfig->height; + + return GLFW_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!_glfwInitOSMesa()) + return GLFW_FALSE; + + if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) + return GLFW_FALSE; + + if (!createWindow(window, wndconfig)) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->context.destroy) + window->context.destroy(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) {} + +void _glfwPlatformSetWindowIcon(_GLFWwindow* window, int count, + const GLFWimage* images) {} + +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) {} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + if (xpos != NULL) *xpos = 0; + if (ypos != NULL) *ypos = 0; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) {} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width != NULL) *width = window->osmesa.width; + if (height != NULL) *height = window->osmesa.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + window->osmesa.width = width; + window->osmesa.height = height; +} + +void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, + int minwidth, int minheight, + int maxwidth, int maxheight) {} + +void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int n, int d) {} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, + int* height) +{ + if (width != NULL) *width = window->osmesa.width; + if (height != NULL) *height = window->osmesa.height; +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, + int* right, int* bottom) +{ + if (left != NULL) *left = 0; + if (top != NULL) *top = 0; + if (right != NULL) *right = window->osmesa.width; + if (bottom != NULL) *top = window->osmesa.height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) {} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) {} + +void _glfwPlatformMaximizeWindow(_GLFWwindow* window) {} + +int _glfwPlatformWindowMaximized(_GLFWwindow* window) { + return 0; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) {} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) {} + +void _glfwPlatformHideWindow(_GLFWwindow* window) {} + +void _glfwPlatformFocusWindow(_GLFWwindow* window) {} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) { return GLFW_FALSE; } + +int _glfwPlatformWindowIconified(_GLFWwindow* window) { return GLFW_FALSE; } + +int _glfwPlatformWindowVisible(_GLFWwindow* window) { return GLFW_FALSE; } + +void _glfwPlatformPollEvents(void) {} + +void _glfwPlatformWaitEvents(void) {} + +void _glfwPlatformWaitEventsTimeout(double timeout) {} + +void _glfwPlatformPostEmptyEvent(void) {} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) { + if (xpos != NULL) *xpos = 0; + if (ypos != NULL) *ypos = 0; +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) {} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) {} + +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) {} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, + int xhot, int yhot) +{ + return GLFW_FALSE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + return GLFW_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) {} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) {} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) {} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + return NULL; +} + +const char* _glfwPlatformGetKeyName(int key, int scancode) { return ""; } + +int _glfwPlatformJoystickPresent(int joy) { return 0; } + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + if (count != NULL) *count = 0; + return NULL; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + if (count != NULL) *count = 0; + return NULL; +} + +const char* _glfwPlatformGetJoystickName(int joy) { return NULL; } + +char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count) +{ + if (count != NULL) *count = 0; + return NULL; +} + +int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance, + VkPhysicalDevice device, + uint32_t queuefamily) +{ + return GLFW_FALSE; +} + +VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) +{ + // This seems like the most appropriate error to return here. + return VK_ERROR_INITIALIZATION_FAILED; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, + int* height, int* format, void** buffer) +{ + GLint mesaWidth; + GLint mesaHeight; + GLint mesaFormat; + void* mesaBuffer; + + assert(window != NULL); + + OSMesaContext ctx = ((_GLFWwindow*) window)->context.osmesa.handle; + + // Query OSMesa for the color buffer data. + int result = OSMesaGetColorBuffer( + ctx, &mesaWidth, &mesaHeight, &mesaFormat, &mesaBuffer); + if (result) { + // Copy the values returned by OSMesa. + if (width != NULL) *width = mesaWidth; + if (height != NULL) *height = mesaHeight; + if (format != NULL) *format = mesaFormat; + if (buffer != NULL) *buffer = mesaBuffer; + } + + return result; +} + +GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, + int* height, int* bytesPerValue, + void** buffer) +{ + GLint mesaWidth; + GLint mesaHeight; + GLint mesaBytes; + void* mesaBuffer; + + assert(window != NULL); + + OSMesaContext ctx = ((_GLFWwindow*) window)->context.osmesa.handle; + + // Query OSMesa for the color buffer data. + int result = OSMesaGetDepthBuffer( + ctx, &mesaWidth, &mesaHeight, &mesaBytes, &mesaBuffer); + if (result) { + // Copy the values returned by OSMesa. + if (width != NULL) *width = mesaWidth; + if (height != NULL) *height = mesaHeight; + if (bytesPerValue != NULL) *bytesPerValue = mesaBytes; + if (buffer != NULL) *buffer = mesaBuffer; + } + + return result; +} +