1//========================================================================
2// GLFW 3.4 OSMesa - www.glfw.org
3//------------------------------------------------------------------------
4// Copyright (c) 2016 Google Inc.
5// Copyright (c) 2016-2017 Camilla Löwy <[email protected]>
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// Please use C89 style variable declarations in this file because VS 2010
28//========================================================================
29
30#include <stdlib.h>
31#include <string.h>
32#include <assert.h>
33
34#include "internal.h"
35
36
37static void makeContextCurrentOSMesa(_GLFWwindow* window)
38{
39 if (window)
40 {
41 int width, height;
42 _glfw.platform.getFramebufferSize(window, &width, &height);
43
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))
48 {
49 _glfw_free(window->context.osmesa.buffer);
50
51 // Allocate the new buffer (width * height * 8-bit RGBA)
52 window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height);
53 window->context.osmesa.width = width;
54 window->context.osmesa.height = height;
55 }
56
57 if (!OSMesaMakeCurrent(window->context.osmesa.handle,
58 window->context.osmesa.buffer,
59 GL_UNSIGNED_BYTE,
60 width, height))
61 {
62 _glfwInputError(GLFW_PLATFORM_ERROR,
63 "OSMesa: Failed to make context current");
64 return;
65 }
66 }
67
68 _glfwPlatformSetTls(&_glfw.contextSlot, window);
69}
70
71static GLFWglproc getProcAddressOSMesa(const char* procname)
72{
73 return (GLFWglproc) OSMesaGetProcAddress(procname);
74}
75
76static void destroyContextOSMesa(_GLFWwindow* window)
77{
78 if (window->context.osmesa.handle)
79 {
80 OSMesaDestroyContext(window->context.osmesa.handle);
81 window->context.osmesa.handle = NULL;
82 }
83
84 if (window->context.osmesa.buffer)
85 {
86 _glfw_free(window->context.osmesa.buffer);
87 window->context.osmesa.width = 0;
88 window->context.osmesa.height = 0;
89 }
90}
91
92static void swapBuffersOSMesa(_GLFWwindow* window)
93{
94 // No double buffering on OSMesa
95}
96
97static void swapIntervalOSMesa(int interval)
98{
99 // No swap interval on OSMesa
100}
101
102static int extensionSupportedOSMesa(const char* extension)
103{
104 // OSMesa does not have extensions
105 return GLFW_FALSE;
106}
107
108
109//////////////////////////////////////////////////////////////////////////
110////// GLFW internal API //////
111//////////////////////////////////////////////////////////////////////////
112
113GLFWbool _glfwInitOSMesa(void)
114{
115 int i;
116 const char* sonames[] =
117 {
118#if defined(_GLFW_OSMESA_LIBRARY)
119 _GLFW_OSMESA_LIBRARY,
120#elif defined(_WIN32)
121 "libOSMesa.dll",
122 "OSMesa.dll",
123#elif defined(__APPLE__)
124 "libOSMesa.8.dylib",
125#elif defined(__CYGWIN__)
126 "libOSMesa-8.so",
127#else
128 "libOSMesa.so.8",
129 "libOSMesa.so.6",
130#endif
131 NULL
132 };
133
134 if (_glfw.osmesa.handle)
135 return GLFW_TRUE;
136
137 for (i = 0; sonames[i]; i++)
138 {
139 _glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]);
140 if (_glfw.osmesa.handle)
141 break;
142 }
143
144 if (!_glfw.osmesa.handle)
145 {
146 _glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
147 return GLFW_FALSE;
148 }
149
150 _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
151 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt");
152 _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
153 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
154 _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
155 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext");
156 _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
157 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent");
158 _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
159 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
160 _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
161 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
162 _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
163 _glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress");
164
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)
171 {
172 _glfwInputError(GLFW_PLATFORM_ERROR,
173 "OSMesa: Failed to load required entry points");
174
175 _glfwTerminateOSMesa();
176 return GLFW_FALSE;
177 }
178
179 return GLFW_TRUE;
180}
181
182void _glfwTerminateOSMesa(void)
183{
184 if (_glfw.osmesa.handle)
185 {
186 _glfwPlatformFreeModule(_glfw.osmesa.handle);
187 _glfw.osmesa.handle = NULL;
188 }
189}
190
191#define setAttrib(a, v) \
192{ \
193 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
194 attribs[index++] = a; \
195 attribs[index++] = v; \
196}
197
198GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
199 const _GLFWctxconfig* ctxconfig,
200 const _GLFWfbconfig* fbconfig)
201{
202 OSMesaContext share = NULL;
203 const int accumBits = fbconfig->accumRedBits +
204 fbconfig->accumGreenBits +
205 fbconfig->accumBlueBits +
206 fbconfig->accumAlphaBits;
207
208 if (ctxconfig->client == GLFW_OPENGL_ES_API)
209 {
210 _glfwInputError(GLFW_API_UNAVAILABLE,
211 "OSMesa: OpenGL ES is not available on OSMesa");
212 return GLFW_FALSE;
213 }
214
215 if (ctxconfig->share)
216 share = ctxconfig->share->context.osmesa.handle;
217
218 if (OSMesaCreateContextAttribs)
219 {
220 int index = 0, attribs[40];
221
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);
226
227 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
228 {
229 setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
230 }
231 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
232 {
233 setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
234 }
235
236 if (ctxconfig->major != 1 || ctxconfig->minor != 0)
237 {
238 setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
239 setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
240 }
241
242 if (ctxconfig->forward)
243 {
244 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
245 "OSMesa: Forward-compatible contexts not supported");
246 return GLFW_FALSE;
247 }
248
249 setAttrib(0, 0);
250
251 window->context.osmesa.handle =
252 OSMesaCreateContextAttribs(attribs, share);
253 }
254 else
255 {
256 if (ctxconfig->profile)
257 {
258 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
259 "OSMesa: OpenGL profiles unavailable");
260 return GLFW_FALSE;
261 }
262
263 window->context.osmesa.handle =
264 OSMesaCreateContextExt(OSMESA_RGBA,
265 fbconfig->depthBits,
266 fbconfig->stencilBits,
267 accumBits,
268 share);
269 }
270
271 if (window->context.osmesa.handle == NULL)
272 {
273 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
274 "OSMesa: Failed to create context");
275 return GLFW_FALSE;
276 }
277
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;
284
285 return GLFW_TRUE;
286}
287
288#undef setAttrib
289
290
291//////////////////////////////////////////////////////////////////////////
292////// GLFW native API //////
293//////////////////////////////////////////////////////////////////////////
294
295GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
296 int* height, int* format, void** buffer)
297{
298 void* mesaBuffer;
299 GLint mesaWidth, mesaHeight, mesaFormat;
300 _GLFWwindow* window = (_GLFWwindow*) handle;
301 assert(window != NULL);
302
303 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
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
332GLFWAPI 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 _GLFWwindow* window = (_GLFWwindow*) handle;
340 assert(window != NULL);
341
342 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
343
344 if (window->context.source != GLFW_OSMESA_CONTEXT_API)
345 {
346 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
347 return GLFW_FALSE;
348 }
349
350 if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
351 &mesaWidth, &mesaHeight,
352 &mesaBytes, &mesaBuffer))
353 {
354 _glfwInputError(GLFW_PLATFORM_ERROR,
355 "OSMesa: Failed to retrieve depth buffer");
356 return GLFW_FALSE;
357 }
358
359 if (width)
360 *width = mesaWidth;
361 if (height)
362 *height = mesaHeight;
363 if (bytesPerValue)
364 *bytesPerValue = mesaBytes;
365 if (buffer)
366 *buffer = mesaBuffer;
367
368 return GLFW_TRUE;
369}
370
371GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
372{
373 _GLFWwindow* window = (_GLFWwindow*) handle;
374 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
375
376 if (window->context.source != GLFW_OSMESA_CONTEXT_API)
377 {
378 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
379 return NULL;
380 }
381
382 return window->context.osmesa.handle;
383}
384
385