OSMesa backend for GLFW. Allows creation and drawing to in-memory OpenGL

contexts.

Two examples (simple and particles) are modified to draw to OSMesa
contexts for a while, and then dump the framebuffer to an image file.
This commit is contained in:
Jason Daly 2016-08-30 15:53:19 -07:00
parent 2e6a110181
commit 6be8aee836
15 changed files with 2100 additions and 0 deletions

View File

@ -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 <brandon.schaefer@canonical.com>
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 ()

View File

@ -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)
@ -145,6 +146,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")
@ -306,6 +310,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
#--------------------------------------------------------------------

View File

@ -35,8 +35,16 @@ add_executable(particles WIN32 MACOSX_BUNDLE particles.c ${ICON} ${TINYCTHREAD}
add_executable(simple WIN32 MACOSX_BUNDLE simple.c ${ICON} ${GLAD})
add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD})
add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD})
if (GLFW_USE_OSMESA)
add_executable(simple_osmesa WIN32 MACOSX_BUNDLE simple_osmesa.c ${ICON} ${GLAD})
add_executable(particles_osmesa WIN32 MACOSX_BUNDLE particles_osmesa.c ${ICON} ${TINYCTHREAD} ${GETOPT} ${GLAD})
endif()
target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
if (GLFW_USE_OSMESA)
target_link_libraries(particles_osmesa "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
endif()
set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave)

1117
examples/particles_osmesa.c Normal file

File diff suppressed because it is too large Load Diff

209
examples/simple_osmesa.c Normal file
View File

@ -0,0 +1,209 @@
//========================================================================
// Simple GLFW example
// Copyright (c) Camilla Berglund <elmindreda@glfw.org>
//
// 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.
//
//========================================================================
//! [code]
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "linmath.h"
#include <stdlib.h>
#include <stdio.h>
static const struct
{
float x, y;
float r, g, b;
} vertices[3] =
{
{ -0.6f, -0.4f, 1.f, 0.f, 0.f },
{ 0.6f, -0.4f, 0.f, 1.f, 0.f },
{ 0.f, 0.6f, 0.f, 0.f, 1.f }
};
static const char* vertex_shader_text =
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
// Dumps the window's color buffer in ImageMagick .miff format.
void dumpFramebuffer(GLFWwindow* window)
{
// Switch to the given context.
GLFWwindow* old = glfwGetCurrentContext();
glfwMakeContextCurrent(window);
// Fetch the framebuffer.
int width;
int height;
void* buffer;
glfwGetFramebufferSize(window, &width, &height);
buffer = malloc(width * height * 4);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// Write to an ImageMagick .miff file.
FILE *fp = fopen("simple.miff", "w");
fprintf(fp, "id=ImageMagick version=1.0\n");
fprintf(fp, "class=DirectClass matte=True\n");
fprintf(fp, "columns=%d rows=%d\n", width, height);
fprintf(fp, "\f\n:\032");
void* ptr;
for (ptr = buffer + (height - 1) * width * 4;
ptr >= buffer;
ptr -= width * 4)
{
fwrite(ptr, 1, width * 4, fp);
}
fclose(fp);
printf("Wrote simple.miff!\n");
// Toss the buffer.
free(buffer);
// Restore the original context.
glfwMakeContextCurrent(old);
}
int main(void)
{
GLFWwindow* window;
GLuint vertex_buffer, vertex_shader, fragment_shader, program;
GLint mvp_location, vpos_location, vcol_location;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
glfwSwapInterval(1);
// NOTE: OpenGL error checks have been omitted for brevity
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
mvp_location = glGetUniformLocation(program, "MVP");
vpos_location = glGetAttribLocation(program, "vPos");
vcol_location = glGetAttribLocation(program, "vCol");
glEnableVertexAttribArray(vpos_location);
glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
sizeof(float) * 5, (void*) 0);
glEnableVertexAttribArray(vcol_location);
glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
sizeof(float) * 5, (void*) (sizeof(float) * 2));
int snap = 5;
while (!glfwWindowShouldClose(window))
{
float ratio;
int width, height;
mat4x4 m, p, mvp;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
mat4x4_identity(m);
mat4x4_rotate_Z(m, m, (float) glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m);
glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
if (--snap == 0)
{
dumpFramebuffer(window);
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
//! [code]

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -171,6 +171,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
src/osmesa_context.c Normal file
View File

@ -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
src/osmesa_context.h Normal file
View File

@ -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
src/osmesa_init.c Normal file
View File

@ -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
src/osmesa_monitor.c Normal file
View File

@ -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
src/osmesa_platform.h Normal file
View File

@ -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
src/osmesa_window.c Normal file
View File

@ -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;
}