src/video/windows/SDL_windowsopengl.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 31 Jul 2013 11:00:23 -0400
changeset 7553 f0091f8eae33
parent 7412 50211a1fd557
child 7559 0dd3b05797f9
permissions -rw-r--r--
Workaround some Windows OpenGL drivers mishandling wglMakeCurrent().

You should be able to do wglMakeCurrent(NULL, NULL), according to MSDN, since
the first parameter is ignored if the second is NULL, but this causes problems
on some drivers, so make sure we always have a valid HDC in the first
parameter (and exit early if we already have no current context in the
NULL, NULL case).
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "SDL_assert.h"
    26 #include "SDL_windowsvideo.h"
    27 
    28 /* WGL implementation of SDL OpenGL support */
    29 
    30 #if SDL_VIDEO_OPENGL_WGL
    31 #include "SDL_opengl.h"
    32 
    33 #define DEFAULT_OPENGL "OPENGL32.DLL"
    34 
    35 #ifndef WGL_ARB_create_context
    36 #define WGL_ARB_create_context
    37 #define WGL_CONTEXT_MAJOR_VERSION_ARB   0x2091
    38 #define WGL_CONTEXT_MINOR_VERSION_ARB   0x2092
    39 #define WGL_CONTEXT_LAYER_PLANE_ARB     0x2093
    40 #define WGL_CONTEXT_FLAGS_ARB           0x2094
    41 #define WGL_CONTEXT_DEBUG_BIT_ARB       0x0001
    42 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB  0x0002
    43 
    44 #ifndef WGL_ARB_create_context_profile
    45 #define WGL_ARB_create_context_profile
    46 #define WGL_CONTEXT_PROFILE_MASK_ARB              0x9126
    47 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB          0x00000001
    48 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
    49 #endif
    50 
    51 #ifndef WGL_ARB_create_context_robustness
    52 #define WGL_ARB_create_context_robustness
    53 #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB         0x00000004
    54 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
    55 #define WGL_NO_RESET_NOTIFICATION_ARB                   0x8261
    56 #define WGL_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
    57 #endif
    58 #endif
    59 
    60 #ifndef WGL_EXT_create_context_es2_profile
    61 #define WGL_EXT_create_context_es2_profile
    62 #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT           0x00000004
    63 #endif
    64 
    65 #ifndef WGL_EXT_create_context_es_profile
    66 #define WGL_EXT_create_context_es_profile
    67 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT            0x00000004
    68 #endif
    69 
    70 typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC,
    71                                                             HGLRC
    72                                                             hShareContext,
    73                                                             const int
    74                                                             *attribList);
    75 
    76 int
    77 WIN_GL_LoadLibrary(_THIS, const char *path)
    78 {
    79     LPTSTR wpath;
    80     HANDLE handle;
    81 
    82     if (path == NULL) {
    83         path = SDL_getenv("SDL_OPENGL_LIBRARY");
    84     }
    85     if (path == NULL) {
    86         path = DEFAULT_OPENGL;
    87     }
    88     wpath = WIN_UTF8ToString(path);
    89     _this->gl_config.dll_handle = LoadLibrary(wpath);
    90     SDL_free(wpath);
    91     if (!_this->gl_config.dll_handle) {
    92         char message[1024];
    93         SDL_snprintf(message, SDL_arraysize(message), "LoadLibrary(\"%s\")",
    94                      path);
    95         return WIN_SetError(message);
    96     }
    97     SDL_strlcpy(_this->gl_config.driver_path, path,
    98                 SDL_arraysize(_this->gl_config.driver_path));
    99 
   100     /* Allocate OpenGL memory */
   101     _this->gl_data =
   102         (struct SDL_GLDriverData *) SDL_calloc(1,
   103                                                sizeof(struct
   104                                                       SDL_GLDriverData));
   105     if (!_this->gl_data) {
   106         return SDL_OutOfMemory();
   107     }
   108 
   109     /* Load function pointers */
   110     handle = _this->gl_config.dll_handle;
   111     _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
   112         GetProcAddress(handle, "wglGetProcAddress");
   113     _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
   114         GetProcAddress(handle, "wglCreateContext");
   115     _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
   116         GetProcAddress(handle, "wglDeleteContext");
   117     _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
   118         GetProcAddress(handle, "wglMakeCurrent");
   119     _this->gl_data->wglShareLists = (BOOL(WINAPI *) (HGLRC, HGLRC))
   120         GetProcAddress(handle, "wglShareLists");
   121 
   122     if (!_this->gl_data->wglGetProcAddress ||
   123         !_this->gl_data->wglCreateContext ||
   124         !_this->gl_data->wglDeleteContext ||
   125         !_this->gl_data->wglMakeCurrent) {
   126         SDL_UnloadObject(handle);
   127         return SDL_SetError("Could not retrieve OpenGL functions");
   128     }
   129 
   130     return 0;
   131 }
   132 
   133 void *
   134 WIN_GL_GetProcAddress(_THIS, const char *proc)
   135 {
   136     void *func;
   137 
   138     /* This is to pick up extensions */
   139     func = _this->gl_data->wglGetProcAddress(proc);
   140     if (!func) {
   141         /* This is probably a normal GL function */
   142         func = GetProcAddress(_this->gl_config.dll_handle, proc);
   143     }
   144     return func;
   145 }
   146 
   147 void
   148 WIN_GL_UnloadLibrary(_THIS)
   149 {
   150     FreeLibrary((HMODULE) _this->gl_config.dll_handle);
   151     _this->gl_config.dll_handle = NULL;
   152 
   153     /* Free OpenGL memory */
   154     SDL_free(_this->gl_data);
   155     _this->gl_data = NULL;
   156 }
   157 
   158 static void
   159 WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
   160 {
   161     SDL_zerop(pfd);
   162     pfd->nSize = sizeof(*pfd);
   163     pfd->nVersion = 1;
   164     pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
   165     if (_this->gl_config.double_buffer) {
   166         pfd->dwFlags |= PFD_DOUBLEBUFFER;
   167     }
   168     if (_this->gl_config.stereo) {
   169         pfd->dwFlags |= PFD_STEREO;
   170     }
   171     pfd->iLayerType = PFD_MAIN_PLANE;
   172     pfd->iPixelType = PFD_TYPE_RGBA;
   173     pfd->cRedBits = _this->gl_config.red_size;
   174     pfd->cGreenBits = _this->gl_config.green_size;
   175     pfd->cBlueBits = _this->gl_config.blue_size;
   176     pfd->cAlphaBits = _this->gl_config.alpha_size;
   177     if (_this->gl_config.buffer_size) {
   178         pfd->cColorBits =
   179             _this->gl_config.buffer_size - _this->gl_config.alpha_size;
   180     } else {
   181         pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
   182     }
   183     pfd->cAccumRedBits = _this->gl_config.accum_red_size;
   184     pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
   185     pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
   186     pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
   187     pfd->cAccumBits =
   188         (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
   189          pfd->cAccumAlphaBits);
   190     pfd->cDepthBits = _this->gl_config.depth_size;
   191     pfd->cStencilBits = _this->gl_config.stencil_size;
   192 }
   193 
   194 /* Choose the closest pixel format that meets or exceeds the target.
   195    FIXME: Should we weight any particular attribute over any other?
   196 */
   197 static int
   198 WIN_GL_ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * target)
   199 {
   200     PIXELFORMATDESCRIPTOR pfd;
   201     int count, index, best = 0;
   202     unsigned int dist, best_dist = ~0U;
   203 
   204     count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
   205 
   206     for (index = 1; index <= count; index++) {
   207 
   208         if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
   209             continue;
   210         }
   211 
   212         if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
   213             continue;
   214         }
   215 
   216         if (pfd.iLayerType != target->iLayerType) {
   217             continue;
   218         }
   219         if (pfd.iPixelType != target->iPixelType) {
   220             continue;
   221         }
   222 
   223         dist = 0;
   224 
   225         if (pfd.cColorBits < target->cColorBits) {
   226             continue;
   227         } else {
   228             dist += (pfd.cColorBits - target->cColorBits);
   229         }
   230         if (pfd.cRedBits < target->cRedBits) {
   231             continue;
   232         } else {
   233             dist += (pfd.cRedBits - target->cRedBits);
   234         }
   235         if (pfd.cGreenBits < target->cGreenBits) {
   236             continue;
   237         } else {
   238             dist += (pfd.cGreenBits - target->cGreenBits);
   239         }
   240         if (pfd.cBlueBits < target->cBlueBits) {
   241             continue;
   242         } else {
   243             dist += (pfd.cBlueBits - target->cBlueBits);
   244         }
   245         if (pfd.cAlphaBits < target->cAlphaBits) {
   246             continue;
   247         } else {
   248             dist += (pfd.cAlphaBits - target->cAlphaBits);
   249         }
   250         if (pfd.cAccumBits < target->cAccumBits) {
   251             continue;
   252         } else {
   253             dist += (pfd.cAccumBits - target->cAccumBits);
   254         }
   255         if (pfd.cAccumRedBits < target->cAccumRedBits) {
   256             continue;
   257         } else {
   258             dist += (pfd.cAccumRedBits - target->cAccumRedBits);
   259         }
   260         if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
   261             continue;
   262         } else {
   263             dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
   264         }
   265         if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
   266             continue;
   267         } else {
   268             dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
   269         }
   270         if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
   271             continue;
   272         } else {
   273             dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
   274         }
   275         if (pfd.cDepthBits < target->cDepthBits) {
   276             continue;
   277         } else {
   278             dist += (pfd.cDepthBits - target->cDepthBits);
   279         }
   280         if (pfd.cStencilBits < target->cStencilBits) {
   281             continue;
   282         } else {
   283             dist += (pfd.cStencilBits - target->cStencilBits);
   284         }
   285 
   286         if (dist < best_dist) {
   287             best = index;
   288             best_dist = dist;
   289         }
   290     }
   291 
   292     return best;
   293 }
   294 
   295 static SDL_bool
   296 HasExtension(const char *extension, const char *extensions)
   297 {
   298     const char *start;
   299     const char *where, *terminator;
   300 
   301     /* Extension names should not have spaces. */
   302     where = SDL_strchr(extension, ' ');
   303     if (where || *extension == '\0')
   304         return SDL_FALSE;
   305 
   306     if (!extensions)
   307         return SDL_FALSE;
   308 
   309     /* It takes a bit of care to be fool-proof about parsing the
   310      * OpenGL extensions string. Don't be fooled by sub-strings,
   311      * etc. */
   312 
   313     start = extensions;
   314 
   315     for (;;) {
   316         where = SDL_strstr(start, extension);
   317         if (!where)
   318             break;
   319 
   320         terminator = where + SDL_strlen(extension);
   321         if (where == start || *(where - 1) == ' ')
   322             if (*terminator == ' ' || *terminator == '\0')
   323                 return SDL_TRUE;
   324 
   325         start = terminator;
   326     }
   327     return SDL_FALSE;
   328 }
   329 
   330 static void
   331 WIN_GL_InitExtensions(_THIS, HDC hdc)
   332 {
   333     const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
   334     const char *extensions;
   335 
   336     wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
   337         _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
   338     if (wglGetExtensionsStringARB) {
   339         extensions = wglGetExtensionsStringARB(hdc);
   340     } else {
   341         extensions = NULL;
   342     }
   343 
   344     /* Check for WGL_ARB_pixel_format */
   345     _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
   346     if (HasExtension("WGL_ARB_pixel_format", extensions)) {
   347         _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
   348                                                    (HDC, const int *,
   349                                                     const FLOAT *, UINT,
   350                                                     int *, UINT *))
   351             WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
   352         _this->gl_data->wglGetPixelFormatAttribivARB =
   353             (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
   354             WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
   355 
   356         if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
   357             (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
   358             _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
   359         }
   360     }
   361 
   362     /* Check for WGL_EXT_swap_control */
   363     _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
   364     if (HasExtension("WGL_EXT_swap_control", extensions)) {
   365         _this->gl_data->wglSwapIntervalEXT =
   366             WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
   367         _this->gl_data->wglGetSwapIntervalEXT =
   368             WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
   369         if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
   370             _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
   371         }
   372     } else {
   373         _this->gl_data->wglSwapIntervalEXT = NULL;
   374         _this->gl_data->wglGetSwapIntervalEXT = NULL;
   375     }
   376 }
   377 
   378 static int
   379 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
   380 {
   381     HWND hwnd;
   382     HDC hdc;
   383     PIXELFORMATDESCRIPTOR pfd;
   384     HGLRC hglrc;
   385     int pixel_format = 0;
   386     unsigned int matching;
   387 
   388     hwnd =
   389         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
   390                      10, 10, NULL, NULL, SDL_Instance, NULL);
   391     WIN_PumpEvents(_this);
   392 
   393     hdc = GetDC(hwnd);
   394 
   395     WIN_GL_SetupPixelFormat(_this, &pfd);
   396 
   397     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
   398 
   399     hglrc = _this->gl_data->wglCreateContext(hdc);
   400     if (hglrc) {
   401         _this->gl_data->wglMakeCurrent(hdc, hglrc);
   402 
   403         WIN_GL_InitExtensions(_this, hdc);
   404 
   405         if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
   406             _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
   407                                                     1, &pixel_format,
   408                                                     &matching);
   409         }
   410 
   411         _this->gl_data->wglMakeCurrent(hdc, NULL);
   412         _this->gl_data->wglDeleteContext(hglrc);
   413     }
   414     ReleaseDC(hwnd, hdc);
   415     DestroyWindow(hwnd);
   416     WIN_PumpEvents(_this);
   417 
   418     return pixel_format;
   419 }
   420 
   421 int
   422 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
   423 {
   424     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   425     PIXELFORMATDESCRIPTOR pfd;
   426     int pixel_format = 0;
   427     int iAttribs[64];
   428     int *iAttr;
   429     int *iAccelAttr;
   430     float fAttribs[1] = { 0 };
   431 
   432     WIN_GL_SetupPixelFormat(_this, &pfd);
   433 
   434     /* setup WGL_ARB_pixel_format attribs */
   435     iAttr = &iAttribs[0];
   436 
   437     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   438     *iAttr++ = GL_TRUE;
   439     *iAttr++ = WGL_RED_BITS_ARB;
   440     *iAttr++ = _this->gl_config.red_size;
   441     *iAttr++ = WGL_GREEN_BITS_ARB;
   442     *iAttr++ = _this->gl_config.green_size;
   443     *iAttr++ = WGL_BLUE_BITS_ARB;
   444     *iAttr++ = _this->gl_config.blue_size;
   445 
   446     if (_this->gl_config.alpha_size) {
   447         *iAttr++ = WGL_ALPHA_BITS_ARB;
   448         *iAttr++ = _this->gl_config.alpha_size;
   449     }
   450 
   451     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
   452     *iAttr++ = _this->gl_config.double_buffer;
   453 
   454     *iAttr++ = WGL_DEPTH_BITS_ARB;
   455     *iAttr++ = _this->gl_config.depth_size;
   456 
   457     if (_this->gl_config.stencil_size) {
   458         *iAttr++ = WGL_STENCIL_BITS_ARB;
   459         *iAttr++ = _this->gl_config.stencil_size;
   460     }
   461 
   462     if (_this->gl_config.accum_red_size) {
   463         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   464         *iAttr++ = _this->gl_config.accum_red_size;
   465     }
   466 
   467     if (_this->gl_config.accum_green_size) {
   468         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   469         *iAttr++ = _this->gl_config.accum_green_size;
   470     }
   471 
   472     if (_this->gl_config.accum_blue_size) {
   473         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   474         *iAttr++ = _this->gl_config.accum_blue_size;
   475     }
   476 
   477     if (_this->gl_config.accum_alpha_size) {
   478         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   479         *iAttr++ = _this->gl_config.accum_alpha_size;
   480     }
   481 
   482     if (_this->gl_config.stereo) {
   483         *iAttr++ = WGL_STEREO_ARB;
   484         *iAttr++ = GL_TRUE;
   485     }
   486 
   487     if (_this->gl_config.multisamplebuffers) {
   488         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   489         *iAttr++ = _this->gl_config.multisamplebuffers;
   490     }
   491 
   492     if (_this->gl_config.multisamplesamples) {
   493         *iAttr++ = WGL_SAMPLES_ARB;
   494         *iAttr++ = _this->gl_config.multisamplesamples;
   495     }
   496 
   497     /* We always choose either FULL or NO accel on Windows, because of flaky
   498        drivers. If the app didn't specify, we use FULL, because that's
   499        probably what they wanted (and if you didn't care and got FULL, that's
   500        a perfectly valid result in any case). */
   501     *iAttr++ = WGL_ACCELERATION_ARB;
   502     iAccelAttr = iAttr;
   503     if (_this->gl_config.accelerated) {
   504         *iAttr++ = WGL_FULL_ACCELERATION_ARB;
   505     } else {
   506         *iAttr++ = WGL_NO_ACCELERATION_ARB;
   507     }
   508 
   509     *iAttr = 0;
   510 
   511     /* Choose and set the closest available pixel format */
   512     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   513 
   514     /* App said "don't care about accel" and FULL accel failed. Try NO. */
   515     if ( ( !pixel_format ) && ( _this->gl_config.accelerated < 0 ) ) {
   516         *iAccelAttr = WGL_NO_ACCELERATION_ARB;
   517         pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   518         *iAccelAttr = WGL_FULL_ACCELERATION_ARB;  /* if we try again. */
   519     }
   520     if (!pixel_format) {
   521         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
   522     }
   523     if (!pixel_format) {
   524         return SDL_SetError("No matching GL pixel format available");
   525     }
   526     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
   527         return WIN_SetError("SetPixelFormat()");
   528     }
   529     return 0;
   530 }
   531 
   532 SDL_GLContext
   533 WIN_GL_CreateContext(_THIS, SDL_Window * window)
   534 {
   535     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   536     HGLRC context, share_context;
   537 
   538     if (_this->gl_config.share_with_current_context) {
   539         share_context = (HGLRC)SDL_GL_GetCurrentContext();
   540     } else {
   541         share_context = 0;
   542     }
   543 
   544     if (_this->gl_config.major_version < 3 &&
   545     _this->gl_config.profile_mask == 0 &&
   546     _this->gl_config.flags == 0) {
   547         /* Create legacy context */
   548         context = _this->gl_data->wglCreateContext(hdc);
   549     if( share_context != 0 ) {
   550             _this->gl_data->wglShareLists(share_context, context);
   551     }
   552     } else {
   553         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
   554         HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
   555         if (!temp_context) {
   556             SDL_SetError("Could not create GL context");
   557             return NULL;
   558         }
   559 
   560         /* Make the context current */
   561         if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
   562             WIN_GL_DeleteContext(_this, temp_context);
   563             return NULL;
   564         }
   565 
   566         wglCreateContextAttribsARB =
   567             (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   568             wglGetProcAddress("wglCreateContextAttribsARB");
   569         if (!wglCreateContextAttribsARB) {
   570             SDL_SetError("GL 3.x is not supported");
   571             context = temp_context;
   572         } else {
   573         /* max 8 attributes plus terminator */
   574             int attribs[9] = {
   575                 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
   576                 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
   577                 0
   578             };
   579         int iattr = 4;
   580 
   581         /* SDL profile bits match WGL profile bits */
   582         if( _this->gl_config.profile_mask != 0 ) {
   583             attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
   584         attribs[iattr++] = _this->gl_config.profile_mask;
   585         }
   586 
   587         /* SDL flags match WGL flags */
   588         if( _this->gl_config.flags != 0 ) {
   589             attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
   590         attribs[iattr++] = _this->gl_config.flags;
   591         }
   592 
   593         attribs[iattr++] = 0;
   594 
   595             /* Create the GL 3.x context */
   596             context = wglCreateContextAttribsARB(hdc, share_context, attribs);
   597             /* Delete the GL 2.x context */
   598             _this->gl_data->wglDeleteContext(temp_context);
   599         }
   600     }
   601 
   602     if (!context) {
   603         WIN_SetError("Could not create GL context");
   604         return NULL;
   605     }
   606 
   607     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
   608         WIN_GL_DeleteContext(_this, context);
   609         return NULL;
   610     }
   611 
   612     WIN_GL_InitExtensions(_this, hdc);
   613 
   614     return context;
   615 }
   616 
   617 int
   618 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   619 {
   620     HDC hdc;
   621 
   622     if (!_this->gl_data) {
   623         return SDL_SetError("OpenGL not initialized");
   624     }
   625 
   626     /* sanity check that higher level handled this. */
   627     SDL_assert(window || (!window && !context));
   628 
   629     /* Some Windows drivers freak out if hdc is NULL, even when context is
   630        NULL, against spec. Since hdc is _supposed_ to be ignored if context
   631        is NULL, we either use the current GL window, or do nothing if we
   632        already have no current context. */
   633     if (!window) {
   634         window = SDL_GL_GetCurrentWindow();
   635         if (!window) {
   636             SDL_assert(SDL_GL_GetCurrentContext() == NULL);
   637             return 0;  /* already done. */
   638         }
   639     }
   640 
   641     hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   642     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
   643         return WIN_SetError("wglMakeCurrent()");
   644     }
   645     return 0;
   646 }
   647 
   648 int
   649 WIN_GL_SetSwapInterval(_THIS, int interval)
   650 {
   651     if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
   652         return SDL_SetError("Negative swap interval unsupported in this GL");
   653     } else if (_this->gl_data->wglSwapIntervalEXT) {
   654         if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
   655             return WIN_SetError("wglSwapIntervalEXT()");
   656         }
   657     } else {
   658         return SDL_Unsupported();
   659     }
   660     return 0;
   661 }
   662 
   663 int
   664 WIN_GL_GetSwapInterval(_THIS)
   665 {
   666     int retval = 0;
   667     if (_this->gl_data->wglGetSwapIntervalEXT) {
   668         retval = _this->gl_data->wglGetSwapIntervalEXT();
   669     }
   670     return retval;
   671 }
   672 
   673 void
   674 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
   675 {
   676     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   677 
   678     SwapBuffers(hdc);
   679 }
   680 
   681 void
   682 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
   683 {
   684     if (!_this->gl_data) {
   685         return;
   686     }
   687     _this->gl_data->wglDeleteContext((HGLRC) context);
   688 }
   689 
   690 #endif /* SDL_VIDEO_OPENGL_WGL */
   691 
   692 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   693 
   694 /* vi: set ts=4 sw=4 expandtab: */