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