Panda3D
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 
24 TypeHandle wglGraphicsWindow::_type_handle;
25 
26 /**
27  *
28  */
29 wglGraphicsWindow::
30 wglGraphicsWindow(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  */
45 wglGraphicsWindow::
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  */
56 begin_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  */
104 end_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 
119  wglGraphicsStateGuardian *wglgsg;
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  */
137 begin_flip() {
138 }
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  */
152 ready_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.
158  wglGraphicsStateGuardian *wglgsg;
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  */
175 end_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.
181  wglGraphicsStateGuardian *wglgsg;
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  */
194 void wglGraphicsWindow::
195 close_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  */
209 bool wglGraphicsWindow::
210 open_window() {
211  if (!WinGraphicsWindow::open_window()) {
212  return false;
213  }
214 
215  // GSG creationinitialization.
216 
217  wglGraphicsStateGuardian *wglgsg;
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  */
318 void wglGraphicsWindow::
319 setup_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 
369 typedef enum {Software, MCD, ICD} OGLDriverType;
370 static 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  */
376 void wglGraphicsWindow::
377 print_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
FrameBufferProperties
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
Definition: frameBufferProperties.h:26
glgsg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsWindow::end_flip
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
Definition: wglGraphicsWindow.cxx:175
GraphicsOutput::get_name
get_name
Returns the name that was passed to the GraphicsOutput constructor.
Definition: graphicsOutput.h:120
wglGraphicsStateGuardian::fail_pfnum
bool fail_pfnum()
This is called by wglGraphicsWindow when it finds it cannot use the pfnum determined by the GSG.
Definition: wglGraphicsStateGuardian.cxx:81
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsStateGuardian::get_pfnum
int get_pfnum() const
Returns the pixel format number chosen for windows that use this context.
Definition: wglGraphicsStateGuardian.I:22
wglGraphicsStateGuardian::get_fb_properties
const FrameBufferProperties & get_fb_properties() const
Returns the properties of the pixel format that was chosen for this gsg.
Definition: wglGraphicsStateGuardian.I:42
WindowProperties
A container for the various kinds of properties we might ask to have on a graphics window before we o...
Definition: windowProperties.h:29
wglGraphicsWindow::begin_frame
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.
Definition: wglGraphicsWindow.cxx:56
FrameBufferProperties::subsumes
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
Definition: frameBufferProperties.cxx:25
wglGraphicsStateGuardian::choose_pixel_format
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer)
Selects a pixel format for all the windows and buffers that use this gsg.
Definition: wglGraphicsStateGuardian.cxx:250
WinGraphicsWindow
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
Definition: winGraphicsWindow.h:64
FrameBufferProperties::verify_hardware_software
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).
Definition: frameBufferProperties.cxx:604
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
wglGraphicsWindow::ready_flip
virtual void ready_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
Definition: wglGraphicsWindow.cxx:152
config_wgldisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GraphicsOutput
This is a base class for the various different classes that represent the result of a frame of render...
Definition: graphicsOutput.h:63
config_windisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
wglGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
Definition: wglGraphicsStateGuardian.h:28
GraphicsOutput::get_fb_properties
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
Definition: graphicsOutput.I:413
wglGraphicsWindow::begin_flip
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
Definition: wglGraphicsWindow.cxx:137
wglGraphicsPipe.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GraphicsWindow::get_unexposed_draw
get_unexposed_draw
See set_unexposed_draw().
Definition: graphicsWindow.h:78
GraphicsStateGuardian
Encapsulates all the communication with a particular instance of a given rendering backend.
Definition: graphicsStateGuardian.h:65
GraphicsOutput::end_flip
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
Definition: graphicsOutput.cxx:1299
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
wglGraphicsWindow.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsStateGuardian::get_context
HGLRC get_context(HDC hdc)
Returns the GL context associated with the GSG.
Definition: wglGraphicsStateGuardian.I:63
wglGraphicsWindow::end_frame
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.
Definition: wglGraphicsWindow.cxx:104