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