Panda3D
Loading...
Searching...
No Matches
wglGraphicsStateGuardian.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file wglGraphicsStateGuardian.cxx
10 * @author drose
11 * @date 2003-01-27
12 */
13
15#include "config_wgldisplay.h"
16#include "wglGraphicsBuffer.h"
17#include "wglGraphicsPipe.h"
18#include "string_utils.h"
19#include <atomic>
20
21TypeHandle wglGraphicsStateGuardian::_type_handle;
22
23const char * const wglGraphicsStateGuardian::_twindow_class_name = "wglGraphicsStateGuardian";
24bool wglGraphicsStateGuardian::_twindow_class_registered = false;
25
26/**
27 *
28 */
29wglGraphicsStateGuardian::
30wglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
31 wglGraphicsStateGuardian *share_with) :
32 GLGraphicsStateGuardian(engine, pipe),
33 _share_with(share_with)
34{
35 _made_context = false;
36 _context = (HGLRC)nullptr;
37
38 _twindow = (HWND)0;
39 _twindow_dc = (HDC)0;
40
41 _pfnum = -1;
42 _pfnum_supports_pbuffer = false;
43 _pfnum_properties.clear();
44
45 _supports_pbuffer = false;
46 _supports_pixel_format = false;
47 _supports_wgl_multisample = false;
48 _supports_wgl_render_texture = false;
49
50 _wglCreateContextAttribsARB = nullptr;
51
52 get_gamma_table();
53}
54
55/**
56 *
57 */
58wglGraphicsStateGuardian::
59~wglGraphicsStateGuardian() {
60 release_twindow();
61 if (_context != (HGLRC)nullptr) {
62 wglDeleteContext(_context);
63 _context = (HGLRC)nullptr;
64 }
65}
66
67/**
68 * This is called by wglGraphicsWindow when it finds it cannot use the pfnum
69 * determined by the GSG. Assuming this pfnum corresponds to an "advanced"
70 * frame buffer determined by wglChoosePixelFormatARB, this asks the GSG to
71 * swap out that pfnum for the earlier, "preliminary" pfnum determined via
72 * DescribePixelFormat().
73 *
74 * This is a one-way operation. Once called, you can never go back to the
75 * advanced pfnum.
76 *
77 * This method returns true if a change was successfully made, or false if
78 * there was no second tier to fall back to.
79 */
81fail_pfnum() {
82 if (_pfnum == _pre_pfnum) {
83 return false;
84 }
85
86 _pfnum = _pre_pfnum;
87 _pfnum_supports_pbuffer = false;
88 _pfnum_properties = _pre_pfnum_properties;
89 return true;
90}
91
92/**
93 * Gets the FrameBufferProperties to match the indicated pixel format
94 * descriptor.
95 */
97get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum) {
98
99 PIXELFORMATDESCRIPTOR pfd;
100 ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
101 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
102 pfd.nVersion = 1;
103
104 DescribePixelFormat(hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
105
106 properties.clear();
107 properties.set_all_specified();
108
109 if (((pfd.dwFlags & PFD_SUPPORT_OPENGL) == 0)||
110 ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) == 0)) {
111 // Return without setting either RGB or Indexed Color. This indicates a
112 // window that can't do anything at all.
113 return;
114 }
115
116 if (pfd.iPixelType == PFD_TYPE_COLORINDEX) {
117 properties.set_indexed_color(1);
118 properties.set_color_bits(pfd.cColorBits);
119 properties.set_alpha_bits(pfd.cAlphaBits);
120 } else {
121 properties.set_rgb_color(1);
122 properties.set_rgba_bits(pfd.cRedBits, pfd.cGreenBits,
123 pfd.cBlueBits, pfd.cAlphaBits);
124 }
125
126 if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
127 properties.set_back_buffers(1);
128 }
129 if (pfd.dwFlags & PFD_STEREO) {
130 properties.set_stereo(1);
131 }
132 if (pfd.dwFlags & PFD_GENERIC_FORMAT) {
133 properties.set_force_software(1);
134 } else {
135 properties.set_force_hardware(1);
136 }
137
138 if (pfd.cDepthBits != 0) {
139 properties.set_depth_bits(pfd.cDepthBits);
140 }
141 if (pfd.cStencilBits != 0) {
142 properties.set_stencil_bits(pfd.cStencilBits);
143 }
144
145 // The basic API doesn't do accum or multisample.
146}
147
148/**
149 * Gets the FrameBufferProperties to match the indicated pixel format
150 * descriptor, using the WGL extensions.
151 */
154 HDC window_dc, int pfnum) {
155
156 static const int max_attrib_list = 32;
157 int iattrib_list[max_attrib_list];
158 int ivalue_list[max_attrib_list];
159 int ni = 0;
160
161 int acceleration_i, pixel_type_i, double_buffer_i, stereo_i,
162 color_bits_i, red_bits_i, green_bits_i, blue_bits_i, alpha_bits_i,
163 accum_bits_i, depth_bits_i, stencil_bits_i, multisamples_i,
164 srgb_capable_i;
165
166 iattrib_list[acceleration_i = ni++] = WGL_ACCELERATION_ARB;
167 iattrib_list[pixel_type_i = ni++] = WGL_PIXEL_TYPE_ARB;
168 iattrib_list[double_buffer_i = ni++] = WGL_DOUBLE_BUFFER_ARB;
169 iattrib_list[stereo_i = ni++] = WGL_STEREO_ARB;
170 iattrib_list[color_bits_i = ni++] = WGL_COLOR_BITS_ARB;
171 iattrib_list[red_bits_i = ni++] = WGL_RED_BITS_ARB;
172 iattrib_list[green_bits_i = ni++] = WGL_GREEN_BITS_ARB;
173 iattrib_list[blue_bits_i = ni++] = WGL_BLUE_BITS_ARB;
174 iattrib_list[alpha_bits_i = ni++] = WGL_ALPHA_BITS_ARB;
175 iattrib_list[accum_bits_i = ni++] = WGL_ACCUM_BITS_ARB;
176 iattrib_list[depth_bits_i = ni++] = WGL_DEPTH_BITS_ARB;
177 iattrib_list[stencil_bits_i = ni++] = WGL_STENCIL_BITS_ARB;
178 iattrib_list[srgb_capable_i = ni++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
179
180 if (_supports_wgl_multisample) {
181 iattrib_list[multisamples_i = ni++] = WGL_SAMPLES_ARB;
182 }
183
184 // Terminate the list.
185 nassertr(ni <= max_attrib_list, false);
186
187 if (!_wglGetPixelFormatAttribivARB(window_dc, pfnum, 0,
188 ni, iattrib_list, ivalue_list)) {
189 return false;
190 }
191
192 properties.clear();
193 properties.set_all_specified();
194
195 if (ivalue_list[acceleration_i] == WGL_NO_ACCELERATION_ARB) {
196 properties.set_force_software(true);
197 } else {
198 properties.set_force_hardware(true);
199 }
200
201 if (ivalue_list[pixel_type_i] == WGL_TYPE_COLORINDEX_ARB) {
202 properties.set_indexed_color(true);
203 properties.set_color_bits(ivalue_list[color_bits_i]);
204 properties.set_alpha_bits(ivalue_list[alpha_bits_i]);
205 } else {
206 properties.set_rgb_color(true);
207 properties.set_rgba_bits(ivalue_list[red_bits_i],
208 ivalue_list[green_bits_i],
209 ivalue_list[blue_bits_i],
210 ivalue_list[alpha_bits_i]);
211 }
212
213 if (ivalue_list[double_buffer_i]) {
214 properties.set_back_buffers(1);
215 }
216
217 if (ivalue_list[stereo_i]) {
218 properties.set_stereo(true);
219 }
220
221 if (ivalue_list[srgb_capable_i]) {
222 properties.set_srgb_color(true);
223 }
224
225 if (ivalue_list[accum_bits_i] != 0) {
226 properties.set_accum_bits(ivalue_list[accum_bits_i]);
227 }
228
229 if (ivalue_list[depth_bits_i] != 0) {
230 properties.set_depth_bits(ivalue_list[depth_bits_i]);
231 }
232
233 if (ivalue_list[stencil_bits_i] != 0) {
234 properties.set_stencil_bits(ivalue_list[stencil_bits_i]);
235 }
236
237 if (_supports_wgl_multisample) {
238 if (ivalue_list[multisamples_i] != 0) {
239 properties.set_multisamples(ivalue_list[multisamples_i]);
240 }
241 }
242
243 return true;
244}
245
246/**
247 * Selects a pixel format for all the windows and buffers that use this gsg.
248 */
251 bool need_pbuffer) {
252
253 // Choose best format available using DescribePixelFormat. In the process,
254 // we need a DC to examine the available pixel formats. We'll use the
255 // screen DC.
256
257 if (gl_force_pixfmt.has_value()) {
258 wgldisplay_cat.info()
259 << "overriding pixfmt choice with gl-force-pixfmt("
260 << gl_force_pixfmt << ")\n";
261 _pfnum = gl_force_pixfmt;
262 _pfnum_properties = properties;
263 _pfnum_supports_pbuffer = true;
264 return;
265 }
266
267 int best_pfnum = 0;
268 int best_quality = 0;
269 FrameBufferProperties best_prop;
270
271 HDC hdc = GetDC(nullptr);
272
273 int max_pfnum = DescribePixelFormat(hdc, 1, 0, nullptr);
274
275 for (int pfnum = 0; pfnum<max_pfnum; ++pfnum) {
277 get_properties(pfprop, hdc, pfnum);
278 int quality = pfprop.get_quality(properties);
279 if (quality > best_quality) {
280 best_pfnum = pfnum;
281 best_quality = quality;
282 best_prop = pfprop;
283 }
284 }
285
286 ReleaseDC(nullptr, hdc);
287
288 _pfnum = best_pfnum;
289 _pfnum_supports_pbuffer = false;
290 _pfnum_properties = best_prop;
291 _pre_pfnum = _pfnum;
292 _pre_pfnum_properties = _pfnum_properties;
293
294 if (best_quality == 0) {
295 wgldisplay_cat.error()
296 << "Could not find a usable pixel format.\n";
297 return;
298 }
299
300 if (wgldisplay_cat.is_debug()) {
301 wgldisplay_cat.debug()
302 << "Preliminary pixfmt #" << _pfnum << " = "
303 << _pfnum_properties << "\n";
304 }
305
306 // See whether or not the wgl extensions are available. This routine is
307 // called before "reset". So the extensions list is empty. We need to
308 // create a twindow, make it current, fetch the extensions temporarily, get
309 // the few extensions we need, then clear the extensions list again in
310 // preparation for the reset.
311
312 HDC twindow_dc = get_twindow_dc();
313 if (twindow_dc == 0) {
314 return;
315 }
316
317 HGLRC twindow_ctx = wglCreateContext(twindow_dc);
318 if (twindow_ctx == 0) {
319 return;
320 }
321
322 if (!wglGraphicsPipe::wgl_make_current(twindow_dc, twindow_ctx, nullptr)) {
323 wgldisplay_cat.error()
324 << "Failed to make WGL context current.\n";
325 wglDeleteContext(twindow_ctx);
326 return;
327 }
328
329 _extensions.clear();
330 save_extensions((const char *)GLP(GetString)(GL_EXTENSIONS));
331 get_extra_extensions();
332 _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
333 _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
334
335 if (has_extension("WGL_ARB_create_context")) {
336 _wglCreateContextAttribsARB =
337 (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
338 } else {
339 _wglCreateContextAttribsARB = nullptr;
340 }
341
342 _extensions.clear();
343
344 if (!_supports_pixel_format) {
345 wglDeleteContext(twindow_ctx);
346 return;
347 }
348
349 _wglGetPixelFormatAttribivARB =
350 (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
351 _wglGetPixelFormatAttribfvARB =
352 (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
353 _wglChoosePixelFormatARB =
354 (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
355
356 if (_wglGetPixelFormatAttribivARB == nullptr ||
357 _wglGetPixelFormatAttribfvARB == nullptr ||
358 _wglChoosePixelFormatARB == nullptr) {
359 wgldisplay_cat.error()
360 << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
361 wglDeleteContext(twindow_ctx);
362 return;
363 }
364
365 // Use the wgl extensions to find a better format.
366
367 static const int max_attrib_list = 64;
368 int iattrib_list[max_attrib_list];
369 float fattrib_list[max_attrib_list];
370 int ni = 0;
371 int nf = 0;
372
373 iattrib_list[ni++] = WGL_SUPPORT_OPENGL_ARB;
374 iattrib_list[ni++] = true;
375 iattrib_list[ni++] = WGL_PIXEL_TYPE_ARB;
376 iattrib_list[ni++] = WGL_TYPE_RGBA_ARB;
377
378 if (need_pbuffer) {
379 iattrib_list[ni++] = WGL_DRAW_TO_PBUFFER_ARB;
380 iattrib_list[ni++] = true;
381 if (_pfnum_properties.get_alpha_bits()) {
382 iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGBA_ARB;
383 iattrib_list[ni++] = true;
384 } else {
385 iattrib_list[ni++] = WGL_BIND_TO_TEXTURE_RGB_ARB;
386 iattrib_list[ni++] = true;
387 }
388 }
389
390 nassertv(ni < max_attrib_list && nf < max_attrib_list);
391 iattrib_list[ni] = 0;
392 fattrib_list[nf] = 0;
393
394 static const int max_pformats = 1024;
395 int pformat[max_pformats];
396 memset(pformat, 0, sizeof(pformat));
397 int nformats = 0;
398
399 if (!_wglChoosePixelFormatARB(twindow_dc, iattrib_list, fattrib_list,
400 max_pformats, pformat, (unsigned int *)&nformats)) {
401 nformats = 0;
402 }
403 nformats = std::min(nformats, max_pformats);
404
405 if (wgldisplay_cat.is_debug()) {
406 wgldisplay_cat.debug()
407 << "Found " << nformats << " advanced formats: [";
408 for (int i = 0; i < nformats; i++) {
409 wgldisplay_cat.debug(false)
410 << " " << pformat[i];
411 }
412 wgldisplay_cat.debug(false)
413 << " ]\n";
414 }
415
416 if (nformats > 0) {
417 if (need_pbuffer) {
418 best_quality = 0;
419 }
420
421 for (int i = 0; i < nformats; i++) {
423 if (get_properties_advanced(pfprop, twindow_dc, pformat[i])) {
424 int quality = pfprop.get_quality(properties);
425 if (quality > best_quality) {
426 best_pfnum = pformat[i];
427 best_quality = quality;
428 best_prop = pfprop;
429 }
430 }
431 }
432
433 if (!properties.get_srgb_color()) {
434 best_prop.set_srgb_color(false);
435 }
436
437 _pfnum = best_pfnum;
438 _pfnum_supports_pbuffer = need_pbuffer;
439 _pfnum_properties = best_prop;
440
441 if (wgldisplay_cat.is_debug()) {
442 wgldisplay_cat.debug()
443 << "Selected advanced pixfmt #" << _pfnum << " = "
444 << _pfnum_properties << "\n";
445 }
446 }
447
448 wglDeleteContext(twindow_ctx);
449 release_twindow();
450}
451
452/**
453 * Resets all internal state as if the gsg were newly created.
454 */
456reset() {
457 GLGraphicsStateGuardian::reset();
458
459 _supports_swap_control = has_extension("WGL_EXT_swap_control");
460
461 if (_supports_swap_control) {
462 _wglSwapIntervalEXT =
463 (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
464 if (_wglSwapIntervalEXT == nullptr) {
465 wgldisplay_cat.error()
466 << "Driver claims to support WGL_EXT_swap_control extension, but does not define all functions.\n";
467 _supports_swap_control = false;
468 }
469 }
470
471 if (_supports_swap_control) {
472 // Set the video-sync setting up front, if we have the extension that
473 // supports it.
474 _wglSwapIntervalEXT(sync_video ? 1 : 0);
475 }
476
477 _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
478
479 if (_supports_pbuffer) {
480 _wglCreatePbufferARB =
481 (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
482 _wglGetPbufferDCARB =
483 (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
484 _wglReleasePbufferDCARB =
485 (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
486 _wglDestroyPbufferARB =
487 (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
488 _wglQueryPbufferARB =
489 (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
490
491 if (_wglCreatePbufferARB == nullptr ||
492 _wglGetPbufferDCARB == nullptr ||
493 _wglReleasePbufferDCARB == nullptr ||
494 _wglDestroyPbufferARB == nullptr ||
495 _wglQueryPbufferARB == nullptr) {
496 wgldisplay_cat.error()
497 << "Driver claims to support WGL_ARB_pbuffer extension, but does not define all functions.\n";
498 _supports_pbuffer = false;
499 }
500 }
501
502 _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
503
504 if (_supports_pixel_format) {
505 _wglGetPixelFormatAttribivARB =
506 (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
507 _wglGetPixelFormatAttribfvARB =
508 (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
509 _wglChoosePixelFormatARB =
510 (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
511
512 if (_wglGetPixelFormatAttribivARB == nullptr ||
513 _wglGetPixelFormatAttribfvARB == nullptr ||
514 _wglChoosePixelFormatARB == nullptr) {
515 wgldisplay_cat.error()
516 << "Driver claims to support WGL_ARB_pixel_format extension, but does not define all functions.\n";
517 _supports_pixel_format = false;
518 }
519 }
520
521 _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
522
523 _supports_wgl_render_texture = has_extension("WGL_ARB_render_texture");
524
525 if (_supports_wgl_render_texture) {
526 _wglBindTexImageARB =
527 (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
528 _wglReleaseTexImageARB =
529 (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
530 _wglSetPbufferAttribARB =
531 (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
532 if (_wglBindTexImageARB == nullptr ||
533 _wglReleaseTexImageARB == nullptr ||
534 _wglSetPbufferAttribARB == nullptr) {
535 wgldisplay_cat.error()
536 << "Driver claims to support WGL_ARB_render_texture, but does not define all functions.\n";
537 _supports_wgl_render_texture = false;
538 }
539 }
540}
541
542/**
543 * This may be redefined by a derived class (e.g. glx or wgl) to get whatever
544 * further extensions strings may be appropriate to that interface, in
545 * addition to the GL extension strings return by glGetString().
546 */
547void wglGraphicsStateGuardian::
548get_extra_extensions() {
549 // This is a little bit tricky, since the query function is itself an
550 // extension.
551
552 // Look for the ARB flavor first, which wants one parameter, the HDC of the
553 // drawing context.
554 PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
555 (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
556 if (wglGetExtensionsStringARB != nullptr) {
557 HDC hdc = wglGetCurrentDC();
558 if (hdc != 0) {
559 save_extensions((const char *)wglGetExtensionsStringARB(hdc));
560 return;
561 }
562 }
563
564 // If that failed, look for the EXT flavor, which wants no parameters.
565 PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT =
566 (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT");
567 if (wglGetExtensionsStringEXT != nullptr) {
568 save_extensions((const char *)wglGetExtensionsStringEXT());
569 }
570}
571
572/**
573 * Returns the pointer to the GL extension function with the indicated name.
574 * It is the responsibility of the caller to ensure that the required
575 * extension is defined in the OpenGL runtime prior to calling this; it is an
576 * error to call this for a function that is not defined.
577 */
578void *wglGraphicsStateGuardian::
579do_get_extension_func(const char *name) {
580 return (void*) wglGetProcAddress(name);
581}
582
583/**
584 * Creates a suitable context for rendering into the given window. This
585 * should only be called from the draw thread.
586 */
587void wglGraphicsStateGuardian::
588make_context(HDC hdc) {
589 // We should only call this once for a particular GSG.
590 nassertv(!_made_context);
591
592 _made_context = true;
593
594 // Attempt to create a context.
595 wglGraphicsPipe::_current_valid = false;
596
597 if (_wglCreateContextAttribsARB != nullptr) {
598 // We have a fancier version of wglCreateContext that allows us to specify
599 // what kind of OpenGL context we would like.
600 int attrib_list[32];
601 int n = 0;
602 attrib_list[0] = 0;
603
604 if (gl_version.get_num_words() > 0) {
605 attrib_list[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
606 attrib_list[n++] = gl_version[0];
607 if (gl_version.get_num_words() > 1) {
608 attrib_list[n++] = WGL_CONTEXT_MINOR_VERSION_ARB;
609 attrib_list[n++] = gl_version[1];
610 }
611 }
612 int flags = 0;
613 if (gl_debug) {
614 flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
615 }
616 if (gl_forward_compatible) {
617 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
618 if (gl_version.get_num_words() == 0 || gl_version[0] < 2) {
619 wgldisplay_cat.error()
620 << "gl-forward-compatible requires gl-version >= 3 0\n";
621 }
622 }
623 if (flags != 0) {
624 attrib_list[n++] = WGL_CONTEXT_FLAGS_ARB;
625 attrib_list[n++] = flags;
626 }
627#ifndef SUPPORT_FIXED_FUNCTION
628 attrib_list[n++] = WGL_CONTEXT_PROFILE_MASK_ARB;
629 attrib_list[n++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
630#endif
631 attrib_list[n] = 0;
632
633 _context = _wglCreateContextAttribsARB(hdc, 0, attrib_list);
634 } else {
635 _context = wglCreateContext(hdc);
636 }
637
638 if (_context == nullptr) {
639 wgldisplay_cat.error()
640 << "Could not create GL context.\n";
641 _is_valid = false;
642 return;
643 }
644
645 // Now share texture context with the indicated GSG.
646 if (_share_with != nullptr) {
647 HGLRC share_context = _share_with->get_share_context();
648 if (share_context == nullptr) {
649 // Whoops, the target context hasn't yet made its own context. In that
650 // case, it will share context with us.
651 _share_with->redirect_share_pool(this);
652
653 } else {
654 if (!wglShareLists(share_context, _context)) {
655 wgldisplay_cat.error()
656 << "Could not share texture contexts between wglGraphicsStateGuardians.\n";
657 // Too bad we couldn't detect this error sooner. Now there's really
658 // no way to tell the application it's hosed.
659 _is_valid = false;
660
661 } else {
662 _prepared_objects = _share_with->get_prepared_objects();
663 }
664 }
665
666 _share_with = nullptr;
667 }
668}
669
670/**
671 * Returns a wgl context handle for the purpose of sharing texture context
672 * with this GSG. This will either be the GSG's own context handle, if it
673 * exists yet, or the context handle of some other GSG that this GSG is
674 * planning to share with. If this returns NULL, none of the GSG's in this
675 * share pool have yet created their context.
676 */
677HGLRC wglGraphicsStateGuardian::
678get_share_context() const {
679 if (_made_context) {
680 return _context;
681 }
682 if (_share_with != nullptr) {
683 return _share_with->get_share_context();
684 }
685 return nullptr;
686}
687
688/**
689 * Directs the GSG (along with all GSG's it is planning to share a texture
690 * context with) to share texture context with the indicated GSG.
691 *
692 * This assumes that this GSG's context has not yet been created, and neither
693 * have any of the GSG's it is planning to share texture context with; but the
694 * graphics context for the indicated GSG has already been created.
695 */
696void wglGraphicsStateGuardian::
697redirect_share_pool(wglGraphicsStateGuardian *share_with) {
698 nassertv(!_made_context);
699 if (_share_with != nullptr) {
700 _share_with->redirect_share_pool(share_with);
701 } else {
702 _share_with = share_with;
703 }
704}
705
706/**
707 * Creates an invisible window to associate with the GL context, even if we
708 * are not going to use it. This is necessary because in the Windows OpenGL
709 * API, we have to create window before we can create a GL context--even
710 * before we can ask about what GL extensions are available!
711 */
712bool wglGraphicsStateGuardian::
713make_twindow() {
714 release_twindow();
715
716 DWORD window_style = 0;
717
718 register_twindow_class();
719 HINSTANCE hinstance = GetModuleHandle(nullptr);
720 _twindow = CreateWindow(_twindow_class_name, "twindow", window_style,
721 0, 0, 1, 1, nullptr, nullptr, hinstance, 0);
722
723 if (!_twindow) {
724 wgldisplay_cat.error()
725 << "CreateWindow() failed!" << std::endl;
726 return false;
727 }
728
729 ShowWindow(_twindow, SW_HIDE);
730
731 _twindow_dc = GetDC(_twindow);
732
733 PIXELFORMATDESCRIPTOR pixelformat;
734 if (!SetPixelFormat(_twindow_dc, _pfnum, &pixelformat)) {
735 wgldisplay_cat.error()
736 << "SetPixelFormat(" << _pfnum << ") failed after window create\n";
737 release_twindow();
738 return false;
739 }
740
741 return true;
742}
743
744/**
745 * Closes and frees the resources associated with the temporary window created
746 * by a previous call to make_twindow().
747 */
748void wglGraphicsStateGuardian::
749release_twindow() {
750 if (_twindow_dc) {
751 ReleaseDC(_twindow, _twindow_dc);
752 _twindow_dc = 0;
753 }
754 if (_twindow) {
755 DestroyWindow(_twindow);
756 _twindow = 0;
757 }
758}
759
760/**
761 * Registers a Window class for the twindow created by all wglGraphicsPipes.
762 * This only needs to be done once per session.
763 */
764void wglGraphicsStateGuardian::
765register_twindow_class() {
766 if (_twindow_class_registered) {
767 return;
768 }
769
770 WNDCLASS wc;
771
772 HINSTANCE instance = GetModuleHandle(nullptr);
773
774 // Clear before filling in window structure!
775 ZeroMemory(&wc, sizeof(WNDCLASS));
776 wc.style = CS_OWNDC;
777 wc.lpfnWndProc = DefWindowProc;
778 wc.hInstance = instance;
779 wc.lpszClassName = _twindow_class_name;
780
781 if (!RegisterClass(&wc)) {
782 wgldisplay_cat.error()
783 << "could not register window class!" << std::endl;
784 return;
785 }
786 _twindow_class_registered = true;
787}
788
789#define GAMMA_1 (255.0 * 256.0)
790
791static bool _gamma_table_initialized = false;
792static unsigned short _original_gamma_table [256 * 3];
793
794void _create_gamma_table_wgl (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
795 int i;
796 double gamma_correction;
797
798 if (gamma <= 0.0) {
799 // avoid divide by zero and negative exponents
800 gamma = 1.0;
801 }
802 gamma_correction = 1.0 / (double) gamma;
803
804 for (i = 0; i < 256; i++) {
805 double r;
806 double g;
807 double b;
808
809 if (original_red_table) {
810 r = (double) original_red_table [i] / GAMMA_1;
811 g = (double) original_green_table [i] / GAMMA_1;
812 b = (double) original_blue_table [i] / GAMMA_1;
813 }
814 else {
815 r = ((double) i / 255.0);
816 g = r;
817 b = r;
818 }
819
820 r = pow (r, gamma_correction);
821 g = pow (g, gamma_correction);
822 b = pow (b, gamma_correction);
823
824 if (r > 1.00) {
825 r = 1.0;
826 }
827 if (g > 1.00) {
828 g = 1.0;
829 }
830 if (b > 1.00) {
831 b = 1.0;
832 }
833
834 r = r * GAMMA_1;
835 g = g * GAMMA_1;
836 b = b * GAMMA_1;
837
838 red_table [i] = r;
839 green_table [i] = g;
840 blue_table [i] = b;
841 }
842}
843
844/**
845 * Static function for getting the original gamma.
846 */
848get_gamma_table(void) {
849 bool get;
850
851 get = false;
852 if (_gamma_table_initialized == false) {
853 HDC hdc = GetDC(nullptr);
854
855 if (hdc) {
856 if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) {
857 _gamma_table_initialized = true;
858 get = true;
859 }
860
861 ReleaseDC (nullptr, hdc);
862 }
863 }
864
865 return get;
866}
867
868/**
869 * Static function for setting gamma which is needed for atexit.
870 */
872static_set_gamma(bool restore, PN_stdfloat gamma) {
873 bool set;
874 HDC hdc = GetDC(nullptr);
875
876 set = false;
877 if (hdc) {
878 unsigned short ramp [256 * 3];
879
880 if (restore && _gamma_table_initialized) {
881 _create_gamma_table_wgl (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
882 }
883 else {
884 _create_gamma_table_wgl (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
885 }
886
887 if (SetDeviceGammaRamp (hdc, ramp)) {
888 set = true;
889
890 // Register an atexit handler
891 static std::atomic_flag gamma_modified = ATOMIC_FLAG_INIT;
892 if (!gamma_modified.test_and_set()) {
893 atexit(atexit_function);
894 }
895 }
896
897 ReleaseDC (nullptr, hdc);
898 }
899
900 return set;
901}
902
903/**
904 * Non static version of setting gamma. Returns true on success.
905 */
907set_gamma(PN_stdfloat gamma) {
908 bool set;
909
910 set = static_set_gamma(false, gamma);
911 if (set) {
912 _gamma = gamma;
913 }
914
915 return set;
916}
917
918/**
919 * Restore original gamma.
920 */
925
926/**
927 * This function is passed to the atexit function.
928 */
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set,...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
set_color_bits
Sets the number of requested color bits as a single number that represents the sum of the individual ...
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
int get_quality(const FrameBufferProperties &reqs) const
Assumes that these properties are a description of a window.
void set_all_specified()
Marks all bits as having been specified.
This class is the main interface to controlling the render process.
An object to create GraphicsOutputs that share a particular 3-D API.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
HDC get_twindow_dc()
Returns the DC associated with the temporary, invisible window that was created with the gsg to query...
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
virtual void reset()
Resets all internal state as if the gsg were newly created.
void get_properties(FrameBufferProperties &properties, HDC hdc, int pfnum)
Gets the FrameBufferProperties to match the indicated pixel format descriptor.
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer)
Selects a pixel format for all the windows and buffers that use this gsg.
bool get_properties_advanced(FrameBufferProperties &properties, HDC hdc, int pfnum)
Gets the FrameBufferProperties to match the indicated pixel format descriptor, using the WGL extensio...
static bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
static bool get_gamma_table(void)
Static function for getting the original gamma.
static void atexit_function(void)
This function is passed to the atexit function.
void restore_gamma()
Restore original gamma.
bool fail_pfnum()
This is called by wglGraphicsWindow when it finds it cannot use the pfnum determined by the GSG.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.