• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.5 OSMesa - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2016 Google Inc.
5 // Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
6 //
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.
10 //
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:
14 //
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.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 //    be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 //    distribution.
25 //
26 //========================================================================
27 
28 #include "internal.h"
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 
makeContextCurrentOSMesa(_GLFWwindow * window)34 static void makeContextCurrentOSMesa(_GLFWwindow* window)
35 {
36     if (window)
37     {
38         int width, height;
39         _glfw.platform.getFramebufferSize(window, &width, &height);
40 
41         // Check to see if we need to allocate a new buffer
42         if ((window->context.osmesa.buffer == NULL) ||
43             (width != window->context.osmesa.width) ||
44             (height != window->context.osmesa.height))
45         {
46             _glfw_free(window->context.osmesa.buffer);
47 
48             // Allocate the new buffer (width * height * 8-bit RGBA)
49             window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height);
50             window->context.osmesa.width  = width;
51             window->context.osmesa.height = height;
52         }
53 
54         if (!OSMesaMakeCurrent(window->context.osmesa.handle,
55                                window->context.osmesa.buffer,
56                                GL_UNSIGNED_BYTE,
57                                width, height))
58         {
59             _glfwInputError(GLFW_PLATFORM_ERROR,
60                             "OSMesa: Failed to make context current");
61             return;
62         }
63     }
64 
65     _glfwPlatformSetTls(&_glfw.contextSlot, window);
66 }
67 
getProcAddressOSMesa(const char * procname)68 static GLFWglproc getProcAddressOSMesa(const char* procname)
69 {
70     return (GLFWglproc) OSMesaGetProcAddress(procname);
71 }
72 
destroyContextOSMesa(_GLFWwindow * window)73 static void destroyContextOSMesa(_GLFWwindow* window)
74 {
75     if (window->context.osmesa.handle)
76     {
77         OSMesaDestroyContext(window->context.osmesa.handle);
78         window->context.osmesa.handle = NULL;
79     }
80 
81     if (window->context.osmesa.buffer)
82     {
83         _glfw_free(window->context.osmesa.buffer);
84         window->context.osmesa.width = 0;
85         window->context.osmesa.height = 0;
86     }
87 }
88 
swapBuffersOSMesa(_GLFWwindow * window)89 static void swapBuffersOSMesa(_GLFWwindow* window)
90 {
91     // No double buffering on OSMesa
92 }
93 
swapIntervalOSMesa(int interval)94 static void swapIntervalOSMesa(int interval)
95 {
96     // No swap interval on OSMesa
97 }
98 
extensionSupportedOSMesa(const char * extension)99 static int extensionSupportedOSMesa(const char* extension)
100 {
101     // OSMesa does not have extensions
102     return GLFW_FALSE;
103 }
104 
105 
106 //////////////////////////////////////////////////////////////////////////
107 //////                       GLFW internal API                      //////
108 //////////////////////////////////////////////////////////////////////////
109 
_glfwInitOSMesa(void)110 GLFWbool _glfwInitOSMesa(void)
111 {
112     int i;
113     const char* sonames[] =
114     {
115 #if defined(_GLFW_OSMESA_LIBRARY)
116         _GLFW_OSMESA_LIBRARY,
117 #elif defined(_WIN32)
118         "libOSMesa.dll",
119         "OSMesa.dll",
120 #elif defined(__APPLE__)
121         "libOSMesa.8.dylib",
122 #elif defined(__CYGWIN__)
123         "libOSMesa-8.so",
124 #elif defined(__OpenBSD__) || defined(__NetBSD__)
125         "libOSMesa.so",
126 #else
127         "libOSMesa.so.8",
128         "libOSMesa.so.6",
129 #endif
130         NULL
131     };
132 
133     if (_glfw.osmesa.handle)
134         return GLFW_TRUE;
135 
136     for (i = 0;  sonames[i];  i++)
137     {
138         _glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]);
139         if (_glfw.osmesa.handle)
140             break;
141     }
142 
143     if (!_glfw.osmesa.handle)
144     {
145         _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
146         return GLFW_FALSE;
147     }
148 
149     _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
150         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt");
151     _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
152         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
153     _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
154         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext");
155     _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
156         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent");
157     _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
158         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
159     _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
160         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
161     _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
162         _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress");
163 
164     if (!_glfw.osmesa.CreateContextExt ||
165         !_glfw.osmesa.DestroyContext ||
166         !_glfw.osmesa.MakeCurrent ||
167         !_glfw.osmesa.GetColorBuffer ||
168         !_glfw.osmesa.GetDepthBuffer ||
169         !_glfw.osmesa.GetProcAddress)
170     {
171         _glfwInputError(GLFW_PLATFORM_ERROR,
172                         "OSMesa: Failed to load required entry points");
173 
174         _glfwTerminateOSMesa();
175         return GLFW_FALSE;
176     }
177 
178     return GLFW_TRUE;
179 }
180 
_glfwTerminateOSMesa(void)181 void _glfwTerminateOSMesa(void)
182 {
183     if (_glfw.osmesa.handle)
184     {
185         _glfwPlatformFreeModule(_glfw.osmesa.handle);
186         _glfw.osmesa.handle = NULL;
187     }
188 }
189 
190 #define SET_ATTRIB(a, v) \
191 { \
192     assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
193     attribs[index++] = a; \
194     attribs[index++] = v; \
195 }
196 
_glfwCreateContextOSMesa(_GLFWwindow * window,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)197 GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
198                                   const _GLFWctxconfig* ctxconfig,
199                                   const _GLFWfbconfig* fbconfig)
200 {
201     OSMesaContext share = NULL;
202     const int accumBits = fbconfig->accumRedBits +
203                           fbconfig->accumGreenBits +
204                           fbconfig->accumBlueBits +
205                           fbconfig->accumAlphaBits;
206 
207     if (ctxconfig->client == GLFW_OPENGL_ES_API)
208     {
209         _glfwInputError(GLFW_API_UNAVAILABLE,
210                         "OSMesa: OpenGL ES is not available on OSMesa");
211         return GLFW_FALSE;
212     }
213 
214     if (ctxconfig->share)
215         share = ctxconfig->share->context.osmesa.handle;
216 
217     if (OSMesaCreateContextAttribs)
218     {
219         int index = 0, attribs[40];
220 
221         SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA);
222         SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits);
223         SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
224         SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits);
225 
226         if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
227         {
228             SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
229         }
230         else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
231         {
232             SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
233         }
234 
235         if (ctxconfig->major != 1 || ctxconfig->minor != 0)
236         {
237             SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
238             SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
239         }
240 
241         if (ctxconfig->forward)
242         {
243             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
244                             "OSMesa: Forward-compatible contexts not supported");
245             return GLFW_FALSE;
246         }
247 
248         SET_ATTRIB(0, 0);
249 
250         window->context.osmesa.handle =
251             OSMesaCreateContextAttribs(attribs, share);
252     }
253     else
254     {
255         if (ctxconfig->profile)
256         {
257             _glfwInputError(GLFW_VERSION_UNAVAILABLE,
258                             "OSMesa: OpenGL profiles unavailable");
259             return GLFW_FALSE;
260         }
261 
262         window->context.osmesa.handle =
263             OSMesaCreateContextExt(OSMESA_RGBA,
264                                    fbconfig->depthBits,
265                                    fbconfig->stencilBits,
266                                    accumBits,
267                                    share);
268     }
269 
270     if (window->context.osmesa.handle == NULL)
271     {
272         _glfwInputError(GLFW_VERSION_UNAVAILABLE,
273                         "OSMesa: Failed to create context");
274         return GLFW_FALSE;
275     }
276 
277     window->context.makeCurrent = makeContextCurrentOSMesa;
278     window->context.swapBuffers = swapBuffersOSMesa;
279     window->context.swapInterval = swapIntervalOSMesa;
280     window->context.extensionSupported = extensionSupportedOSMesa;
281     window->context.getProcAddress = getProcAddressOSMesa;
282     window->context.destroy = destroyContextOSMesa;
283 
284     return GLFW_TRUE;
285 }
286 
287 #undef SET_ATTRIB
288 
289 
290 //////////////////////////////////////////////////////////////////////////
291 //////                        GLFW native API                       //////
292 //////////////////////////////////////////////////////////////////////////
293 
glfwGetOSMesaColorBuffer(GLFWwindow * handle,int * width,int * height,int * format,void ** buffer)294 GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
295                                      int* height, int* format, void** buffer)
296 {
297     void* mesaBuffer;
298     GLint mesaWidth, mesaHeight, mesaFormat;
299 
300     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
301 
302     _GLFWwindow* window = (_GLFWwindow*) handle;
303     assert(window != NULL);
304 
305     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
306     {
307         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
308         return GLFW_FALSE;
309     }
310 
311     if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
312                               &mesaWidth, &mesaHeight,
313                               &mesaFormat, &mesaBuffer))
314     {
315         _glfwInputError(GLFW_PLATFORM_ERROR,
316                         "OSMesa: Failed to retrieve color buffer");
317         return GLFW_FALSE;
318     }
319 
320     if (width)
321         *width = mesaWidth;
322     if (height)
323         *height = mesaHeight;
324     if (format)
325         *format = mesaFormat;
326     if (buffer)
327         *buffer = mesaBuffer;
328 
329     return GLFW_TRUE;
330 }
331 
glfwGetOSMesaDepthBuffer(GLFWwindow * handle,int * width,int * height,int * bytesPerValue,void ** buffer)332 GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
333                                      int* width, int* height,
334                                      int* bytesPerValue,
335                                      void** buffer)
336 {
337     void* mesaBuffer;
338     GLint mesaWidth, mesaHeight, mesaBytes;
339 
340     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
341 
342     _GLFWwindow* window = (_GLFWwindow*) handle;
343     assert(window != NULL);
344 
345     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
346     {
347         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
348         return GLFW_FALSE;
349     }
350 
351     if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
352                               &mesaWidth, &mesaHeight,
353                               &mesaBytes, &mesaBuffer))
354     {
355         _glfwInputError(GLFW_PLATFORM_ERROR,
356                         "OSMesa: Failed to retrieve depth buffer");
357         return GLFW_FALSE;
358     }
359 
360     if (width)
361         *width = mesaWidth;
362     if (height)
363         *height = mesaHeight;
364     if (bytesPerValue)
365         *bytesPerValue = mesaBytes;
366     if (buffer)
367         *buffer = mesaBuffer;
368 
369     return GLFW_TRUE;
370 }
371 
glfwGetOSMesaContext(GLFWwindow * handle)372 GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
373 {
374     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
375 
376     _GLFWwindow* window = (_GLFWwindow*) handle;
377     assert(window != NULL);
378 
379     if (window->context.source != GLFW_OSMESA_CONTEXT_API)
380     {
381         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
382         return NULL;
383     }
384 
385     return window->context.osmesa.handle;
386 }
387 
388