src/video/windows/SDL_windowsopengl.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 19 Aug 2017 15:02:03 -0400
changeset 11332 e3797888c6f1
parent 10806 36f40b8cc979
child 11346 4d2bf1b340cd
permissions -rw-r--r--
opengl: Add support for [GLX|WGL]_ARB_create_context_robustness.

This patch was originally written by Marc Di Luzio for glX and enhanced by
Maximilian Malek for WGL, etc. Thanks to both of you!

Fixes Bugzilla #3643.
Fixes Bugzilla #3735.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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_internal.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 #include "SDL_windowsopengles.h"
    29 #include "SDL_hints.h"
    30 
    31 /* WGL implementation of SDL OpenGL support */
    32 
    33 #if SDL_VIDEO_OPENGL_WGL
    34 #include "SDL_opengl.h"
    35 
    36 #define DEFAULT_OPENGL "OPENGL32.DLL"
    37 
    38 #ifndef WGL_ARB_create_context
    39 #define WGL_ARB_create_context
    40 #define WGL_CONTEXT_MAJOR_VERSION_ARB   0x2091
    41 #define WGL_CONTEXT_MINOR_VERSION_ARB   0x2092
    42 #define WGL_CONTEXT_LAYER_PLANE_ARB     0x2093
    43 #define WGL_CONTEXT_FLAGS_ARB           0x2094
    44 #define WGL_CONTEXT_DEBUG_BIT_ARB       0x0001
    45 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB  0x0002
    46 
    47 #ifndef WGL_ARB_create_context_profile
    48 #define WGL_ARB_create_context_profile
    49 #define WGL_CONTEXT_PROFILE_MASK_ARB              0x9126
    50 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB          0x00000001
    51 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
    52 #endif
    53 
    54 #ifndef WGL_ARB_create_context_robustness
    55 #define WGL_ARB_create_context_robustness
    56 #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB         0x00000004
    57 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
    58 #define WGL_NO_RESET_NOTIFICATION_ARB                   0x8261
    59 #define WGL_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
    60 #endif
    61 #endif
    62 
    63 #ifndef WGL_EXT_create_context_es2_profile
    64 #define WGL_EXT_create_context_es2_profile
    65 #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT           0x00000004
    66 #endif
    67 
    68 #ifndef WGL_EXT_create_context_es_profile
    69 #define WGL_EXT_create_context_es_profile
    70 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT            0x00000004
    71 #endif
    72 
    73 #ifndef WGL_ARB_framebuffer_sRGB
    74 #define WGL_ARB_framebuffer_sRGB
    75 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB                0x20A9
    76 #endif
    77 
    78 #ifndef WGL_ARB_context_flush_control
    79 #define WGL_ARB_context_flush_control
    80 #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB   0x2097
    81 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB           0x0000
    82 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB          0x2098
    83 #endif
    84 
    85 typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC,
    86                                                             HGLRC
    87                                                             hShareContext,
    88                                                             const int
    89                                                             *attribList);
    90 
    91 int
    92 WIN_GL_LoadLibrary(_THIS, const char *path)
    93 {
    94     void *handle;
    95 
    96     if (path == NULL) {
    97         path = SDL_getenv("SDL_OPENGL_LIBRARY");
    98     }
    99     if (path == NULL) {
   100         path = DEFAULT_OPENGL;
   101     }
   102     _this->gl_config.dll_handle = SDL_LoadObject(path);
   103     if (!_this->gl_config.dll_handle) {
   104         return -1;
   105     }
   106     SDL_strlcpy(_this->gl_config.driver_path, path,
   107                 SDL_arraysize(_this->gl_config.driver_path));
   108 
   109     /* Allocate OpenGL memory */
   110     _this->gl_data = (struct SDL_GLDriverData *) SDL_calloc(1, sizeof(struct SDL_GLDriverData));
   111     if (!_this->gl_data) {
   112         return SDL_OutOfMemory();
   113     }
   114 
   115     /* Load function pointers */
   116     handle = _this->gl_config.dll_handle;
   117     _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
   118         SDL_LoadFunction(handle, "wglGetProcAddress");
   119     _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
   120         SDL_LoadFunction(handle, "wglCreateContext");
   121     _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
   122         SDL_LoadFunction(handle, "wglDeleteContext");
   123     _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
   124         SDL_LoadFunction(handle, "wglMakeCurrent");
   125     _this->gl_data->wglShareLists = (BOOL(WINAPI *) (HGLRC, HGLRC))
   126         SDL_LoadFunction(handle, "wglShareLists");
   127 
   128     if (!_this->gl_data->wglGetProcAddress ||
   129         !_this->gl_data->wglCreateContext ||
   130         !_this->gl_data->wglDeleteContext ||
   131         !_this->gl_data->wglMakeCurrent) {
   132         return SDL_SetError("Could not retrieve OpenGL functions");
   133     }
   134 
   135     /* XXX Too sleazy? WIN_GL_InitExtensions looks for certain OpenGL
   136        extensions via SDL_GL_DeduceMaxSupportedESProfile. This uses
   137        SDL_GL_ExtensionSupported which in turn calls SDL_GL_GetProcAddress.
   138        However SDL_GL_GetProcAddress will fail if the library is not
   139        loaded; it checks for gl_config.driver_loaded > 0. To avoid this
   140        test failing, increment driver_loaded around the call to
   141        WIN_GLInitExtensions.
   142 
   143        Successful loading of the library is normally indicated by
   144        SDL_GL_LoadLibrary incrementing driver_loaded immediately after
   145        this function returns 0 to it.
   146 
   147        Alternatives to this are:
   148        - moving SDL_GL_DeduceMaxSupportedESProfile to both the WIN and
   149          X11 platforms while adding a function equivalent to
   150          SDL_GL_ExtensionSupported but which directly calls
   151          glGetProcAddress(). Having 3 copies of the
   152          SDL_GL_ExtensionSupported makes this alternative unattractive.
   153        - moving SDL_GL_DeduceMaxSupportedESProfile to a new file shared
   154          by the WIN and X11 platforms while adding a function equivalent
   155          to SDL_GL_ExtensionSupported. This is unattractive due to the
   156          number of project files that will need updating, plus there
   157          will be 2 copies of the SDL_GL_ExtensionSupported code.
   158        - Add a private equivalent of SDL_GL_ExtensionSupported to
   159          SDL_video.c.
   160        - Move the call to WIN_GL_InitExtensions back to WIN_CreateWindow
   161          and add a flag to gl_data to avoid multiple calls to this
   162          expensive function. This is probably the least objectionable
   163          alternative if this increment/decrement trick is unacceptable.
   164 
   165        Note that the driver_loaded > 0 check needs to remain in
   166        SDL_GL_ExtensionSupported and SDL_GL_GetProcAddress as they are
   167        public API functions.
   168     */
   169     ++_this->gl_config.driver_loaded;
   170     WIN_GL_InitExtensions(_this);
   171     --_this->gl_config.driver_loaded;
   172 
   173     return 0;
   174 }
   175 
   176 void *
   177 WIN_GL_GetProcAddress(_THIS, const char *proc)
   178 {
   179     void *func;
   180 
   181     /* This is to pick up extensions */
   182     func = _this->gl_data->wglGetProcAddress(proc);
   183     if (!func) {
   184         /* This is probably a normal GL function */
   185         func = GetProcAddress(_this->gl_config.dll_handle, proc);
   186     }
   187     return func;
   188 }
   189 
   190 void
   191 WIN_GL_UnloadLibrary(_THIS)
   192 {
   193     SDL_UnloadObject(_this->gl_config.dll_handle);
   194     _this->gl_config.dll_handle = NULL;
   195 
   196     /* Free OpenGL memory */
   197     SDL_free(_this->gl_data);
   198     _this->gl_data = NULL;
   199 }
   200 
   201 static void
   202 WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
   203 {
   204     SDL_zerop(pfd);
   205     pfd->nSize = sizeof(*pfd);
   206     pfd->nVersion = 1;
   207     pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
   208     if (_this->gl_config.double_buffer) {
   209         pfd->dwFlags |= PFD_DOUBLEBUFFER;
   210     }
   211     if (_this->gl_config.stereo) {
   212         pfd->dwFlags |= PFD_STEREO;
   213     }
   214     pfd->iLayerType = PFD_MAIN_PLANE;
   215     pfd->iPixelType = PFD_TYPE_RGBA;
   216     pfd->cRedBits = _this->gl_config.red_size;
   217     pfd->cGreenBits = _this->gl_config.green_size;
   218     pfd->cBlueBits = _this->gl_config.blue_size;
   219     pfd->cAlphaBits = _this->gl_config.alpha_size;
   220     if (_this->gl_config.buffer_size) {
   221         pfd->cColorBits =
   222             _this->gl_config.buffer_size - _this->gl_config.alpha_size;
   223     } else {
   224         pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
   225     }
   226     pfd->cAccumRedBits = _this->gl_config.accum_red_size;
   227     pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
   228     pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
   229     pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
   230     pfd->cAccumBits =
   231         (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
   232          pfd->cAccumAlphaBits);
   233     pfd->cDepthBits = _this->gl_config.depth_size;
   234     pfd->cStencilBits = _this->gl_config.stencil_size;
   235 }
   236 
   237 /* Choose the closest pixel format that meets or exceeds the target.
   238    FIXME: Should we weight any particular attribute over any other?
   239 */
   240 static int
   241 WIN_GL_ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * target)
   242 {
   243     PIXELFORMATDESCRIPTOR pfd;
   244     int count, index, best = 0;
   245     unsigned int dist, best_dist = ~0U;
   246 
   247     count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
   248 
   249     for (index = 1; index <= count; index++) {
   250 
   251         if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
   252             continue;
   253         }
   254 
   255         if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
   256             continue;
   257         }
   258 
   259         if (pfd.iLayerType != target->iLayerType) {
   260             continue;
   261         }
   262         if (pfd.iPixelType != target->iPixelType) {
   263             continue;
   264         }
   265 
   266         dist = 0;
   267 
   268         if (pfd.cColorBits < target->cColorBits) {
   269             continue;
   270         } else {
   271             dist += (pfd.cColorBits - target->cColorBits);
   272         }
   273         if (pfd.cRedBits < target->cRedBits) {
   274             continue;
   275         } else {
   276             dist += (pfd.cRedBits - target->cRedBits);
   277         }
   278         if (pfd.cGreenBits < target->cGreenBits) {
   279             continue;
   280         } else {
   281             dist += (pfd.cGreenBits - target->cGreenBits);
   282         }
   283         if (pfd.cBlueBits < target->cBlueBits) {
   284             continue;
   285         } else {
   286             dist += (pfd.cBlueBits - target->cBlueBits);
   287         }
   288         if (pfd.cAlphaBits < target->cAlphaBits) {
   289             continue;
   290         } else {
   291             dist += (pfd.cAlphaBits - target->cAlphaBits);
   292         }
   293         if (pfd.cAccumBits < target->cAccumBits) {
   294             continue;
   295         } else {
   296             dist += (pfd.cAccumBits - target->cAccumBits);
   297         }
   298         if (pfd.cAccumRedBits < target->cAccumRedBits) {
   299             continue;
   300         } else {
   301             dist += (pfd.cAccumRedBits - target->cAccumRedBits);
   302         }
   303         if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
   304             continue;
   305         } else {
   306             dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
   307         }
   308         if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
   309             continue;
   310         } else {
   311             dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
   312         }
   313         if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
   314             continue;
   315         } else {
   316             dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
   317         }
   318         if (pfd.cDepthBits < target->cDepthBits) {
   319             continue;
   320         } else {
   321             dist += (pfd.cDepthBits - target->cDepthBits);
   322         }
   323         if (pfd.cStencilBits < target->cStencilBits) {
   324             continue;
   325         } else {
   326             dist += (pfd.cStencilBits - target->cStencilBits);
   327         }
   328 
   329         if (dist < best_dist) {
   330             best = index;
   331             best_dist = dist;
   332         }
   333     }
   334 
   335     return best;
   336 }
   337 
   338 static SDL_bool
   339 HasExtension(const char *extension, const char *extensions)
   340 {
   341     const char *start;
   342     const char *where, *terminator;
   343 
   344     /* Extension names should not have spaces. */
   345     where = SDL_strchr(extension, ' ');
   346     if (where || *extension == '\0')
   347         return SDL_FALSE;
   348 
   349     if (!extensions)
   350         return SDL_FALSE;
   351 
   352     /* It takes a bit of care to be fool-proof about parsing the
   353      * OpenGL extensions string. Don't be fooled by sub-strings,
   354      * etc. */
   355 
   356     start = extensions;
   357 
   358     for (;;) {
   359         where = SDL_strstr(start, extension);
   360         if (!where)
   361             break;
   362 
   363         terminator = where + SDL_strlen(extension);
   364         if (where == start || *(where - 1) == ' ')
   365             if (*terminator == ' ' || *terminator == '\0')
   366                 return SDL_TRUE;
   367 
   368         start = terminator;
   369     }
   370     return SDL_FALSE;
   371 }
   372 
   373 void
   374 WIN_GL_InitExtensions(_THIS)
   375 {
   376     const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
   377     const char *extensions;
   378     HWND hwnd;
   379     HDC hdc;
   380     HGLRC hglrc;
   381     PIXELFORMATDESCRIPTOR pfd;
   382 
   383     if (!_this->gl_data) {
   384         return;
   385     }
   386 
   387     hwnd =
   388         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
   389         10, 10, NULL, NULL, SDL_Instance, NULL);
   390     if (!hwnd) {
   391         return;
   392     }
   393     WIN_PumpEvents(_this);
   394 
   395     hdc = GetDC(hwnd);
   396 
   397     WIN_GL_SetupPixelFormat(_this, &pfd);
   398 
   399     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
   400 
   401     hglrc = _this->gl_data->wglCreateContext(hdc);
   402     if (!hglrc) {
   403         return;
   404     }
   405     _this->gl_data->wglMakeCurrent(hdc, hglrc);
   406 
   407     wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
   408         _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
   409     if (wglGetExtensionsStringARB) {
   410         extensions = wglGetExtensionsStringARB(hdc);
   411     } else {
   412         extensions = NULL;
   413     }
   414 
   415     /* Check for WGL_ARB_pixel_format */
   416     _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
   417     if (HasExtension("WGL_ARB_pixel_format", extensions)) {
   418         _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
   419                                                    (HDC, const int *,
   420                                                     const FLOAT *, UINT,
   421                                                     int *, UINT *))
   422             WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
   423         _this->gl_data->wglGetPixelFormatAttribivARB =
   424             (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
   425             WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
   426 
   427         if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
   428             (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
   429             _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
   430         }
   431     }
   432 
   433     /* Check for WGL_EXT_swap_control */
   434     _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
   435     if (HasExtension("WGL_EXT_swap_control", extensions)) {
   436         _this->gl_data->wglSwapIntervalEXT =
   437             WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
   438         _this->gl_data->wglGetSwapIntervalEXT =
   439             WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
   440         if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
   441             _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
   442         }
   443     } else {
   444         _this->gl_data->wglSwapIntervalEXT = NULL;
   445         _this->gl_data->wglGetSwapIntervalEXT = NULL;
   446     }
   447 
   448     /* Check for WGL_EXT_create_context_es2_profile */
   449     if (HasExtension("WGL_EXT_create_context_es2_profile", extensions)) {
   450         SDL_GL_DeduceMaxSupportedESProfile(
   451             &_this->gl_data->es_profile_max_supported_version.major,
   452             &_this->gl_data->es_profile_max_supported_version.minor
   453         );
   454     }
   455 
   456     /* Check for WGL_ARB_context_flush_control */
   457     if (HasExtension("WGL_ARB_context_flush_control", extensions)) {
   458         _this->gl_data->HAS_WGL_ARB_context_flush_control = SDL_TRUE;
   459     }
   460 
   461     /* Check for WGL_ARB_create_context_robustness */
   462     if (HasExtension("WGL_ARB_create_context_robustness", extensions)) {
   463         _this->gl_data->HAS_WGL_ARB_create_context_robustness = SDL_TRUE;
   464     }
   465 
   466     _this->gl_data->wglMakeCurrent(hdc, NULL);
   467     _this->gl_data->wglDeleteContext(hglrc);
   468     ReleaseDC(hwnd, hdc);
   469     DestroyWindow(hwnd);
   470     WIN_PumpEvents(_this);
   471 }
   472 
   473 static int
   474 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
   475 {
   476     HWND hwnd;
   477     HDC hdc;
   478     PIXELFORMATDESCRIPTOR pfd;
   479     HGLRC hglrc;
   480     int pixel_format = 0;
   481     unsigned int matching;
   482 
   483     hwnd =
   484         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
   485                      10, 10, NULL, NULL, SDL_Instance, NULL);
   486     WIN_PumpEvents(_this);
   487 
   488     hdc = GetDC(hwnd);
   489 
   490     WIN_GL_SetupPixelFormat(_this, &pfd);
   491 
   492     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
   493 
   494     hglrc = _this->gl_data->wglCreateContext(hdc);
   495     if (hglrc) {
   496         _this->gl_data->wglMakeCurrent(hdc, hglrc);
   497 
   498         if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
   499             _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
   500                                                     1, &pixel_format,
   501                                                     &matching);
   502         }
   503 
   504         _this->gl_data->wglMakeCurrent(hdc, NULL);
   505         _this->gl_data->wglDeleteContext(hglrc);
   506     }
   507     ReleaseDC(hwnd, hdc);
   508     DestroyWindow(hwnd);
   509     WIN_PumpEvents(_this);
   510 
   511     return pixel_format;
   512 }
   513 
   514 /* actual work of WIN_GL_SetupWindow() happens here. */
   515 static int
   516 WIN_GL_SetupWindowInternal(_THIS, SDL_Window * window)
   517 {
   518     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   519     PIXELFORMATDESCRIPTOR pfd;
   520     int pixel_format = 0;
   521     int iAttribs[64];
   522     int *iAttr;
   523     int *iAccelAttr;
   524     float fAttribs[1] = { 0 };
   525 
   526     WIN_GL_SetupPixelFormat(_this, &pfd);
   527 
   528     /* setup WGL_ARB_pixel_format attribs */
   529     iAttr = &iAttribs[0];
   530 
   531     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   532     *iAttr++ = GL_TRUE;
   533     *iAttr++ = WGL_RED_BITS_ARB;
   534     *iAttr++ = _this->gl_config.red_size;
   535     *iAttr++ = WGL_GREEN_BITS_ARB;
   536     *iAttr++ = _this->gl_config.green_size;
   537     *iAttr++ = WGL_BLUE_BITS_ARB;
   538     *iAttr++ = _this->gl_config.blue_size;
   539 
   540     if (_this->gl_config.alpha_size) {
   541         *iAttr++ = WGL_ALPHA_BITS_ARB;
   542         *iAttr++ = _this->gl_config.alpha_size;
   543     }
   544 
   545     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
   546     *iAttr++ = _this->gl_config.double_buffer;
   547 
   548     *iAttr++ = WGL_DEPTH_BITS_ARB;
   549     *iAttr++ = _this->gl_config.depth_size;
   550 
   551     if (_this->gl_config.stencil_size) {
   552         *iAttr++ = WGL_STENCIL_BITS_ARB;
   553         *iAttr++ = _this->gl_config.stencil_size;
   554     }
   555 
   556     if (_this->gl_config.accum_red_size) {
   557         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   558         *iAttr++ = _this->gl_config.accum_red_size;
   559     }
   560 
   561     if (_this->gl_config.accum_green_size) {
   562         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   563         *iAttr++ = _this->gl_config.accum_green_size;
   564     }
   565 
   566     if (_this->gl_config.accum_blue_size) {
   567         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   568         *iAttr++ = _this->gl_config.accum_blue_size;
   569     }
   570 
   571     if (_this->gl_config.accum_alpha_size) {
   572         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   573         *iAttr++ = _this->gl_config.accum_alpha_size;
   574     }
   575 
   576     if (_this->gl_config.stereo) {
   577         *iAttr++ = WGL_STEREO_ARB;
   578         *iAttr++ = GL_TRUE;
   579     }
   580 
   581     if (_this->gl_config.multisamplebuffers) {
   582         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   583         *iAttr++ = _this->gl_config.multisamplebuffers;
   584     }
   585 
   586     if (_this->gl_config.multisamplesamples) {
   587         *iAttr++ = WGL_SAMPLES_ARB;
   588         *iAttr++ = _this->gl_config.multisamplesamples;
   589     }
   590 
   591     if (_this->gl_config.framebuffer_srgb_capable) {
   592         *iAttr++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   593         *iAttr++ = _this->gl_config.framebuffer_srgb_capable;
   594     }
   595 
   596     /* We always choose either FULL or NO accel on Windows, because of flaky
   597        drivers. If the app didn't specify, we use FULL, because that's
   598        probably what they wanted (and if you didn't care and got FULL, that's
   599        a perfectly valid result in any case). */
   600     *iAttr++ = WGL_ACCELERATION_ARB;
   601     iAccelAttr = iAttr;
   602     if (_this->gl_config.accelerated) {
   603         *iAttr++ = WGL_FULL_ACCELERATION_ARB;
   604     } else {
   605         *iAttr++ = WGL_NO_ACCELERATION_ARB;
   606     }
   607 
   608     *iAttr = 0;
   609 
   610     /* Choose and set the closest available pixel format */
   611     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   612 
   613     /* App said "don't care about accel" and FULL accel failed. Try NO. */
   614     if ( ( !pixel_format ) && ( _this->gl_config.accelerated < 0 ) ) {
   615         *iAccelAttr = WGL_NO_ACCELERATION_ARB;
   616         pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   617         *iAccelAttr = WGL_FULL_ACCELERATION_ARB;  /* if we try again. */
   618     }
   619     if (!pixel_format) {
   620         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
   621     }
   622     if (!pixel_format) {
   623         return SDL_SetError("No matching GL pixel format available");
   624     }
   625     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
   626         return WIN_SetError("SetPixelFormat()");
   627     }
   628     return 0;
   629 }
   630 
   631 int
   632 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
   633 {
   634     /* The current context is lost in here; save it and reset it. */
   635     SDL_Window *current_win = SDL_GL_GetCurrentWindow();
   636     SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
   637     const int retval = WIN_GL_SetupWindowInternal(_this, window);
   638     WIN_GL_MakeCurrent(_this, current_win, current_ctx);
   639     return retval;
   640 }
   641 
   642 SDL_bool
   643 WIN_GL_UseEGL(_THIS)
   644 {
   645     SDL_assert(_this->gl_data != NULL);
   646     SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   647 
   648     return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
   649             || _this->gl_config.major_version == 1 /* No WGL extension for OpenGL ES 1.x profiles. */
   650             || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
   651             || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
   652                 && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
   653 }
   654 
   655 SDL_GLContext
   656 WIN_GL_CreateContext(_THIS, SDL_Window * window)
   657 {
   658     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   659     HGLRC context, share_context;
   660 
   661     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && WIN_GL_UseEGL(_this)) {
   662 #if SDL_VIDEO_OPENGL_EGL        
   663         /* Switch to EGL based functions */
   664         WIN_GL_UnloadLibrary(_this);
   665         _this->GL_LoadLibrary = WIN_GLES_LoadLibrary;
   666         _this->GL_GetProcAddress = WIN_GLES_GetProcAddress;
   667         _this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
   668         _this->GL_CreateContext = WIN_GLES_CreateContext;
   669         _this->GL_MakeCurrent = WIN_GLES_MakeCurrent;
   670         _this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
   671         _this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
   672         _this->GL_SwapWindow = WIN_GLES_SwapWindow;
   673         _this->GL_DeleteContext = WIN_GLES_DeleteContext;
   674         
   675         if (WIN_GLES_LoadLibrary(_this, NULL) != 0) {
   676             return NULL;
   677         }
   678         
   679         return WIN_GLES_CreateContext(_this, window);
   680 #else
   681         SDL_SetError("SDL not configured with EGL support");
   682         return NULL;
   683 #endif
   684     }
   685 
   686     if (_this->gl_config.share_with_current_context) {
   687         share_context = (HGLRC)SDL_GL_GetCurrentContext();
   688     } else {
   689         share_context = 0;
   690     }
   691 
   692     if (_this->gl_config.major_version < 3 &&
   693         _this->gl_config.profile_mask == 0 &&
   694         _this->gl_config.flags == 0) {
   695         /* Create legacy context */
   696         context = _this->gl_data->wglCreateContext(hdc);
   697         if( share_context != 0 ) {
   698             _this->gl_data->wglShareLists(share_context, context);
   699         }
   700     } else {
   701         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
   702         HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
   703         if (!temp_context) {
   704             SDL_SetError("Could not create GL context");
   705             return NULL;
   706         }
   707 
   708         /* Make the context current */
   709         if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
   710             WIN_GL_DeleteContext(_this, temp_context);
   711             return NULL;
   712         }
   713 
   714         wglCreateContextAttribsARB =
   715             (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   716             wglGetProcAddress("wglCreateContextAttribsARB");
   717         if (!wglCreateContextAttribsARB) {
   718             SDL_SetError("GL 3.x is not supported");
   719             context = temp_context;
   720         } else {
   721         /* max 12 attributes plus terminator */
   722             int attribs[13] = {
   723                 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
   724                 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
   725                 0
   726             };
   727             int iattr = 4;
   728 
   729             /* SDL profile bits match WGL profile bits */
   730             if (_this->gl_config.profile_mask != 0) {
   731                 attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
   732                 attribs[iattr++] = _this->gl_config.profile_mask;
   733             }
   734 
   735             /* SDL flags match WGL flags */
   736             if (_this->gl_config.flags != 0) {
   737                 attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
   738                 attribs[iattr++] = _this->gl_config.flags;
   739             }
   740 
   741             /* only set if wgl extension is available */
   742             if (_this->gl_data->HAS_WGL_ARB_context_flush_control) {
   743                 attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB;
   744                 attribs[iattr++] = _this->gl_config.release_behavior ?
   745                                     WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
   746                                     WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   747             }
   748 
   749             /* only set if wgl extension is available */
   750             if (_this->gl_data->HAS_WGL_ARB_create_context_robustness) {
   751                 attribs[iattr++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
   752                 attribs[iattr++] = _this->gl_config.reset_notification ?
   753                                     WGL_LOSE_CONTEXT_ON_RESET_ARB :
   754                                     WGL_NO_RESET_NOTIFICATION_ARB;
   755             }
   756 
   757             attribs[iattr++] = 0;
   758 
   759             /* Create the GL 3.x context */
   760             context = wglCreateContextAttribsARB(hdc, share_context, attribs);
   761             /* Delete the GL 2.x context */
   762             _this->gl_data->wglDeleteContext(temp_context);
   763         }
   764     }
   765 
   766     if (!context) {
   767         WIN_SetError("Could not create GL context");
   768         return NULL;
   769     }
   770 
   771     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
   772         WIN_GL_DeleteContext(_this, context);
   773         return NULL;
   774     }
   775 
   776     return context;
   777 }
   778 
   779 int
   780 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   781 {
   782     HDC hdc;
   783 
   784     if (!_this->gl_data) {
   785         return SDL_SetError("OpenGL not initialized");
   786     }
   787 
   788     /* sanity check that higher level handled this. */
   789     SDL_assert(window || (!window && !context));
   790 
   791     /* Some Windows drivers freak out if hdc is NULL, even when context is
   792        NULL, against spec. Since hdc is _supposed_ to be ignored if context
   793        is NULL, we either use the current GL window, or do nothing if we
   794        already have no current context. */
   795     if (!window) {
   796         window = SDL_GL_GetCurrentWindow();
   797         if (!window) {
   798             SDL_assert(SDL_GL_GetCurrentContext() == NULL);
   799             return 0;  /* already done. */
   800         }
   801     }
   802 
   803     hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   804     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
   805         return WIN_SetError("wglMakeCurrent()");
   806     }
   807     return 0;
   808 }
   809 
   810 int
   811 WIN_GL_SetSwapInterval(_THIS, int interval)
   812 {
   813     if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
   814         return SDL_SetError("Negative swap interval unsupported in this GL");
   815     } else if (_this->gl_data->wglSwapIntervalEXT) {
   816         if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
   817             return WIN_SetError("wglSwapIntervalEXT()");
   818         }
   819     } else {
   820         return SDL_Unsupported();
   821     }
   822     return 0;
   823 }
   824 
   825 int
   826 WIN_GL_GetSwapInterval(_THIS)
   827 {
   828     int retval = 0;
   829     if (_this->gl_data->wglGetSwapIntervalEXT) {
   830         retval = _this->gl_data->wglGetSwapIntervalEXT();
   831     }
   832     return retval;
   833 }
   834 
   835 int
   836 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
   837 {
   838     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   839 
   840     if (!SwapBuffers(hdc)) {
   841         return WIN_SetError("SwapBuffers()");
   842     }
   843     return 0;
   844 }
   845 
   846 void
   847 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
   848 {
   849     if (!_this->gl_data) {
   850         return;
   851     }
   852     _this->gl_data->wglDeleteContext((HGLRC) context);
   853 }
   854 
   855 
   856 SDL_bool
   857 WIN_GL_SetPixelFormatFrom(_THIS, SDL_Window * fromWindow, SDL_Window * toWindow)
   858 {
   859     HDC hfromdc = ((SDL_WindowData *) fromWindow->driverdata)->hdc;
   860     HDC htodc = ((SDL_WindowData *) toWindow->driverdata)->hdc;
   861     BOOL result;
   862 
   863     /* get the pixel format of the fromWindow */
   864     int pixel_format = GetPixelFormat(hfromdc);
   865     PIXELFORMATDESCRIPTOR pfd;
   866     SDL_memset(&pfd, 0, sizeof(pfd));
   867     DescribePixelFormat(hfromdc, pixel_format, sizeof(pfd), &pfd);
   868 
   869     /* set the pixel format of the toWindow */
   870     result = SetPixelFormat(htodc, pixel_format, &pfd);
   871 
   872     return result ? SDL_TRUE : SDL_FALSE;
   873 }
   874 
   875 #endif /* SDL_VIDEO_OPENGL_WGL */
   876 
   877 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   878 
   879 /* vi: set ts=4 sw=4 expandtab: */