src/video/windows/SDL_windowsopengl.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 20 Oct 2013 21:18:05 -0400
changeset 7853 4861edda71d1
parent 7559 0dd3b05797f9
child 7865 f2a42ca4ddf0
permissions -rw-r--r--
Added SDL_GL_FRAMEBUFFER_SRGB_CAPABLE (thanks, David!).

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