瀏覽代碼

Add headless OSMesa backend

Allows creation and drawing to in-memory OpenGL contexts.

This backend does not provide input.

Related to #850.
Jason Daly 9 年之前
父節點
當前提交
368fa9475d

+ 18 - 0
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 <[email protected]>
+
+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 ()

+ 16 - 0
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
 #--------------------------------------------------------------------

+ 24 - 0
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

+ 6 - 0
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)

+ 2 - 0
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

+ 2 - 0
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

+ 213 - 0
src/osmesa_context.c

@@ -0,0 +1,213 @@
+
+#include <stdlib.h>
+#include <string.h>
+
+#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                       //////
+//////////////////////////////////////////////////////////////////////////
+

+ 87 - 0
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_

+ 35 - 0
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;
+}
+

+ 43 - 0
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                       //////
+//////////////////////////////////////////////////////////////////////////

+ 61 - 0
src/osmesa_platform.h

@@ -0,0 +1,61 @@
+
+#ifndef _osmesa_platform_h_
+#define _osmesa_platform_h_
+
+#include <dlfcn.h>
+
+#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_

+ 259 - 0
src/osmesa_window.c

@@ -0,0 +1,259 @@
+
+#include "internal.h"
+
+#include <assert.h>
+
+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;
+}
+