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