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