Panda3D
Loading...
Searching...
No Matches
wglGraphicsWindow.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 wglGraphicsWindow.cxx
10 * @author drose
11 * @date 2002-12-20
12 */
13
14#include "wglGraphicsWindow.h"
15#include "config_wgldisplay.h"
16#include "config_windisplay.h"
17#include "wglGraphicsPipe.h"
18#include "pStatTimer.h"
19#include "glgsg.h"
21
22#include <wingdi.h>
23
24TypeHandle wglGraphicsWindow::_type_handle;
25
26/**
27 *
28 */
29wglGraphicsWindow::
30wglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
31 const std::string &name,
32 const FrameBufferProperties &fb_prop,
33 const WindowProperties &win_prop,
34 int flags,
36 GraphicsOutput *host) :
37 WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
38{
39 _hdc = (HDC)0;
40}
41
42/**
43 *
44 */
45wglGraphicsWindow::
46~wglGraphicsWindow() {
47}
48
49/**
50 * This function will be called within the draw thread before beginning
51 * rendering for a given frame. It should do whatever setup is required, and
52 * return true if the frame should be rendered, or false if it should be
53 * skipped.
54 */
56begin_frame(FrameMode mode, Thread *current_thread) {
57
58 begin_frame_spam(mode);
59 if (_gsg == nullptr) {
60 return false;
61 }
62
63 if (!get_unexposed_draw() && !_got_expose_event) {
64 if (wgldisplay_cat.is_spam()) {
65 wgldisplay_cat.spam()
66 << "Not drawing " << this << ": unexposed.\n";
67 }
68 return false;
69 }
70
71 if (wgldisplay_cat.is_spam()) {
72 wgldisplay_cat.spam()
73 << "Drawing " << this << ": exposed.\n";
74 }
75
77 DCAST_INTO_R(wglgsg, _gsg, false);
78
79 HGLRC context = wglgsg->get_context(_hdc);
80 nassertr(context, false);
81
82 if (!wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector)) {
83 wgldisplay_cat.error()
84 << "Failed to make WGL context current.\n";
85 return false;
86 }
87 wglgsg->reset_if_new();
88
89 if (mode == FM_render) {
90 wglgsg->push_group_marker(std::string("wglGraphicsWindow ") + get_name());
91 clear_cube_map_selection();
92 }
93
94 _gsg->set_current_properties(&get_fb_properties());
95 return _gsg->begin_frame(current_thread);
96}
97
98/**
99 * This function will be called within the draw thread after rendering is
100 * completed for a given frame. It should do whatever finalization is
101 * required.
102 */
104end_frame(FrameMode mode, Thread *current_thread) {
105 end_frame_spam(mode);
106
107 nassertv(_gsg != nullptr);
108
109 if (mode == FM_render) {
110 copy_to_textures();
111 }
112
113 _gsg->end_frame(current_thread);
114
115 if (mode == FM_render) {
116 trigger_flip();
117 clear_cube_map_selection();
118
120 DCAST_INTO_V(wglgsg, _gsg);
121 wglgsg->pop_group_marker();
122 }
123}
124
125/**
126 * This function will be called within the draw thread after end_frame() has
127 * been called on all windows, to initiate the exchange of the front and back
128 * buffers.
129 *
130 * This should instruct the window to prepare for the flip at the next video
131 * sync, but it should not wait.
132 *
133 * We have the two separate functions, begin_flip() and end_flip(), to make it
134 * easier to flip all of the windows at the same time.
135 */
139
140/**
141 * This function will be called within the draw thread after end_frame() has
142 * been called on all windows, to initiate the exchange of the front and back
143 * buffers.
144 *
145 * This should instruct the window to prepare for the flip when command, but
146 * will not actually flip
147 *
148 * We have the two separate functions, begin_flip() and end_flip(), to make it
149 * easier to flip all of the windows at the same time.
150 */
152ready_flip() {
153 if (_hdc) {
154 // The documentation on SwapBuffers() is not at all clear on whether the
155 // GL context needs to be current before it can be called. Empirically,
156 // it appears that it is not necessary in many cases, but it definitely is
157 // necessary at least in the case of Mesa on Windows.
159 DCAST_INTO_V(wglgsg, _gsg);
160 HGLRC context = wglgsg->get_context(_hdc);
161 nassertv(context);
162 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
163 wglgsg->finish();
164 }
165}
166
167/**
168 * This function will be called within the draw thread after begin_flip() has
169 * been called on all windows, to finish the exchange of the front and back
170 * buffers.
171 *
172 * This should cause the window to wait for the flip, if necessary.
173 */
175end_flip() {
176 if (_hdc != nullptr && _flip_ready) {
177 // The documentation on SwapBuffers() is not at all clear on whether the
178 // GL context needs to be current before it can be called. Empirically,
179 // it appears that it is not necessary in many cases, but it definitely is
180 // necessary at least in the case of Mesa on Windows.
182 DCAST_INTO_V(wglgsg, _gsg);
183 HGLRC context = wglgsg->get_context(_hdc);
184 nassertv(context);
185 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
186 SwapBuffers(_hdc);
187 }
189}
190
191/**
192 * Closes the window right now. Called from the window thread.
193 */
194void wglGraphicsWindow::
195close_window() {
196 if (_gsg != nullptr) {
197 wglGraphicsPipe::wgl_make_current(_hdc, nullptr, &_make_current_pcollector);
198 _gsg.clear();
199 }
200 ReleaseDC(_hWnd, _hdc);
201 _hdc = (HDC)0;
202 WinGraphicsWindow::close_window();
203}
204
205/**
206 * Opens the window right now. Called from the window thread. Returns true
207 * if the window is successfully opened, or false if there was a problem.
208 */
209bool wglGraphicsWindow::
210open_window() {
211 if (!WinGraphicsWindow::open_window()) {
212 return false;
213 }
214
215 // GSG creationinitialization.
216
218 if (_gsg == 0) {
219 // There is no old gsg. Create a new one.
220 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, nullptr);
221 wglgsg->choose_pixel_format(_fb_properties, false);
222 _gsg = wglgsg;
223 } else {
224 // If the old gsg has the wrong pixel format, create a new one that shares
225 // with the old gsg.
226 DCAST_INTO_R(wglgsg, _gsg, false);
227 if (!wglgsg->get_fb_properties().subsumes(_fb_properties)) {
228 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg);
229 wglgsg->choose_pixel_format(_fb_properties, false);
230 _gsg = wglgsg;
231 }
232 }
233
234 // Set up the pixel format of the window appropriately for GL.
235
236 _hdc = GetDC(_hWnd);
237 int pfnum = wglgsg->get_pfnum();
238 PIXELFORMATDESCRIPTOR pixelformat;
239 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR),
240 &pixelformat);
241
242#ifdef NOTIFY_DEBUG
243 char msg[200];
244 sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
245 print_pfd(&pixelformat, msg);
246#endif
247
248 BOOL set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
249
250 if (!set_pfnum) {
251 if (wglgsg->fail_pfnum()) {
252 wgldisplay_cat.error()
253 << "SetPixelFormat(" << pfnum << ") failed; trying "
254 << wglgsg->get_pfnum() << " instead\n";
255
256 pfnum = wglgsg->get_pfnum();
257 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR),
258 &pixelformat);
259
260#ifdef NOTIFY_DEBUG
261 sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
262 print_pfd(&pixelformat, msg);
263#endif
264
265 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR),
266 &pixelformat);
267 set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
268 }
269 }
270
271 if (!set_pfnum) {
272 wgldisplay_cat.error()
273 << "SetPixelFormat(" << pfnum << ") failed after window create\n";
274 close_window();
275 return false;
276 }
277
278#ifndef NDEBUG
279 if (gl_force_invalid) {
280 wgldisplay_cat.error()
281 << "Artificially failing window.\n";
282 close_window();
283 return false;
284 }
285#endif // NDEBUG
286
287 // Initializes _colormap
288 setup_colormap(pixelformat);
289
290 // Make sure we have a context created.
291 HGLRC context = wglgsg->get_context(_hdc);
292 if (!context) {
293 // The context failed to create for some reason.
294 wgldisplay_cat.error()
295 << "Closing window because no valid context is available.\n";
296 close_window();
297 return false;
298 }
299
300 // Initialize the gsg.
301 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
302 wglgsg->reset_if_new();
303 wglgsg->report_my_gl_errors();
305 (_fb_properties,wglgsg->get_gl_renderer())) {
306 close_window();
307 return false;
308 }
309 _fb_properties = wglgsg->get_fb_properties();
310
311 return true;
312}
313
314/**
315 * Sets up a colormap for the window matching the selected pixel format. This
316 * is necessary before creating a GL context.
317 */
318void wglGraphicsWindow::
319setup_colormap(const PIXELFORMATDESCRIPTOR &pixelformat) {
320 LOGPALETTE *logical;
321 int n;
322
323 if (!(pixelformat.dwFlags & PFD_NEED_PALETTE ||
324 pixelformat.iPixelType == PFD_TYPE_COLORINDEX))
325 return;
326
327 n = 1 << pixelformat.cColorBits;
328
329 /* allocate a bunch of memory for the logical palette (assume 256
330 colors in a Win32 palette */
331 logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
332 sizeof(PALETTEENTRY) * n);
333 memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
334
335 /* set the entries in the logical palette */
336 logical->palVersion = 0x300;
337 logical->palNumEntries = n;
338
339 /* start with a copy of the current system palette */
340 GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]);
341
342 if (pixelformat.iPixelType == PFD_TYPE_RGBA) {
343 int redMask = (1 << pixelformat.cRedBits) - 1;
344 int greenMask = (1 << pixelformat.cGreenBits) - 1;
345 int blueMask = (1 << pixelformat.cBlueBits) - 1;
346 int i;
347
348 /* fill in an RGBA color palette */
349 for (i = 0; i < n; ++i) {
350 logical->palPalEntry[i].peRed =
351 (((i >> pixelformat.cRedShift) & redMask) * 255) / redMask;
352 logical->palPalEntry[i].peGreen =
353 (((i >> pixelformat.cGreenShift) & greenMask) * 255) / greenMask;
354 logical->palPalEntry[i].peBlue =
355 (((i >> pixelformat.cBlueShift) & blueMask) * 255) / blueMask;
356 logical->palPalEntry[i].peFlags = 0;
357 }
358 }
359
360 _colormap = CreatePalette(logical);
361 free(logical);
362
363 SelectPalette(_hdc, _colormap, FALSE);
364 RealizePalette(_hdc);
365}
366
367#ifdef NOTIFY_DEBUG
368
369typedef enum {Software, MCD, ICD} OGLDriverType;
370static const char *OGLDrvStrings[3] = {"Software","MCD","ICD"};
371
372/**
373 * Reports information about the selected pixel format descriptor, along with
374 * the indicated message.
375 */
376void wglGraphicsWindow::
377print_pfd(PIXELFORMATDESCRIPTOR *pfd, char *msg) {
378 if (!wgldisplay_cat.is_debug()) {
379 return;
380 }
381
382 OGLDriverType drvtype;
383 if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) &&
384 (pfd->dwFlags & PFD_GENERIC_FORMAT)) {
385 drvtype=MCD;
386 } else if (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT)) {
387 drvtype=ICD;
388 } else {
389 drvtype=Software;
390 }
391
392#define PRINT_FLAG(FLG) ((pfd->dwFlags & PFD_##FLG) ? (" PFD_" #FLG "|") : "")
393 wgldisplay_cat.debug()
394 << "================================\n";
395
396 wgldisplay_cat.debug()
397 << msg << ", " << OGLDrvStrings[drvtype] << " driver\n"
398 << "PFD flags: 0x" << std::hex << pfd->dwFlags << std::dec << " ("
399 << PRINT_FLAG(GENERIC_ACCELERATED)
400 << PRINT_FLAG(GENERIC_FORMAT)
401 << PRINT_FLAG(DOUBLEBUFFER)
402 << PRINT_FLAG(SUPPORT_OPENGL)
403 << PRINT_FLAG(SUPPORT_GDI)
404 << PRINT_FLAG(STEREO)
405 << PRINT_FLAG(DRAW_TO_WINDOW)
406 << PRINT_FLAG(DRAW_TO_BITMAP)
407 << PRINT_FLAG(SWAP_EXCHANGE)
408 << PRINT_FLAG(SWAP_COPY)
409 << PRINT_FLAG(SWAP_LAYER_BUFFERS)
410 << PRINT_FLAG(NEED_PALETTE)
411 << PRINT_FLAG(NEED_SYSTEM_PALETTE)
412 << PRINT_FLAG(SUPPORT_DIRECTDRAW) << ")\n"
413 << "PFD iPixelType: "
414 << ((pfd->iPixelType==PFD_TYPE_RGBA) ? "PFD_TYPE_RGBA":"PFD_TYPE_COLORINDEX")
415 << std::endl
416 << "PFD cColorBits: " << (DWORD)pfd->cColorBits
417 << " R: " << (DWORD)pfd->cRedBits
418 <<" G: " << (DWORD)pfd->cGreenBits
419 <<" B: " << (DWORD)pfd->cBlueBits << std::endl
420 << "PFD cAlphaBits: " << (DWORD)pfd->cAlphaBits
421 << " DepthBits: " << (DWORD)pfd->cDepthBits
422 <<" StencilBits: " << (DWORD)pfd->cStencilBits
423 <<" AccumBits: " << (DWORD)pfd->cAccumBits
424 << std::endl;
425}
426#endif
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool verify_hardware_software(const FrameBufferProperties &props, const std::string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software).
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
get_name
Returns the name that was passed to the GraphicsOutput constructor.
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
get_unexposed_draw
See set_unexposed_draw().
A thread; that is, a lightweight process.
Definition thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer)
Selects a pixel format for all the windows and buffers that use this gsg.
int get_pfnum() const
Returns the pixel format number chosen for windows that use this context.
bool fail_pfnum()
This is called by wglGraphicsWindow when it finds it cannot use the pfnum determined by the GSG.
const FrameBufferProperties & get_fb_properties() const
Returns the properties of the pixel format that was chosen for this gsg.
HGLRC get_context(HDC hdc)
Returns the GL context associated with the GSG.
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame.
virtual void ready_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
STL namespace.
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.