src/video/windows/SDL_windowsopengl.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 01 Aug 2013 00:27:22 -0400
changeset 7559 0dd3b05797f9
parent 7553 f0091f8eae33
child 7853 4861edda71d1
permissions -rw-r--r--
Move the fix for Bugzilla #1395 into WIN_GL_SetupWindow() directly.

It's a cleaner solution.
     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 /* actual work of WIN_GL_SetupWindow() happens here. */
   422 static int
   423 WIN_GL_SetupWindowInternal(_THIS, SDL_Window * window)
   424 {
   425     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   426     PIXELFORMATDESCRIPTOR pfd;
   427     int pixel_format = 0;
   428     int iAttribs[64];
   429     int *iAttr;
   430     int *iAccelAttr;
   431     float fAttribs[1] = { 0 };
   432 
   433     WIN_GL_SetupPixelFormat(_this, &pfd);
   434 
   435     /* setup WGL_ARB_pixel_format attribs */
   436     iAttr = &iAttribs[0];
   437 
   438     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   439     *iAttr++ = GL_TRUE;
   440     *iAttr++ = WGL_RED_BITS_ARB;
   441     *iAttr++ = _this->gl_config.red_size;
   442     *iAttr++ = WGL_GREEN_BITS_ARB;
   443     *iAttr++ = _this->gl_config.green_size;
   444     *iAttr++ = WGL_BLUE_BITS_ARB;
   445     *iAttr++ = _this->gl_config.blue_size;
   446 
   447     if (_this->gl_config.alpha_size) {
   448         *iAttr++ = WGL_ALPHA_BITS_ARB;
   449         *iAttr++ = _this->gl_config.alpha_size;
   450     }
   451 
   452     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
   453     *iAttr++ = _this->gl_config.double_buffer;
   454 
   455     *iAttr++ = WGL_DEPTH_BITS_ARB;
   456     *iAttr++ = _this->gl_config.depth_size;
   457 
   458     if (_this->gl_config.stencil_size) {
   459         *iAttr++ = WGL_STENCIL_BITS_ARB;
   460         *iAttr++ = _this->gl_config.stencil_size;
   461     }
   462 
   463     if (_this->gl_config.accum_red_size) {
   464         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   465         *iAttr++ = _this->gl_config.accum_red_size;
   466     }
   467 
   468     if (_this->gl_config.accum_green_size) {
   469         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   470         *iAttr++ = _this->gl_config.accum_green_size;
   471     }
   472 
   473     if (_this->gl_config.accum_blue_size) {
   474         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   475         *iAttr++ = _this->gl_config.accum_blue_size;
   476     }
   477 
   478     if (_this->gl_config.accum_alpha_size) {
   479         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   480         *iAttr++ = _this->gl_config.accum_alpha_size;
   481     }
   482 
   483     if (_this->gl_config.stereo) {
   484         *iAttr++ = WGL_STEREO_ARB;
   485         *iAttr++ = GL_TRUE;
   486     }
   487 
   488     if (_this->gl_config.multisamplebuffers) {
   489         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   490         *iAttr++ = _this->gl_config.multisamplebuffers;
   491     }
   492 
   493     if (_this->gl_config.multisamplesamples) {
   494         *iAttr++ = WGL_SAMPLES_ARB;
   495         *iAttr++ = _this->gl_config.multisamplesamples;
   496     }
   497 
   498     /* We always choose either FULL or NO accel on Windows, because of flaky
   499        drivers. If the app didn't specify, we use FULL, because that's
   500        probably what they wanted (and if you didn't care and got FULL, that's
   501        a perfectly valid result in any case). */
   502     *iAttr++ = WGL_ACCELERATION_ARB;
   503     iAccelAttr = iAttr;
   504     if (_this->gl_config.accelerated) {
   505         *iAttr++ = WGL_FULL_ACCELERATION_ARB;
   506     } else {
   507         *iAttr++ = WGL_NO_ACCELERATION_ARB;
   508     }
   509 
   510     *iAttr = 0;
   511 
   512     /* Choose and set the closest available pixel format */
   513     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   514 
   515     /* App said "don't care about accel" and FULL accel failed. Try NO. */
   516     if ( ( !pixel_format ) && ( _this->gl_config.accelerated < 0 ) ) {
   517         *iAccelAttr = WGL_NO_ACCELERATION_ARB;
   518         pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   519         *iAccelAttr = WGL_FULL_ACCELERATION_ARB;  /* if we try again. */
   520     }
   521     if (!pixel_format) {
   522         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
   523     }
   524     if (!pixel_format) {
   525         return SDL_SetError("No matching GL pixel format available");
   526     }
   527     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
   528         return WIN_SetError("SetPixelFormat()");
   529     }
   530     return 0;
   531 }
   532 
   533 int
   534 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
   535 {
   536     /* The current context is lost in here; save it and reset it. */
   537     SDL_Window *current_win = SDL_GL_GetCurrentWindow();
   538     SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
   539     const int retval = WIN_GL_SetupWindowInternal(_this, window);
   540     WIN_GL_MakeCurrent(_this, current_win, current_ctx);
   541     return retval;
   542 }
   543 
   544 SDL_GLContext
   545 WIN_GL_CreateContext(_THIS, SDL_Window * window)
   546 {
   547     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   548     HGLRC context, share_context;
   549 
   550     if (_this->gl_config.share_with_current_context) {
   551         share_context = (HGLRC)SDL_GL_GetCurrentContext();
   552     } else {
   553         share_context = 0;
   554     }
   555 
   556     if (_this->gl_config.major_version < 3 &&
   557     _this->gl_config.profile_mask == 0 &&
   558     _this->gl_config.flags == 0) {
   559         /* Create legacy context */
   560         context = _this->gl_data->wglCreateContext(hdc);
   561     if( share_context != 0 ) {
   562             _this->gl_data->wglShareLists(share_context, context);
   563     }
   564     } else {
   565         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
   566         HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
   567         if (!temp_context) {
   568             SDL_SetError("Could not create GL context");
   569             return NULL;
   570         }
   571 
   572         /* Make the context current */
   573         if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
   574             WIN_GL_DeleteContext(_this, temp_context);
   575             return NULL;
   576         }
   577 
   578         wglCreateContextAttribsARB =
   579             (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   580             wglGetProcAddress("wglCreateContextAttribsARB");
   581         if (!wglCreateContextAttribsARB) {
   582             SDL_SetError("GL 3.x is not supported");
   583             context = temp_context;
   584         } else {
   585         /* max 8 attributes plus terminator */
   586             int attribs[9] = {
   587                 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
   588                 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
   589                 0
   590             };
   591         int iattr = 4;
   592 
   593         /* SDL profile bits match WGL profile bits */
   594         if( _this->gl_config.profile_mask != 0 ) {
   595             attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
   596         attribs[iattr++] = _this->gl_config.profile_mask;
   597         }
   598 
   599         /* SDL flags match WGL flags */
   600         if( _this->gl_config.flags != 0 ) {
   601             attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
   602         attribs[iattr++] = _this->gl_config.flags;
   603         }
   604 
   605         attribs[iattr++] = 0;
   606 
   607             /* Create the GL 3.x context */
   608             context = wglCreateContextAttribsARB(hdc, share_context, attribs);
   609             /* Delete the GL 2.x context */
   610             _this->gl_data->wglDeleteContext(temp_context);
   611         }
   612     }
   613 
   614     if (!context) {
   615         WIN_SetError("Could not create GL context");
   616         return NULL;
   617     }
   618 
   619     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
   620         WIN_GL_DeleteContext(_this, context);
   621         return NULL;
   622     }
   623 
   624     WIN_GL_InitExtensions(_this, hdc);
   625 
   626     return context;
   627 }
   628 
   629 int
   630 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   631 {
   632     HDC hdc;
   633 
   634     if (!_this->gl_data) {
   635         return SDL_SetError("OpenGL not initialized");
   636     }
   637 
   638     /* sanity check that higher level handled this. */
   639     SDL_assert(window || (!window && !context));
   640 
   641     /* Some Windows drivers freak out if hdc is NULL, even when context is
   642        NULL, against spec. Since hdc is _supposed_ to be ignored if context
   643        is NULL, we either use the current GL window, or do nothing if we
   644        already have no current context. */
   645     if (!window) {
   646         window = SDL_GL_GetCurrentWindow();
   647         if (!window) {
   648             SDL_assert(SDL_GL_GetCurrentContext() == NULL);
   649             return 0;  /* already done. */
   650         }
   651     }
   652 
   653     hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   654     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
   655         return WIN_SetError("wglMakeCurrent()");
   656     }
   657     return 0;
   658 }
   659 
   660 int
   661 WIN_GL_SetSwapInterval(_THIS, int interval)
   662 {
   663     if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
   664         return SDL_SetError("Negative swap interval unsupported in this GL");
   665     } else if (_this->gl_data->wglSwapIntervalEXT) {
   666         if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
   667             return WIN_SetError("wglSwapIntervalEXT()");
   668         }
   669     } else {
   670         return SDL_Unsupported();
   671     }
   672     return 0;
   673 }
   674 
   675 int
   676 WIN_GL_GetSwapInterval(_THIS)
   677 {
   678     int retval = 0;
   679     if (_this->gl_data->wglGetSwapIntervalEXT) {
   680         retval = _this->gl_data->wglGetSwapIntervalEXT();
   681     }
   682     return retval;
   683 }
   684 
   685 void
   686 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
   687 {
   688     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   689 
   690     SwapBuffers(hdc);
   691 }
   692 
   693 void
   694 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
   695 {
   696     if (!_this->gl_data) {
   697         return;
   698     }
   699     _this->gl_data->wglDeleteContext((HGLRC) context);
   700 }
   701 
   702 #endif /* SDL_VIDEO_OPENGL_WGL */
   703 
   704 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   705 
   706 /* vi: set ts=4 sw=4 expandtab: */