osmesa_context.c 13 KB
Newer Older
Camilla Berglund's avatar
Camilla Berglund committed
1
2
3
4
//========================================================================
// GLFW 3.3 OSMesa - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2016 Google Inc.
Camilla Löwy's avatar
Camilla Löwy committed
5
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
Camilla Berglund's avatar
Camilla Berglund committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//
// 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.
//
//========================================================================
27
28
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
Jason Daly's avatar
Jason Daly committed
29
30
31

#include <stdlib.h>
#include <string.h>
Camilla Berglund's avatar
Camilla Berglund committed
32
#include <assert.h>
Jason Daly's avatar
Jason Daly committed
33
34

#include "internal.h"
Camilla Berglund's avatar
Camilla Berglund committed
35

Jason Daly's avatar
Jason Daly committed
36
37
38
39
40

static void makeContextCurrentOSMesa(_GLFWwindow* window)
{
    if (window)
    {
Camilla Löwy's avatar
Camilla Löwy committed
41
        int width, height;
42
        _glfwPlatformGetFramebufferSize(window, &width, &height);
Camilla Löwy's avatar
Camilla Löwy committed
43

Camilla Berglund's avatar
Camilla Berglund committed
44
        // Check to see if we need to allocate a new buffer
Jason Daly's avatar
Jason Daly committed
45
        if ((window->context.osmesa.buffer == NULL) ||
Camilla Löwy's avatar
Camilla Löwy committed
46
47
            (width != window->context.osmesa.width) ||
            (height != window->context.osmesa.height))
Jason Daly's avatar
Jason Daly committed
48
        {
Camilla Berglund's avatar
Camilla Berglund committed
49
50
51
            free(window->context.osmesa.buffer);

            // Allocate the new buffer (width * height * 8-bit RGBA)
52
            window->context.osmesa.buffer = calloc(4, (size_t) width * height);
Camilla Löwy's avatar
Camilla Löwy committed
53
54
            window->context.osmesa.width  = width;
            window->context.osmesa.height = height;
Jason Daly's avatar
Jason Daly committed
55
56
57
        }

        if (!OSMesaMakeCurrent(window->context.osmesa.handle,
Camilla Löwy's avatar
Camilla Löwy committed
58
59
60
                               window->context.osmesa.buffer,
                               GL_UNSIGNED_BYTE,
                               width, height))
Jason Daly's avatar
Jason Daly committed
61
62
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
63
                            "OSMesa: Failed to make context current");
Jason Daly's avatar
Jason Daly committed
64
65
66
67
            return;
        }
    }

68
    _glfwPlatformSetTls(&_glfw.contextSlot, window);
Jason Daly's avatar
Jason Daly committed
69
70
71
72
}

static GLFWglproc getProcAddressOSMesa(const char* procname)
{
Camilla Berglund's avatar
Camilla Berglund committed
73
    return (GLFWglproc) OSMesaGetProcAddress(procname);
Jason Daly's avatar
Jason Daly committed
74
75
76
77
}

static void destroyContextOSMesa(_GLFWwindow* window)
{
Camilla Berglund's avatar
Camilla Berglund committed
78
    if (window->context.osmesa.handle)
Jason Daly's avatar
Jason Daly committed
79
80
81
82
83
    {
        OSMesaDestroyContext(window->context.osmesa.handle);
        window->context.osmesa.handle = NULL;
    }

Camilla Berglund's avatar
Camilla Berglund committed
84
    if (window->context.osmesa.buffer)
Jason Daly's avatar
Jason Daly committed
85
86
87
88
89
90
91
    {
        free(window->context.osmesa.buffer);
        window->context.osmesa.width = 0;
        window->context.osmesa.height = 0;
    }
}

Camilla Berglund's avatar
Camilla Berglund committed
92
93
94
95
static void swapBuffersOSMesa(_GLFWwindow* window)
{
    // No double buffering on OSMesa
}
Jason Daly's avatar
Jason Daly committed
96

Camilla Berglund's avatar
Camilla Berglund committed
97
98
99
100
static void swapIntervalOSMesa(int interval)
{
    // No swap interval on OSMesa
}
Jason Daly's avatar
Jason Daly committed
101

Camilla Berglund's avatar
Camilla Berglund committed
102
static int extensionSupportedOSMesa(const char* extension)
Jason Daly's avatar
Jason Daly committed
103
{
Camilla Berglund's avatar
Camilla Berglund committed
104
    // OSMesa does not have extensions
Jason Daly's avatar
Jason Daly committed
105
106
107
    return GLFW_FALSE;
}

Camilla Berglund's avatar
Camilla Berglund committed
108

Jason Daly's avatar
Jason Daly committed
109
110
111
112
113
114
115
116
117
//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////

GLFWbool _glfwInitOSMesa(void)
{
    int i;
    const char* sonames[] =
    {
118
119
120
#if defined(_GLFW_OSMESA_LIBRARY)
        _GLFW_OSMESA_LIBRARY,
#elif defined(_WIN32)
Jason Daly's avatar
Jason Daly committed
121
122
        "libOSMesa.dll",
        "OSMesa.dll",
Camilla Berglund's avatar
Camilla Berglund committed
123
124
125
126
#elif defined(__APPLE__)
        "libOSMesa.8.dylib",
#elif defined(__CYGWIN__)
        "libOSMesa-8.so",
Jason Daly's avatar
Jason Daly committed
127
#else
128
        "libOSMesa.so.8",
Jason Daly's avatar
Jason Daly committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
        "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;
    }

150
    _glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
151
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextExt");
152
    _glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
Camilla Berglund's avatar
Camilla Berglund committed
153
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
154
    _glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
Jason Daly's avatar
Jason Daly committed
155
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaDestroyContext");
156
    _glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
Jason Daly's avatar
Jason Daly committed
157
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaMakeCurrent");
158
    _glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
Jason Daly's avatar
Jason Daly committed
159
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
160
    _glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
Jason Daly's avatar
Jason Daly committed
161
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
162
    _glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
Jason Daly's avatar
Jason Daly committed
163
164
        _glfw_dlsym(_glfw.osmesa.handle, "OSMesaGetProcAddress");

165
    if (!_glfw.osmesa.CreateContextExt ||
Jason Daly's avatar
Jason Daly committed
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
        !_glfw.osmesa.DestroyContext ||
        !_glfw.osmesa.MakeCurrent ||
        !_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;
    }
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
191
#define setAttrib(a, v) \
Camilla Berglund's avatar
Camilla Berglund committed
192
{ \
193
    assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
194
195
    attribs[index++] = a; \
    attribs[index++] = v; \
Camilla Berglund's avatar
Camilla Berglund committed
196
197
}

198
199
200
GLFWbool _glfwCreateContextForConfigOSMesa(const _GLFWctxconfig* ctxconfig,
                                           const _GLFWfbconfig* fbconfig,
                                           OSMesaContext* context )
Jason Daly's avatar
Jason Daly committed
201
{
Camilla Berglund's avatar
Camilla Berglund committed
202
    OSMesaContext share = NULL;
203
204
205
206
    const int accumBits = fbconfig->accumRedBits +
                          fbconfig->accumGreenBits +
                          fbconfig->accumBlueBits +
                          fbconfig->accumAlphaBits;
Jason Daly's avatar
Jason Daly committed
207

208
209
210
211
212
213
214
    if (ctxconfig->client == GLFW_OPENGL_ES_API)
    {
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "OSMesa: OpenGL ES is not available on OSMesa");
        return GLFW_FALSE;
    }

Jason Daly's avatar
Jason Daly committed
215
216
217
    if (ctxconfig->share)
        share = ctxconfig->share->context.osmesa.handle;

218
    if (OSMesaCreateContextAttribs)
Camilla Berglund's avatar
Camilla Berglund committed
219
    {
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
        int index = 0, attribs[40];

        setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
        setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
        setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
        setAttrib(OSMESA_ACCUM_BITS, accumBits);

        if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
        {
            setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
        }
        else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
        {
            setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
        }

        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
        {
            setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
            setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
        }

242
243
244
        if (ctxconfig->forward)
        {
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
Vallentin's avatar
Vallentin committed
245
                            "OSMesa: Forward-compatible contexts not supported");
246
247
248
            return GLFW_FALSE;
        }

249
250
        setAttrib(0, 0);

251
        *context =
252
            OSMesaCreateContextAttribs(attribs, share);
Camilla Berglund's avatar
Camilla Berglund committed
253
    }
254
    else
Camilla Berglund's avatar
Camilla Berglund committed
255
    {
256
257
258
259
260
261
        if (ctxconfig->profile)
        {
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                            "OSMesa: OpenGL profiles unavailable");
            return GLFW_FALSE;
        }
Camilla Berglund's avatar
Camilla Berglund committed
262

263
        *context =
264
265
266
267
268
            OSMesaCreateContextExt(OSMESA_RGBA,
                                   fbconfig->depthBits,
                                   fbconfig->stencilBits,
                                   accumBits,
                                   share);
Camilla Berglund's avatar
Camilla Berglund committed
269
270
    }

271
    if (*context == NULL)
Jason Daly's avatar
Jason Daly committed
272
273
    {
        _glfwInputError(GLFW_VERSION_UNAVAILABLE,
Camilla Berglund's avatar
Camilla Berglund committed
274
                        "OSMesa: Failed to create context");
Jason Daly's avatar
Jason Daly committed
275
276
277
        return GLFW_FALSE;
    }

278
279
280
281
282
283
284
285
286
287
288
289
290
291
    return GLFW_TRUE;
}

#undef setAttrib

GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
                                  const _GLFWctxconfig* ctxconfig,
                                  const _GLFWfbconfig* fbconfig)
{
    if(!_glfwCreateContextForConfigOSMesa(ctxconfig,fbconfig,&window->context.osmesa.handle))
    {
        return GLFW_FALSE;
    }

Jason Daly's avatar
Jason Daly committed
292
293
294
295
296
297
298
299
300
301
    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;
}

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
static void _glfwMakeUserContextCurrentOSMesa(_GLFWusercontext* context)
{
    if(context)
    {
        if (!OSMesaMakeCurrent(context->osmesa.handle,
                               context->window->context.osmesa.buffer,
                               GL_UNSIGNED_BYTE,
                               context->window->context.osmesa.width, context->window->context.osmesa.height))
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "OSMesa: Failed to make context current");
            return;
        }
    }
}

static void _glfwDestroyUserContextOSMesa(_GLFWusercontext* context)
{
    if (context->osmesa.handle)
    {
        OSMesaDestroyContext(context->osmesa.handle);
    }
    free(context);
}
Camilla Berglund's avatar
Camilla Berglund committed
326

327
328
_GLFWusercontext* _glfwCreateUserContextOSMesa(_GLFWwindow* window)
{
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    _GLFWusercontext* context;
    _GLFWctxconfig ctxconfig;
    _GLFWfbconfig fbconfig;

    context = calloc(1, sizeof(_GLFWusercontext));
    context->window = window;

    ctxconfig = _glfw.hints.context;
    ctxconfig.share = window;

    fbconfig = _glfw.hints.framebuffer;

    if(!_glfwCreateContextForConfigOSMesa(&ctxconfig,&fbconfig,&context->osmesa.handle))
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                                "OSMesa: Failed to create user OpenGL context");
        free(context);
        return NULL;
    }

    context->makeCurrent = _glfwMakeUserContextCurrentOSMesa;
    context->destroy = _glfwDestroyUserContextOSMesa;

    return context;
353
}
Camilla Berglund's avatar
Camilla Berglund committed
354

Jason Daly's avatar
Jason Daly committed
355
356
357
358
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

Camilla Berglund's avatar
Camilla Berglund committed
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
                                     int* height, int* format, void** buffer)
{
    void* mesaBuffer;
    GLint mesaWidth, mesaHeight, mesaFormat;
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);

    if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
                              &mesaWidth, &mesaHeight,
                              &mesaFormat, &mesaBuffer))
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "OSMesa: Failed to retrieve color buffer");
        return GLFW_FALSE;
    }

    if (width)
        *width = mesaWidth;
    if (height)
        *height = mesaHeight;
    if (format)
        *format = mesaFormat;
    if (buffer)
        *buffer = mesaBuffer;

    return GLFW_TRUE;
}

GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
                                     int* width, int* height,
                                     int* bytesPerValue,
                                     void** buffer)
{
    void* mesaBuffer;
    GLint mesaWidth, mesaHeight, mesaBytes;
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);

    if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
                              &mesaWidth, &mesaHeight,
                              &mesaBytes, &mesaBuffer))
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "OSMesa: Failed to retrieve depth buffer");
        return GLFW_FALSE;
    }

    if (width)
        *width = mesaWidth;
    if (height)
        *height = mesaHeight;
    if (bytesPerValue)
        *bytesPerValue = mesaBytes;
    if (buffer)
        *buffer = mesaBuffer;

    return GLFW_TRUE;
}

GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);

    if (window->context.client == GLFW_NO_API)
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return NULL;
    }

    return window->context.osmesa.handle;
}