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"
20 #include "wglGraphicsStateGuardian.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,
35 GraphicsStateGuardian *gsg,
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 */
55 bool wglGraphicsWindow::
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
76 wglGraphicsStateGuardian *wglgsg;
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 */
103 void wglGraphicsWindow::
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 */
136 void wglGraphicsWindow::
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 */
151 void wglGraphicsWindow::
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 */
174 void wglGraphicsWindow::
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 }
188 WinGraphicsWindow::end_flip();
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();
304 if (!wglgsg->get_fb_properties().verify_hardware_software
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
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
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
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
GraphicsOutput
This is a base class for the various different classes that represent the result of a frame of render...
Definition: graphicsOutput.h:63
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
GraphicsOutput::get_fb_properties
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
Definition: graphicsOutput.I:413
GraphicsOutput::get_name
get_name
Returns the name that was passed to the GraphicsOutput constructor.
Definition: graphicsOutput.h:120
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
GraphicsStateGuardian
Encapsulates all the communication with a particular instance of a given rendering backend.
Definition: graphicsStateGuardian.h:65
GraphicsWindow::get_unexposed_draw
get_unexposed_draw
See set_unexposed_draw().
Definition: graphicsWindow.h:78
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
WinGraphicsWindow
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
Definition: winGraphicsWindow.h:64
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
wglGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
Definition: wglGraphicsStateGuardian.h:28
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
wglGraphicsStateGuardian::get_pfnum
int get_pfnum() const
Returns the pixel format number chosen for windows that use this context.
Definition: wglGraphicsStateGuardian.I:22
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
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
wglGraphicsStateGuardian::get_context
HGLRC get_context(HDC hdc)
Returns the GL context associated with the GSG.
Definition: wglGraphicsStateGuardian.I:63
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
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
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
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
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
config_wgldisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_windisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
glgsg.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsPipe.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
wglGraphicsWindow.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.