mirror of
https://github.com/glfw/glfw.git
synced 2026-09-20 16:30:45 +00:00
Add headless OSMesa backend
Allows creation and drawing to in-memory OpenGL contexts. This backend does not provide input. Related to #850.
This commit is contained in:
committed by
Camilla Berglund
parent
a90ee65f7b
commit
368fa9475d
@@ -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 //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user