src/video/windows/SDL_windowsopengl.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 10 Jan 2017 08:54:33 -0800
changeset 10806 36f40b8cc979
parent 10737 3406a0f8b041
child 11332 e3797888c6f1
permissions -rw-r--r--
Fixed bugs 2570, 3145, improved OpenGL ES context support on Windows and X11

Mark Callow

The attached patch does the following for the X11 and Windows platforms, the only ones where SDL attempts to use context_create_es_profile:

- Adds SDL_HINT_OPENGL_ES_DRIVER by which the application can
say to use the OpenGL ES driver & EGL rather than the Open GL
driver. (For bug #2570)
- Adds code to {WIN,X11}_GL_InitExtensions to determine the maximum
OpenGL ES version supported by the OpenGL driver (for bug #3145)
- Modifies the test that determines whether to use the OpenGL
driver or the real OpenGL ES driver to take into account the
hint, the requested and supported ES version and whether ES 1.X
is being requested. (For bug #2570 & bug #3145)
- Enables the testgles2 test for __WINDOWS__ and __LINUX__ and adds
the test to the VisualC projects.

With the fix in place I have run testdraw2, testgl and testgles2 without any issues and have run my own apps that use OpenGL, OpenGL ES 3 and OpenGL ES 1.1.
     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 GLX_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     _this->gl_data->wglMakeCurrent(hdc, NULL);
   462     _this->gl_data->wglDeleteContext(hglrc);
   463     ReleaseDC(hwnd, hdc);
   464     DestroyWindow(hwnd);
   465     WIN_PumpEvents(_this);
   466 }
   467 
   468 static int
   469 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
   470 {
   471     HWND hwnd;
   472     HDC hdc;
   473     PIXELFORMATDESCRIPTOR pfd;
   474     HGLRC hglrc;
   475     int pixel_format = 0;
   476     unsigned int matching;
   477 
   478     hwnd =
   479         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
   480                      10, 10, NULL, NULL, SDL_Instance, NULL);
   481     WIN_PumpEvents(_this);
   482 
   483     hdc = GetDC(hwnd);
   484 
   485     WIN_GL_SetupPixelFormat(_this, &pfd);
   486 
   487     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
   488 
   489     hglrc = _this->gl_data->wglCreateContext(hdc);
   490     if (hglrc) {
   491         _this->gl_data->wglMakeCurrent(hdc, hglrc);
   492 
   493         if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
   494             _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
   495                                                     1, &pixel_format,
   496                                                     &matching);
   497         }
   498 
   499         _this->gl_data->wglMakeCurrent(hdc, NULL);
   500         _this->gl_data->wglDeleteContext(hglrc);
   501     }
   502     ReleaseDC(hwnd, hdc);
   503     DestroyWindow(hwnd);
   504     WIN_PumpEvents(_this);
   505 
   506     return pixel_format;
   507 }
   508 
   509 /* actual work of WIN_GL_SetupWindow() happens here. */
   510 static int
   511 WIN_GL_SetupWindowInternal(_THIS, SDL_Window * window)
   512 {
   513     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   514     PIXELFORMATDESCRIPTOR pfd;
   515     int pixel_format = 0;
   516     int iAttribs[64];
   517     int *iAttr;
   518     int *iAccelAttr;
   519     float fAttribs[1] = { 0 };
   520 
   521     WIN_GL_SetupPixelFormat(_this, &pfd);
   522 
   523     /* setup WGL_ARB_pixel_format attribs */
   524     iAttr = &iAttribs[0];
   525 
   526     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
   527     *iAttr++ = GL_TRUE;
   528     *iAttr++ = WGL_RED_BITS_ARB;
   529     *iAttr++ = _this->gl_config.red_size;
   530     *iAttr++ = WGL_GREEN_BITS_ARB;
   531     *iAttr++ = _this->gl_config.green_size;
   532     *iAttr++ = WGL_BLUE_BITS_ARB;
   533     *iAttr++ = _this->gl_config.blue_size;
   534 
   535     if (_this->gl_config.alpha_size) {
   536         *iAttr++ = WGL_ALPHA_BITS_ARB;
   537         *iAttr++ = _this->gl_config.alpha_size;
   538     }
   539 
   540     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
   541     *iAttr++ = _this->gl_config.double_buffer;
   542 
   543     *iAttr++ = WGL_DEPTH_BITS_ARB;
   544     *iAttr++ = _this->gl_config.depth_size;
   545 
   546     if (_this->gl_config.stencil_size) {
   547         *iAttr++ = WGL_STENCIL_BITS_ARB;
   548         *iAttr++ = _this->gl_config.stencil_size;
   549     }
   550 
   551     if (_this->gl_config.accum_red_size) {
   552         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
   553         *iAttr++ = _this->gl_config.accum_red_size;
   554     }
   555 
   556     if (_this->gl_config.accum_green_size) {
   557         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
   558         *iAttr++ = _this->gl_config.accum_green_size;
   559     }
   560 
   561     if (_this->gl_config.accum_blue_size) {
   562         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
   563         *iAttr++ = _this->gl_config.accum_blue_size;
   564     }
   565 
   566     if (_this->gl_config.accum_alpha_size) {
   567         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
   568         *iAttr++ = _this->gl_config.accum_alpha_size;
   569     }
   570 
   571     if (_this->gl_config.stereo) {
   572         *iAttr++ = WGL_STEREO_ARB;
   573         *iAttr++ = GL_TRUE;
   574     }
   575 
   576     if (_this->gl_config.multisamplebuffers) {
   577         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
   578         *iAttr++ = _this->gl_config.multisamplebuffers;
   579     }
   580 
   581     if (_this->gl_config.multisamplesamples) {
   582         *iAttr++ = WGL_SAMPLES_ARB;
   583         *iAttr++ = _this->gl_config.multisamplesamples;
   584     }
   585 
   586     if (_this->gl_config.framebuffer_srgb_capable) {
   587         *iAttr++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
   588         *iAttr++ = _this->gl_config.framebuffer_srgb_capable;
   589     }
   590 
   591     /* We always choose either FULL or NO accel on Windows, because of flaky
   592        drivers. If the app didn't specify, we use FULL, because that's
   593        probably what they wanted (and if you didn't care and got FULL, that's
   594        a perfectly valid result in any case). */
   595     *iAttr++ = WGL_ACCELERATION_ARB;
   596     iAccelAttr = iAttr;
   597     if (_this->gl_config.accelerated) {
   598         *iAttr++ = WGL_FULL_ACCELERATION_ARB;
   599     } else {
   600         *iAttr++ = WGL_NO_ACCELERATION_ARB;
   601     }
   602 
   603     *iAttr = 0;
   604 
   605     /* Choose and set the closest available pixel format */
   606     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   607 
   608     /* App said "don't care about accel" and FULL accel failed. Try NO. */
   609     if ( ( !pixel_format ) && ( _this->gl_config.accelerated < 0 ) ) {
   610         *iAccelAttr = WGL_NO_ACCELERATION_ARB;
   611         pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
   612         *iAccelAttr = WGL_FULL_ACCELERATION_ARB;  /* if we try again. */
   613     }
   614     if (!pixel_format) {
   615         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
   616     }
   617     if (!pixel_format) {
   618         return SDL_SetError("No matching GL pixel format available");
   619     }
   620     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
   621         return WIN_SetError("SetPixelFormat()");
   622     }
   623     return 0;
   624 }
   625 
   626 int
   627 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
   628 {
   629     /* The current context is lost in here; save it and reset it. */
   630     SDL_Window *current_win = SDL_GL_GetCurrentWindow();
   631     SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
   632     const int retval = WIN_GL_SetupWindowInternal(_this, window);
   633     WIN_GL_MakeCurrent(_this, current_win, current_ctx);
   634     return retval;
   635 }
   636 
   637 SDL_bool
   638 WIN_GL_UseEGL(_THIS)
   639 {
   640     SDL_assert(_this->gl_data != NULL);
   641     SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
   642 
   643     return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE)
   644             || _this->gl_config.major_version == 1 /* No WGL extension for OpenGL ES 1.x profiles. */
   645             || _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major
   646             || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major
   647                 && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
   648 }
   649 
   650 SDL_GLContext
   651 WIN_GL_CreateContext(_THIS, SDL_Window * window)
   652 {
   653     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   654     HGLRC context, share_context;
   655 
   656     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && WIN_GL_UseEGL(_this)) {
   657 #if SDL_VIDEO_OPENGL_EGL        
   658         /* Switch to EGL based functions */
   659         WIN_GL_UnloadLibrary(_this);
   660         _this->GL_LoadLibrary = WIN_GLES_LoadLibrary;
   661         _this->GL_GetProcAddress = WIN_GLES_GetProcAddress;
   662         _this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
   663         _this->GL_CreateContext = WIN_GLES_CreateContext;
   664         _this->GL_MakeCurrent = WIN_GLES_MakeCurrent;
   665         _this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
   666         _this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
   667         _this->GL_SwapWindow = WIN_GLES_SwapWindow;
   668         _this->GL_DeleteContext = WIN_GLES_DeleteContext;
   669         
   670         if (WIN_GLES_LoadLibrary(_this, NULL) != 0) {
   671             return NULL;
   672         }
   673         
   674         return WIN_GLES_CreateContext(_this, window);
   675 #else
   676         SDL_SetError("SDL not configured with EGL support");
   677         return NULL;
   678 #endif
   679     }
   680 
   681     if (_this->gl_config.share_with_current_context) {
   682         share_context = (HGLRC)SDL_GL_GetCurrentContext();
   683     } else {
   684         share_context = 0;
   685     }
   686 
   687     if (_this->gl_config.major_version < 3 &&
   688         _this->gl_config.profile_mask == 0 &&
   689         _this->gl_config.flags == 0) {
   690         /* Create legacy context */
   691         context = _this->gl_data->wglCreateContext(hdc);
   692         if( share_context != 0 ) {
   693             _this->gl_data->wglShareLists(share_context, context);
   694         }
   695     } else {
   696         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
   697         HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
   698         if (!temp_context) {
   699             SDL_SetError("Could not create GL context");
   700             return NULL;
   701         }
   702 
   703         /* Make the context current */
   704         if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
   705             WIN_GL_DeleteContext(_this, temp_context);
   706             return NULL;
   707         }
   708 
   709         wglCreateContextAttribsARB =
   710             (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
   711             wglGetProcAddress("wglCreateContextAttribsARB");
   712         if (!wglCreateContextAttribsARB) {
   713             SDL_SetError("GL 3.x is not supported");
   714             context = temp_context;
   715         } else {
   716         /* max 10 attributes plus terminator */
   717             int attribs[11] = {
   718                 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
   719                 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
   720                 0
   721             };
   722             int iattr = 4;
   723 
   724             /* SDL profile bits match WGL profile bits */
   725             if (_this->gl_config.profile_mask != 0) {
   726                 attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
   727                 attribs[iattr++] = _this->gl_config.profile_mask;
   728             }
   729 
   730             /* SDL flags match WGL flags */
   731             if (_this->gl_config.flags != 0) {
   732                 attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
   733                 attribs[iattr++] = _this->gl_config.flags;
   734             }
   735 
   736             /* only set if wgl extension is available */
   737             if (_this->gl_data->HAS_WGL_ARB_context_flush_control) {
   738                 attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB;
   739                 attribs[iattr++] = _this->gl_config.release_behavior ?
   740                                     WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
   741                                     WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
   742             }
   743 
   744             attribs[iattr++] = 0;
   745 
   746             /* Create the GL 3.x context */
   747             context = wglCreateContextAttribsARB(hdc, share_context, attribs);
   748             /* Delete the GL 2.x context */
   749             _this->gl_data->wglDeleteContext(temp_context);
   750         }
   751     }
   752 
   753     if (!context) {
   754         WIN_SetError("Could not create GL context");
   755         return NULL;
   756     }
   757 
   758     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
   759         WIN_GL_DeleteContext(_this, context);
   760         return NULL;
   761     }
   762 
   763     return context;
   764 }
   765 
   766 int
   767 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
   768 {
   769     HDC hdc;
   770 
   771     if (!_this->gl_data) {
   772         return SDL_SetError("OpenGL not initialized");
   773     }
   774 
   775     /* sanity check that higher level handled this. */
   776     SDL_assert(window || (!window && !context));
   777 
   778     /* Some Windows drivers freak out if hdc is NULL, even when context is
   779        NULL, against spec. Since hdc is _supposed_ to be ignored if context
   780        is NULL, we either use the current GL window, or do nothing if we
   781        already have no current context. */
   782     if (!window) {
   783         window = SDL_GL_GetCurrentWindow();
   784         if (!window) {
   785             SDL_assert(SDL_GL_GetCurrentContext() == NULL);
   786             return 0;  /* already done. */
   787         }
   788     }
   789 
   790     hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   791     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
   792         return WIN_SetError("wglMakeCurrent()");
   793     }
   794     return 0;
   795 }
   796 
   797 int
   798 WIN_GL_SetSwapInterval(_THIS, int interval)
   799 {
   800     if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
   801         return SDL_SetError("Negative swap interval unsupported in this GL");
   802     } else if (_this->gl_data->wglSwapIntervalEXT) {
   803         if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
   804             return WIN_SetError("wglSwapIntervalEXT()");
   805         }
   806     } else {
   807         return SDL_Unsupported();
   808     }
   809     return 0;
   810 }
   811 
   812 int
   813 WIN_GL_GetSwapInterval(_THIS)
   814 {
   815     int retval = 0;
   816     if (_this->gl_data->wglGetSwapIntervalEXT) {
   817         retval = _this->gl_data->wglGetSwapIntervalEXT();
   818     }
   819     return retval;
   820 }
   821 
   822 int
   823 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
   824 {
   825     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
   826 
   827     if (!SwapBuffers(hdc)) {
   828         return WIN_SetError("SwapBuffers()");
   829     }
   830     return 0;
   831 }
   832 
   833 void
   834 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
   835 {
   836     if (!_this->gl_data) {
   837         return;
   838     }
   839     _this->gl_data->wglDeleteContext((HGLRC) context);
   840 }
   841 
   842 
   843 SDL_bool
   844 WIN_GL_SetPixelFormatFrom(_THIS, SDL_Window * fromWindow, SDL_Window * toWindow)
   845 {
   846     HDC hfromdc = ((SDL_WindowData *) fromWindow->driverdata)->hdc;
   847     HDC htodc = ((SDL_WindowData *) toWindow->driverdata)->hdc;
   848     BOOL result;
   849 
   850     /* get the pixel format of the fromWindow */
   851     int pixel_format = GetPixelFormat(hfromdc);
   852     PIXELFORMATDESCRIPTOR pfd;
   853     SDL_memset(&pfd, 0, sizeof(pfd));
   854     DescribePixelFormat(hfromdc, pixel_format, sizeof(pfd), &pfd);
   855 
   856     /* set the pixel format of the toWindow */
   857     result = SetPixelFormat(htodc, pixel_format, &pfd);
   858 
   859     return result ? SDL_TRUE : SDL_FALSE;
   860 }
   861 
   862 #endif /* SDL_VIDEO_OPENGL_WGL */
   863 
   864 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   865 
   866 /* vi: set ts=4 sw=4 expandtab: */