context.c 23.2 KB
Newer Older
Camilla Berglund's avatar
Camilla Berglund committed
1
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
2
// GLFW 3.3 - www.glfw.org
Camilla Berglund's avatar
Camilla Berglund committed
3
4
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
Camilla Löwy's avatar
Camilla Löwy committed
5
// Copyright (c) 2006-2016 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
27
28
29
//
// 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.
//
//========================================================================

#include "internal.h"

30
#include <assert.h>
31
#include <stdio.h>
32
#include <string.h>
33
#include <limits.h>
34
#include <stdio.h>
35

Camilla Berglund's avatar
Camilla Berglund committed
36

37
38
39
40
//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////

41
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
Camilla Berglund's avatar
Camilla Berglund committed
42
{
43
    if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
Camilla Löwy's avatar
Camilla Löwy committed
44
45
        ctxconfig->source != GLFW_EGL_CONTEXT_API &&
        ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
46
47
48
49
50
51
52
53
54
55
    {
        _glfwInputError(GLFW_INVALID_ENUM,
                        "Invalid context creation API %i",
                        ctxconfig->source);
        return GLFW_FALSE;
    }

    if (ctxconfig->client != GLFW_NO_API &&
        ctxconfig->client != GLFW_OPENGL_API &&
        ctxconfig->client != GLFW_OPENGL_ES_API)
56
    {
Camilla Berglund's avatar
Camilla Berglund committed
57
58
        _glfwInputError(GLFW_INVALID_ENUM,
                        "Invalid client API %i",
59
                        ctxconfig->client);
60
        return GLFW_FALSE;
61
    }
Camilla Berglund's avatar
Camilla Berglund committed
62

63
    if (ctxconfig->client == GLFW_OPENGL_API)
64
    {
65
66
67
68
        if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
            (ctxconfig->major == 1 && ctxconfig->minor > 5) ||
            (ctxconfig->major == 2 && ctxconfig->minor > 1) ||
            (ctxconfig->major == 3 && ctxconfig->minor > 3))
69
70
71
72
73
        {
            // OpenGL 1.0 is the smallest valid version
            // OpenGL 1.x series ended with version 1.5
            // OpenGL 2.x series ended with version 2.1
            // OpenGL 3.x series ended with version 3.3
Camilla Berglund's avatar
Camilla Berglund committed
74
            // For now, let everything else through
75

76
            _glfwInputError(GLFW_INVALID_VALUE,
Camilla Berglund's avatar
Camilla Berglund committed
77
                            "Invalid OpenGL version %i.%i",
78
                            ctxconfig->major, ctxconfig->minor);
79
            return GLFW_FALSE;
80
81
        }

82
        if (ctxconfig->profile)
83
        {
84
85
            if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
                ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
86
            {
87
                _glfwInputError(GLFW_INVALID_ENUM,
Camilla Berglund's avatar
Camilla Berglund committed
88
89
                                "Invalid OpenGL profile %i",
                                ctxconfig->profile);
90
                return GLFW_FALSE;
91
            }
Camilla Berglund's avatar
Camilla Berglund committed
92

93
            if (ctxconfig->major <= 2 ||
94
                (ctxconfig->major == 3 && ctxconfig->minor < 2))
95
96
97
98
            {
                // Desktop OpenGL context profiles are only defined for version 3.2
                // and above

99
                _glfwInputError(GLFW_INVALID_VALUE,
Camilla Berglund's avatar
Camilla Berglund committed
100
                                "Context profiles are only defined for OpenGL version 3.2 and above");
101
                return GLFW_FALSE;
102
103
104
            }
        }

105
        if (ctxconfig->forward && ctxconfig->major <= 2)
106
107
        {
            // Forward-compatible contexts are only defined for OpenGL version 3.0 and above
108
            _glfwInputError(GLFW_INVALID_VALUE,
Camilla Berglund's avatar
Camilla Berglund committed
109
                            "Forward-compatibility is only defined for OpenGL version 3.0 and above");
110
            return GLFW_FALSE;
111
112
        }
    }
113
    else if (ctxconfig->client == GLFW_OPENGL_ES_API)
114
    {
115
116
117
        if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
            (ctxconfig->major == 1 && ctxconfig->minor > 1) ||
            (ctxconfig->major == 2 && ctxconfig->minor > 0))
118
        {
119
120
            // OpenGL ES 1.0 is the smallest valid version
            // OpenGL ES 1.x series ended with version 1.1
121
            // OpenGL ES 2.x series ended with version 2.0
Camilla Berglund's avatar
Camilla Berglund committed
122
            // For now, let everything else through
123

124
            _glfwInputError(GLFW_INVALID_VALUE,
Camilla Berglund's avatar
Camilla Berglund committed
125
                            "Invalid OpenGL ES version %i.%i",
126
                            ctxconfig->major, ctxconfig->minor);
127
            return GLFW_FALSE;
128
        }
129
    }
Camilla Berglund's avatar
Camilla Berglund committed
130

131
    if (ctxconfig->robustness)
132
    {
133
134
        if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
            ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
135
        {
Camilla Berglund's avatar
Camilla Berglund committed
136
            _glfwInputError(GLFW_INVALID_ENUM,
Camilla Berglund's avatar
Camilla Berglund committed
137
138
                            "Invalid context robustness mode %i",
                            ctxconfig->robustness);
139
            return GLFW_FALSE;
140
141
142
        }
    }

143
144
145
146
147
    if (ctxconfig->release)
    {
        if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
            ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
        {
Camilla Berglund's avatar
Camilla Berglund committed
148
            _glfwInputError(GLFW_INVALID_ENUM,
Camilla Berglund's avatar
Camilla Berglund committed
149
150
                            "Invalid context release behavior %i",
                            ctxconfig->release);
151
            return GLFW_FALSE;
152
153
154
        }
    }

155
    return GLFW_TRUE;
156
}
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
                                         const _GLFWfbconfig* alternatives,
                                         unsigned int count)
{
    unsigned int i;
    unsigned int missing, leastMissing = UINT_MAX;
    unsigned int colorDiff, leastColorDiff = UINT_MAX;
    unsigned int extraDiff, leastExtraDiff = UINT_MAX;
    const _GLFWfbconfig* current;
    const _GLFWfbconfig* closest = NULL;

    for (i = 0;  i < count;  i++)
    {
        current = alternatives + i;

        if (desired->stereo > 0 && current->stereo == 0)
        {
            // Stereo is a hard constraint
            continue;
        }

Camilla Berglund's avatar
Camilla Berglund committed
179
180
181
182
183
184
        if (desired->doublebuffer != current->doublebuffer)
        {
            // Double buffering is a hard constraint
            continue;
        }

185
186
187
188
189
190
191
192
193
194
195
196
197
        // Count number of missing buffers
        {
            missing = 0;

            if (desired->alphaBits > 0 && current->alphaBits == 0)
                missing++;

            if (desired->depthBits > 0 && current->depthBits == 0)
                missing++;

            if (desired->stencilBits > 0 && current->stencilBits == 0)
                missing++;

Camilla Berglund's avatar
Camilla Berglund committed
198
199
200
            if (desired->auxBuffers > 0 &&
                current->auxBuffers < desired->auxBuffers)
            {
201
                missing += desired->auxBuffers - current->auxBuffers;
Camilla Berglund's avatar
Camilla Berglund committed
202
            }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

            if (desired->samples > 0 && current->samples == 0)
            {
                // Technically, several multisampling buffers could be
                // involved, but that's a lower level implementation detail and
                // not important to us here, so we count them as one
                missing++;
            }
        }

        // These polynomials make many small channel size differences matter
        // less than one large channel size difference

        // Calculate color channel size difference value
        {
            colorDiff = 0;

Camilla Berglund's avatar
Camilla Berglund committed
220
            if (desired->redBits != GLFW_DONT_CARE)
221
222
223
224
225
            {
                colorDiff += (desired->redBits - current->redBits) *
                             (desired->redBits - current->redBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
226
            if (desired->greenBits != GLFW_DONT_CARE)
227
228
229
230
231
            {
                colorDiff += (desired->greenBits - current->greenBits) *
                             (desired->greenBits - current->greenBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
232
            if (desired->blueBits != GLFW_DONT_CARE)
233
234
235
236
237
238
239
240
241
242
            {
                colorDiff += (desired->blueBits - current->blueBits) *
                             (desired->blueBits - current->blueBits);
            }
        }

        // Calculate non-color channel size difference value
        {
            extraDiff = 0;

Camilla Berglund's avatar
Camilla Berglund committed
243
            if (desired->alphaBits != GLFW_DONT_CARE)
244
245
246
247
248
            {
                extraDiff += (desired->alphaBits - current->alphaBits) *
                             (desired->alphaBits - current->alphaBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
249
            if (desired->depthBits != GLFW_DONT_CARE)
250
251
252
253
254
            {
                extraDiff += (desired->depthBits - current->depthBits) *
                             (desired->depthBits - current->depthBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
255
            if (desired->stencilBits != GLFW_DONT_CARE)
256
257
258
259
260
            {
                extraDiff += (desired->stencilBits - current->stencilBits) *
                             (desired->stencilBits - current->stencilBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
261
            if (desired->accumRedBits != GLFW_DONT_CARE)
262
263
264
265
266
            {
                extraDiff += (desired->accumRedBits - current->accumRedBits) *
                             (desired->accumRedBits - current->accumRedBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
267
            if (desired->accumGreenBits != GLFW_DONT_CARE)
268
269
270
271
272
            {
                extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
                             (desired->accumGreenBits - current->accumGreenBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
273
            if (desired->accumBlueBits != GLFW_DONT_CARE)
274
275
276
277
278
            {
                extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
                             (desired->accumBlueBits - current->accumBlueBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
279
            if (desired->accumAlphaBits != GLFW_DONT_CARE)
280
281
282
283
284
            {
                extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
                             (desired->accumAlphaBits - current->accumAlphaBits);
            }

Camilla Berglund's avatar
Camilla Berglund committed
285
            if (desired->samples != GLFW_DONT_CARE)
286
287
288
289
290
            {
                extraDiff += (desired->samples - current->samples) *
                             (desired->samples - current->samples);
            }

Camilla Berglund's avatar
Camilla Berglund committed
291
292
            if (desired->sRGB && !current->sRGB)
                extraDiff++;
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
        }

        // Figure out if the current one is better than the best one found so far
        // Least number of missing buffers is the most important heuristic,
        // then color buffer size match and lastly size match for other buffers

        if (missing < leastMissing)
            closest = current;
        else if (missing == leastMissing)
        {
            if ((colorDiff < leastColorDiff) ||
                (colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
            {
                closest = current;
            }
        }

        if (current == closest)
        {
            leastMissing = missing;
            leastColorDiff = colorDiff;
            leastExtraDiff = extraDiff;
        }
    }

    return closest;
}

321
GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
322
{
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
323
324
325
326
327
328
329
330
331
332
333
    int i;
    _GLFWwindow* window;
    const char* version;
    const char* prefixes[] =
    {
        "OpenGL ES-CM ",
        "OpenGL ES-CL ",
        "OpenGL ES ",
        NULL
    };

Camilla Löwy's avatar
Camilla Löwy committed
334
    window = _glfwPlatformGetTls(&_glfw.context);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
335
336
337

    window->context.source = ctxconfig->source;
    window->context.client = GLFW_OPENGL_API;
338

339
    window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
340
        window->context.getProcAddress("glGetIntegerv");
341
    window->context.GetString = (PFNGLGETSTRINGPROC)
342
        window->context.getProcAddress("glGetString");
343
344
345
346
347
    if (!window->context.GetIntegerv || !window->context.GetString)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
        return GLFW_FALSE;
    }
348

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
349
350
    version = (const char*) window->context.GetString(GL_VERSION);
    if (!version)
351
    {
352
353
354
355
356
357
358
359
360
361
362
        if (ctxconfig->client == GLFW_OPENGL_API)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "OpenGL version string retrieval is broken");
        }
        else
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "OpenGL ES version string retrieval is broken");
        }

363
        return GLFW_FALSE;
Camilla Berglund's avatar
Camilla Berglund committed
364
365
    }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    for (i = 0;  prefixes[i];  i++)
    {
        const size_t length = strlen(prefixes[i]);

        if (strncmp(version, prefixes[i], length) == 0)
        {
            version += length;
            window->context.client = GLFW_OPENGL_ES_API;
            break;
        }
    }

    if (!sscanf(version, "%d.%d.%d",
                &window->context.major,
                &window->context.minor,
                &window->context.revision))
    {
383
384
385
386
387
388
389
390
391
392
393
        if (window->context.client == GLFW_OPENGL_API)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "No version found in OpenGL version string");
        }
        else
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "No version found in OpenGL ES version string");
        }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
394
395
        return GLFW_FALSE;
    }
396

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
397
398
399
400
401
402
403
404
405
406
407
    if (window->context.major < ctxconfig->major ||
        (window->context.major == ctxconfig->major &&
         window->context.minor < ctxconfig->minor))
    {
        // The desired OpenGL version is greater than the actual version
        // This only happens if the machine lacks {GLX|WGL}_ARB_create_context
        // /and/ the user has requested an OpenGL version greater than 1.0

        // For API consistency, we emulate the behavior of the
        // {GLX|WGL}_ARB_create_context extension and fail here

408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
        if (window->context.client == GLFW_OPENGL_API)
        {
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                            "Requested OpenGL version %i.%i, got version %i.%i",
                            ctxconfig->major, ctxconfig->minor,
                            window->context.major, window->context.minor);
        }
        else
        {
            _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                            "Requested OpenGL ES version %i.%i, got version %i.%i",
                            ctxconfig->major, ctxconfig->minor,
                            window->context.major, window->context.minor);
        }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
423
424
425
        return GLFW_FALSE;
    }

426
    if (window->context.major >= 3)
Camilla Berglund's avatar
Camilla Berglund committed
427
428
429
430
431
    {
        // OpenGL 3.0+ uses a different function for extension string retrieval
        // We cache it here instead of in glfwExtensionSupported mostly to alert
        // users as early as possible that their build may be broken

432
        window->context.GetStringi = (PFNGLGETSTRINGIPROC)
433
            window->context.getProcAddress("glGetStringi");
434
        if (!window->context.GetStringi)
Camilla Berglund's avatar
Camilla Berglund committed
435
        {
436
437
            _glfwInputError(GLFW_PLATFORM_ERROR,
                            "Entry point retrieval is broken");
438
            return GLFW_FALSE;
Camilla Berglund's avatar
Camilla Berglund committed
439
        }
440
    }
441

442
    if (window->context.client == GLFW_OPENGL_API)
443
    {
444
        // Read back context flags (OpenGL 3.0 and above)
445
        if (window->context.major >= 3)
Camilla Berglund's avatar
Camilla Berglund committed
446
447
        {
            GLint flags;
448
            window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
Camilla Berglund's avatar
Camilla Berglund committed
449
450

            if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
451
                window->context.forward = GLFW_TRUE;
452

453
            if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
454
                window->context.debug = GLFW_TRUE;
455
            else if (glfwExtensionSupported("GL_ARB_debug_output") &&
456
                     ctxconfig->debug)
457
458
            {
                // HACK: This is a workaround for older drivers (pre KHR_debug)
459
460
                //       not setting the debug bit in the context flags for
                //       debug contexts
461
                window->context.debug = GLFW_TRUE;
462
            }
463
464
465

            if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
                window->context.noerror = GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
466
        }
467

468
        // Read back OpenGL context profile (OpenGL 3.2 and above)
469
        if (window->context.major >= 4 ||
470
            (window->context.major == 3 && window->context.minor >= 2))
Camilla Berglund's avatar
Camilla Berglund committed
471
472
        {
            GLint mask;
473
            window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
Camilla Berglund's avatar
Camilla Berglund committed
474
475

            if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
476
                window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
Camilla Berglund's avatar
Camilla Berglund committed
477
            else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
478
                window->context.profile = GLFW_OPENGL_CORE_PROFILE;
479
480
481
482
483
484
            else if (glfwExtensionSupported("GL_ARB_compatibility"))
            {
                // HACK: This is a workaround for the compatibility profile bit
                //       not being set in the context flags if an OpenGL 3.2+
                //       context was created without having requested a specific
                //       version
485
                window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
486
            }
Camilla Berglund's avatar
Camilla Berglund committed
487
        }
488
489
490
491
492

        // Read back robustness strategy
        if (glfwExtensionSupported("GL_ARB_robustness"))
        {
            // NOTE: We avoid using the context flags for detection, as they are
Camilla Berglund's avatar
Camilla Berglund committed
493
            //       only present from 3.0 while the extension applies from 1.1
494
495

            GLint strategy;
496
497
            window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
                                        &strategy);
498
499

            if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
500
                window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
501
            else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
502
                window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
503
504
505
506
507
508
509
510
        }
    }
    else
    {
        // Read back robustness strategy
        if (glfwExtensionSupported("GL_EXT_robustness"))
        {
            // NOTE: The values of these constants match those of the OpenGL ARB
Camilla Berglund's avatar
Camilla Berglund committed
511
            //       one, so we can reuse them here
512
513

            GLint strategy;
514
515
            window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
                                        &strategy);
516
517

            if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
518
                window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
519
            else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
520
                window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
521
        }
522
    }
523
524
525
526

    if (glfwExtensionSupported("GL_KHR_context_flush_control"))
    {
        GLint behavior;
527
        window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
528
529
530
531
532
533

        if (behavior == GL_NONE)
            window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
        else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
            window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
    }
534

535
536
537
    // Clearing the front buffer to black to avoid garbage pixels left over from
    // previous uses of our bit of VRAM
    {
538
539
        PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
            window->context.getProcAddress("glClear");
540
        glClear(GL_COLOR_BUFFER_BIT);
541
        window->context.swapBuffers(window);
542
543
    }

544
    return GLFW_TRUE;
545
546
}

Camilla Berglund's avatar
Camilla Berglund committed
547
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
Camilla Berglund's avatar
Camilla Berglund committed
548
{
549
    const char* start = extensions;
Camilla Berglund's avatar
Camilla Berglund committed
550

551
    for (;;)
Camilla Berglund's avatar
Camilla Berglund committed
552
    {
553
554
        const char* where;
        const char* terminator;
Camilla Berglund's avatar
Camilla Berglund committed
555

556
        where = strstr(start, string);
557
        if (!where)
558
            return GLFW_FALSE;
559

560
561
        terminator = where + strlen(string);
        if (where == start || *(where - 1) == ' ')
Camilla Berglund's avatar
Camilla Berglund committed
562
        {
563
            if (*terminator == ' ' || *terminator == '\0')
Camilla Berglund's avatar
Camilla Berglund committed
564
565
                break;
        }
566

Camilla Berglund's avatar
Camilla Berglund committed
567
568
569
        start = terminator;
    }

570
    return GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
571
572
573
}


574
575
576
//////////////////////////////////////////////////////////////////////////
//////                        GLFW public API                       //////
//////////////////////////////////////////////////////////////////////////
Camilla Berglund's avatar
Camilla Berglund committed
577

578
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
579
580
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
Camilla Löwy's avatar
Camilla Löwy committed
581
    _GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.context);
582

583
    _GLFW_REQUIRE_INIT();
584

585
    if (window && window->context.client == GLFW_NO_API)
586
587
588
589
590
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return;
    }

591
592
593
    if (previous)
    {
        if (!window || window->context.source != previous->context.source)
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
594
            previous->context.makeCurrent(NULL);
595
596
597
    }

    if (window)
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
598
        window->context.makeCurrent(window);
599
600
}

601
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
602
{
603
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
Camilla Löwy's avatar
Camilla Löwy committed
604
    return _glfwPlatformGetTls(&_glfw.context);
605
606
}

607
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
608
{
609
    _GLFWwindow* window = (_GLFWwindow*) handle;
Camilla Berglund's avatar
Camilla Berglund committed
610
    assert(window != NULL);
611

612
    _GLFW_REQUIRE_INIT();
613

614
    if (window->context.client == GLFW_NO_API)
615
616
617
618
619
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return;
    }

620
    window->context.swapBuffers(window);
621
622
623
624
}

GLFWAPI void glfwSwapInterval(int interval)
{
625
626
    _GLFWwindow* window;

627
    _GLFW_REQUIRE_INIT();
628

Camilla Löwy's avatar
Camilla Löwy committed
629
    window = _glfwPlatformGetTls(&_glfw.context);
630
    if (!window)
631
    {
632
        _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
633
634
635
        return;
    }

636
    window->context.swapInterval(interval);
637
638
}

639
GLFWAPI int glfwExtensionSupported(const char* extension)
Camilla Berglund's avatar
Camilla Berglund committed
640
{
Camilla Berglund's avatar
Camilla Berglund committed
641
    _GLFWwindow* window;
Camilla Berglund's avatar
Camilla Berglund committed
642
    assert(extension != NULL);
643

644
    _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
Camilla Berglund's avatar
Camilla Berglund committed
645

Camilla Löwy's avatar
Camilla Löwy committed
646
    window = _glfwPlatformGetTls(&_glfw.context);
Camilla Berglund's avatar
Camilla Berglund committed
647
    if (!window)
648
    {
649
        _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
650
        return GLFW_FALSE;
651
652
    }

653
    if (*extension == '\0')
654
    {
Camilla Berglund's avatar
Camilla Berglund committed
655
        _glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string");
656
        return GLFW_FALSE;
657
    }
Camilla Berglund's avatar
Camilla Berglund committed
658

659
    if (window->context.major >= 3)
Camilla Berglund's avatar
Camilla Berglund committed
660
    {
661
662
663
        int i;
        GLint count;

Camilla Berglund's avatar
Camilla Berglund committed
664
665
        // Check if extension is in the modern OpenGL extensions string list

666
        window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
Camilla Berglund's avatar
Camilla Berglund committed
667

668
        for (i = 0;  i < count;  i++)
Camilla Berglund's avatar
Camilla Berglund committed
669
        {
670
671
            const char* en = (const char*)
                window->context.GetStringi(GL_EXTENSIONS, i);
672
            if (!en)
673
            {
674
                _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
675
                                "Extension string retrieval is broken");
676
                return GLFW_FALSE;
677
            }
678
679

            if (strcmp(en, extension) == 0)
680
                return GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
681
682
        }
    }
683
684
685
686
    else
    {
        // Check if extension is in the old style OpenGL extensions string

687
688
        const char* extensions = (const char*)
            window->context.GetString(GL_EXTENSIONS);
689
690
691
        if (!extensions)
        {
            _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
692
                            "Extension string retrieval is broken");
693
            return GLFW_FALSE;
694
695
696
        }

        if (_glfwStringInExtensionString(extension, extensions))
697
            return GLFW_TRUE;
698
    }
Camilla Berglund's avatar
Camilla Berglund committed
699

700
    // Check if extension is in the platform-specific string
701
    return window->context.extensionSupported(extension);
Camilla Berglund's avatar
Camilla Berglund committed
702
703
}

704
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
Camilla Berglund's avatar
Camilla Berglund committed
705
{
706
    _GLFWwindow* window;
Camilla Berglund's avatar
Camilla Berglund committed
707
    assert(procname != NULL);
708

709
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
710

Camilla Löwy's avatar
Camilla Löwy committed
711
    window = _glfwPlatformGetTls(&_glfw.context);
712
    if (!window)
713
    {
714
        _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
Camilla Berglund's avatar
Camilla Berglund committed
715
        return NULL;
716
    }
Camilla Berglund's avatar
Camilla Berglund committed
717

718
    return window->context.getProcAddress(procname);
Camilla Berglund's avatar
Camilla Berglund committed
719
720
}