src/video/windows/SDL_windowsopengl.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 24 Aug 2017 21:30:53 -0400
changeset 11346 4d2bf1b340cd
parent 11332 e3797888c6f1
child 11347 7f254d0b7842
permissions -rw-r--r--
opengl: add support for GL_KHR_no_error.

This is completely untested!

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