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