1 //========================================================================
2 // GLFW 3.4 OSMesa - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2016 Google Inc.
5 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
15 // 1. The origin of this software must not be misrepresented; you must not
16 // claim that you wrote the original software. If you use this software
17 // in a product, an acknowledgment in the product documentation would
18 // be appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
26 //========================================================================
27 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
37 static void makeContextCurrentOSMesa(_GLFWwindow* window)
42 _glfwPlatformGetFramebufferSize(window, &width, &height);
44 // Check to see if we need to allocate a new buffer
45 if ((window->context.osmesa.buffer == NULL) ||
46 (width != window->context.osmesa.width) ||
47 (height != window->context.osmesa.height))
49 free(window->context.osmesa.buffer);
51 // Allocate the new buffer (width * height * 8-bit RGBA)
52 window->context.osmesa.buffer = calloc(4, (size_t) width * height);
53 window->context.osmesa.width = width;
54 window->context.osmesa.height = height;
57 if (!OSMesaMakeCurrent(window->context.osmesa.handle,
58 window->context.osmesa.buffer,
62 _glfwInputError(GLFW_PLATFORM_ERROR,
63 "OSMesa: Failed to make context current");
68 _glfwPlatformSetTls(&_glfw.contextSlot, window);
71 static GLFWglproc getProcAddressOSMesa(const char* procname)
73 return (GLFWglproc) OSMesaGetProcAddress(procname);
76 static void destroyContextOSMesa(_GLFWwindow* window)
78 if (window->context.osmesa.handle)
80 OSMesaDestroyContext(window->context.osmesa.handle);
81 window->context.osmesa.handle = NULL;
84 if (window->context.osmesa.buffer)
86 free(window->context.osmesa.buffer);
87 window->context.osmesa.width = 0;
88 window->context.osmesa.height = 0;
92 static void swapBuffersOSMesa(_GLFWwindow* window)
94 // No double buffering on OSMesa
97 static void swapIntervalOSMesa(int interval)
99 // No swap interval on OSMesa
102 static int extensionSupportedOSMesa(const char* extension)
104 // OSMesa does not have extensions
109 //////////////////////////////////////////////////////////////////////////
110 ////// GLFW internal API //////
111 //////////////////////////////////////////////////////////////////////////
113 GLFWbool _glfwInitOSMesa(void)
116 const char* sonames[] =
118 #if defined(_GLFW_OSMESA_LIBRARY)
119 _GLFW_OSMESA_LIBRARY,
120 #elif defined(_WIN32)
123 #elif defined(__APPLE__)
125 #elif defined(__CYGWIN__)
134 if (_glfw.osmesa.handle)
137 for (i = 0; sonames[i]; i++)
139 _glfw.osmesa.handle = _glfw_dlopen(sonames[i]);
140 if (_glfw.osmesa.handle)
144 if (!_glfw.osmesa.handle)
146 _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
150 _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
151 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
152 _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
153 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
154 _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
155 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
156 _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
157 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
158 _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
159 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
160 _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
161 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
162 _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
163 _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");
165 if (!_glfw.osmesa.CreateContextExt ||
166 !_glfw.osmesa.DestroyContext ||
167 !_glfw.osmesa.MakeCurrent ||
168 !_glfw.osmesa.GetColorBuffer ||
169 !_glfw.osmesa.GetDepthBuffer ||
170 !_glfw.osmesa.GetProcAddress)
172 _glfwInputError(GLFW_PLATFORM_ERROR,
173 "OSMesa: Failed to load required entry points");
175 _glfwTerminateOSMesa();
182 void _glfwTerminateOSMesa(void)
184 if (_glfw.osmesa.handle)
186 _glfw_dlclose(_glfw.osmesa.handle);
187 _glfw.osmesa.handle = NULL;
191 #define setAttrib(a, v) \
193 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
194 attribs[index++] = a; \
195 attribs[index++] = v; \
198 GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
199 const _GLFWctxconfig* ctxconfig,
200 const _GLFWfbconfig* fbconfig)
202 OSMesaContext share = NULL;
203 const int accumBits = fbconfig->accumRedBits +
204 fbconfig->accumGreenBits +
205 fbconfig->accumBlueBits +
206 fbconfig->accumAlphaBits;
208 if (ctxconfig->client == GLFW_OPENGL_ES_API)
210 _glfwInputError(GLFW_API_UNAVAILABLE,
211 "OSMesa: OpenGL ES is not available on OSMesa");
215 if (ctxconfig->share)
216 share = ctxconfig->share->context.osmesa.handle;
218 if (OSMesaCreateContextAttribs)
220 int index = 0, attribs[40];
222 setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
223 setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
224 setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
225 setAttrib(OSMESA_ACCUM_BITS, accumBits);
227 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
229 setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
231 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
233 setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
236 if (ctxconfig->major != 1 || ctxconfig->minor != 0)
238 setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
239 setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
242 if (ctxconfig->forward)
244 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
245 "OSMesa: Forward-compatible contexts not supported");
251 window->context.osmesa.handle =
252 OSMesaCreateContextAttribs(attribs, share);
256 if (ctxconfig->profile)
258 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
259 "OSMesa: OpenGL profiles unavailable");
263 window->context.osmesa.handle =
264 OSMesaCreateContextExt(OSMESA_RGBA,
266 fbconfig->stencilBits,
271 if (window->context.osmesa.handle == NULL)
273 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
274 "OSMesa: Failed to create context");
278 window->context.makeCurrent = makeContextCurrentOSMesa;
279 window->context.swapBuffers = swapBuffersOSMesa;
280 window->context.swapInterval = swapIntervalOSMesa;
281 window->context.extensionSupported = extensionSupportedOSMesa;
282 window->context.getProcAddress = getProcAddressOSMesa;
283 window->context.destroy = destroyContextOSMesa;
291 //////////////////////////////////////////////////////////////////////////
292 ////// GLFW native API //////
293 //////////////////////////////////////////////////////////////////////////
295 GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
296 int* height, int* format, void** buffer)
299 GLint mesaWidth, mesaHeight, mesaFormat;
300 _GLFWwindow* window = (_GLFWwindow*) handle;
301 assert(window != NULL);
303 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
305 if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
306 &mesaWidth, &mesaHeight,
307 &mesaFormat, &mesaBuffer))
309 _glfwInputError(GLFW_PLATFORM_ERROR,
310 "OSMesa: Failed to retrieve color buffer");
317 *height = mesaHeight;
319 *format = mesaFormat;
321 *buffer = mesaBuffer;
326 GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
327 int* width, int* height,
332 GLint mesaWidth, mesaHeight, mesaBytes;
333 _GLFWwindow* window = (_GLFWwindow*) handle;
334 assert(window != NULL);
336 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
338 if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
339 &mesaWidth, &mesaHeight,
340 &mesaBytes, &mesaBuffer))
342 _glfwInputError(GLFW_PLATFORM_ERROR,
343 "OSMesa: Failed to retrieve depth buffer");
350 *height = mesaHeight;
352 *bytesPerValue = mesaBytes;
354 *buffer = mesaBuffer;
359 GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
361 _GLFWwindow* window = (_GLFWwindow*) handle;
362 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
364 if (window->context.client == GLFW_NO_API)
366 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
370 return window->context.osmesa.handle;