Panda3D
|
00001 // Filename: wglGraphicsWindow.cxx 00002 // Created by: drose (20Dec02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "wglGraphicsWindow.h" 00016 #include "config_wgldisplay.h" 00017 #include "config_windisplay.h" 00018 #include "wglGraphicsPipe.h" 00019 #include "pStatTimer.h" 00020 #include "glgsg.h" 00021 00022 #include <wingdi.h> 00023 00024 TypeHandle wglGraphicsWindow::_type_handle; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: wglGraphicsWindow::Constructor 00028 // Access: Public 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 wglGraphicsWindow:: 00032 wglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, 00033 const string &name, 00034 const FrameBufferProperties &fb_prop, 00035 const WindowProperties &win_prop, 00036 int flags, 00037 GraphicsStateGuardian *gsg, 00038 GraphicsOutput *host) : 00039 WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) 00040 { 00041 _hdc = (HDC)0; 00042 } 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: wglGraphicsWindow::Destructor 00046 // Access: Public, Virtual 00047 // Description: 00048 //////////////////////////////////////////////////////////////////// 00049 wglGraphicsWindow:: 00050 ~wglGraphicsWindow() { 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: wglGraphicsWindow::begin_frame 00055 // Access: Public, Virtual 00056 // Description: This function will be called within the draw thread 00057 // before beginning rendering for a given frame. It 00058 // should do whatever setup is required, and return true 00059 // if the frame should be rendered, or false if it 00060 // should be skipped. 00061 //////////////////////////////////////////////////////////////////// 00062 bool wglGraphicsWindow:: 00063 begin_frame(FrameMode mode, Thread *current_thread) { 00064 00065 begin_frame_spam(mode); 00066 if (_gsg == (GraphicsStateGuardian *)NULL) { 00067 return false; 00068 } 00069 00070 if (!get_unexposed_draw() && !_got_expose_event) { 00071 if (wgldisplay_cat.is_spam()) { 00072 wgldisplay_cat.spam() 00073 << "Not drawing " << this << ": unexposed.\n"; 00074 } 00075 return false; 00076 } 00077 00078 if (wgldisplay_cat.is_spam()) { 00079 wgldisplay_cat.spam() 00080 << "Drawing " << this << ": exposed.\n"; 00081 } 00082 00083 wglGraphicsStateGuardian *wglgsg; 00084 DCAST_INTO_R(wglgsg, _gsg, false); 00085 00086 HGLRC context = wglgsg->get_context(_hdc); 00087 nassertr(context, false); 00088 00089 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector); 00090 wglgsg->reset_if_new(); 00091 00092 if (mode == FM_render) { 00093 clear_cube_map_selection(); 00094 } 00095 00096 _gsg->set_current_properties(&get_fb_properties()); 00097 return _gsg->begin_frame(current_thread); 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: wglGraphicsWindow::end_frame 00102 // Access: Public, Virtual 00103 // Description: This function will be called within the draw thread 00104 // after rendering is completed for a given frame. It 00105 // should do whatever finalization is required. 00106 //////////////////////////////////////////////////////////////////// 00107 void wglGraphicsWindow:: 00108 end_frame(FrameMode mode, Thread *current_thread) { 00109 end_frame_spam(mode); 00110 00111 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00112 00113 if (mode == FM_render) { 00114 copy_to_textures(); 00115 } 00116 00117 _gsg->end_frame(current_thread); 00118 00119 if (mode == FM_render) { 00120 trigger_flip(); 00121 clear_cube_map_selection(); 00122 } 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: wglGraphicsWindow::begin_flip 00127 // Access: Public, Virtual 00128 // Description: This function will be called within the draw thread 00129 // after end_frame() has been called on all windows, to 00130 // initiate the exchange of the front and back buffers. 00131 // 00132 // This should instruct the window to prepare for the 00133 // flip at the next video sync, but it should not wait. 00134 // 00135 // We have the two separate functions, begin_flip() and 00136 // end_flip(), to make it easier to flip all of the 00137 // windows at the same time. 00138 //////////////////////////////////////////////////////////////////// 00139 void wglGraphicsWindow:: 00140 begin_flip() { 00141 } 00142 00143 //////////////////////////////////////////////////////////////////// 00144 // Function: wglGraphicsWindow::ready_flip 00145 // Access: Public, Virtual 00146 // Description: This function will be called within the draw thread 00147 // after end_frame() has been called on all windows, to 00148 // initiate the exchange of the front and back buffers. 00149 // 00150 // This should instruct the window to prepare for the 00151 // flip when command, but will not actually flip 00152 // 00153 // We have the two separate functions, begin_flip() and 00154 // end_flip(), to make it easier to flip all of the 00155 // windows at the same time. 00156 //////////////////////////////////////////////////////////////////// 00157 void wglGraphicsWindow:: 00158 ready_flip() { 00159 if (_hdc) { 00160 // The documentation on SwapBuffers() is not at all clear on 00161 // whether the GL context needs to be current before it can be 00162 // called. Empirically, it appears that it is not necessary in 00163 // many cases, but it definitely is necessary at least in the case 00164 // of Mesa on Windows. 00165 wglGraphicsStateGuardian *wglgsg; 00166 DCAST_INTO_V(wglgsg, _gsg); 00167 HGLRC context = wglgsg->get_context(_hdc); 00168 nassertv(context); 00169 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector); 00170 wglgsg->finish(); 00171 } 00172 } 00173 00174 //////////////////////////////////////////////////////////////////// 00175 // Function: wglGraphicsWindow::end_flip 00176 // Access: Public, Virtual 00177 // Description: This function will be called within the draw thread 00178 // after begin_flip() has been called on all windows, to 00179 // finish the exchange of the front and back buffers. 00180 // 00181 // This should cause the window to wait for the flip, if 00182 // necessary. 00183 //////////////////////////////////////////////////////////////////// 00184 void wglGraphicsWindow:: 00185 end_flip() { 00186 if (_hdc != NULL && _flip_ready) { 00187 // The documentation on SwapBuffers() is not at all clear on 00188 // whether the GL context needs to be current before it can be 00189 // called. Empirically, it appears that it is not necessary in 00190 // many cases, but it definitely is necessary at least in the case 00191 // of Mesa on Windows. 00192 wglGraphicsStateGuardian *wglgsg; 00193 DCAST_INTO_V(wglgsg, _gsg); 00194 HGLRC context = wglgsg->get_context(_hdc); 00195 nassertv(context); 00196 wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector); 00197 SwapBuffers(_hdc); 00198 } 00199 WinGraphicsWindow::end_flip(); 00200 } 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: wglGraphicsWindow::close_window 00204 // Access: Protected, Virtual 00205 // Description: Closes the window right now. Called from the window 00206 // thread. 00207 //////////////////////////////////////////////////////////////////// 00208 void wglGraphicsWindow:: 00209 close_window() { 00210 if (_gsg != (GraphicsStateGuardian *)NULL) { 00211 wglGraphicsPipe::wgl_make_current(_hdc, NULL, &_make_current_pcollector); 00212 _gsg.clear(); 00213 } 00214 ReleaseDC(_hWnd, _hdc); 00215 _hdc = (HDC)0; 00216 WinGraphicsWindow::close_window(); 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: wglGraphicsWindow::open_window 00221 // Access: Protected, Virtual 00222 // Description: Opens the window right now. Called from the window 00223 // thread. Returns true if the window is successfully 00224 // opened, or false if there was a problem. 00225 //////////////////////////////////////////////////////////////////// 00226 bool wglGraphicsWindow:: 00227 open_window() { 00228 if (!WinGraphicsWindow::open_window()) { 00229 return false; 00230 } 00231 00232 // GSG creation/initialization. 00233 00234 wglGraphicsStateGuardian *wglgsg; 00235 if (_gsg == 0) { 00236 // There is no old gsg. Create a new one. 00237 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, NULL); 00238 wglgsg->choose_pixel_format(_fb_properties, false); 00239 _gsg = wglgsg; 00240 } else { 00241 // If the old gsg has the wrong pixel format, create a 00242 // new one that shares with the old gsg. 00243 DCAST_INTO_R(wglgsg, _gsg, false); 00244 if (!wglgsg->get_fb_properties().subsumes(_fb_properties)) { 00245 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg); 00246 wglgsg->choose_pixel_format(_fb_properties, false); 00247 _gsg = wglgsg; 00248 } 00249 } 00250 00251 // Set up the pixel format of the window appropriately for GL. 00252 00253 _hdc = GetDC(_hWnd); 00254 int pfnum = wglgsg->get_pfnum(); 00255 PIXELFORMATDESCRIPTOR pixelformat; 00256 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 00257 &pixelformat); 00258 00259 #ifdef NOTIFY_DEBUG 00260 char msg[200]; 00261 sprintf(msg, "Selected GL PixelFormat is #%d", pfnum); 00262 print_pfd(&pixelformat, msg); 00263 #endif 00264 00265 BOOL set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat); 00266 00267 if (!set_pfnum) { 00268 if (wglgsg->fail_pfnum()) { 00269 wgldisplay_cat.error() 00270 << "SetPixelFormat(" << pfnum << ") failed; trying " 00271 << wglgsg->get_pfnum() << " instead\n"; 00272 00273 pfnum = wglgsg->get_pfnum(); 00274 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 00275 &pixelformat); 00276 00277 #ifdef NOTIFY_DEBUG 00278 sprintf(msg, "Selected GL PixelFormat is #%d", pfnum); 00279 print_pfd(&pixelformat, msg); 00280 #endif 00281 00282 DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 00283 &pixelformat); 00284 set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat); 00285 } 00286 } 00287 00288 if (!set_pfnum) { 00289 wgldisplay_cat.error() 00290 << "SetPixelFormat(" << pfnum << ") failed after window create\n"; 00291 close_window(); 00292 return false; 00293 } 00294 00295 #ifndef NDEBUG 00296 if (gl_force_invalid) { 00297 wgldisplay_cat.error() 00298 << "Artificially failing window.\n"; 00299 close_window(); 00300 return false; 00301 } 00302 #endif // NDEBUG 00303 00304 // Initializes _colormap 00305 setup_colormap(pixelformat); 00306 00307 // Initialize the gsg. 00308 wglGraphicsPipe::wgl_make_current(_hdc, wglgsg->get_context(_hdc), &_make_current_pcollector); 00309 wglgsg->reset_if_new(); 00310 wglgsg->report_my_gl_errors(); 00311 if (!wglgsg->get_fb_properties().verify_hardware_software 00312 (_fb_properties,wglgsg->get_gl_renderer())) { 00313 close_window(); 00314 return false; 00315 } 00316 _fb_properties = wglgsg->get_fb_properties(); 00317 00318 return true; 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: wglGraphicsWindow::setup_colormap 00323 // Access: Private 00324 // Description: Sets up a colormap for the window matching the 00325 // selected pixel format. This is necessary before 00326 // creating a GL context. 00327 //////////////////////////////////////////////////////////////////// 00328 void wglGraphicsWindow:: 00329 setup_colormap(const PIXELFORMATDESCRIPTOR &pixelformat) { 00330 LOGPALETTE *logical; 00331 int n; 00332 00333 if (!(pixelformat.dwFlags & PFD_NEED_PALETTE || 00334 pixelformat.iPixelType == PFD_TYPE_COLORINDEX)) 00335 return; 00336 00337 n = 1 << pixelformat.cColorBits; 00338 00339 /* allocate a bunch of memory for the logical palette (assume 256 00340 colors in a Win32 palette */ 00341 logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + 00342 sizeof(PALETTEENTRY) * n); 00343 memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n); 00344 00345 /* set the entries in the logical palette */ 00346 logical->palVersion = 0x300; 00347 logical->palNumEntries = n; 00348 00349 /* start with a copy of the current system palette */ 00350 GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]); 00351 00352 if (pixelformat.iPixelType == PFD_TYPE_RGBA) { 00353 int redMask = (1 << pixelformat.cRedBits) - 1; 00354 int greenMask = (1 << pixelformat.cGreenBits) - 1; 00355 int blueMask = (1 << pixelformat.cBlueBits) - 1; 00356 int i; 00357 00358 /* fill in an RGBA color palette */ 00359 for (i = 0; i < n; ++i) { 00360 logical->palPalEntry[i].peRed = 00361 (((i >> pixelformat.cRedShift) & redMask) * 255) / redMask; 00362 logical->palPalEntry[i].peGreen = 00363 (((i >> pixelformat.cGreenShift) & greenMask) * 255) / greenMask; 00364 logical->palPalEntry[i].peBlue = 00365 (((i >> pixelformat.cBlueShift) & blueMask) * 255) / blueMask; 00366 logical->palPalEntry[i].peFlags = 0; 00367 } 00368 } 00369 00370 _colormap = CreatePalette(logical); 00371 free(logical); 00372 00373 SelectPalette(_hdc, _colormap, FALSE); 00374 RealizePalette(_hdc); 00375 } 00376 00377 #ifdef NOTIFY_DEBUG 00378 00379 //typedef enum {Software, MCD, ICD} OGLDriverType; 00380 static char *OGLDrvStrings[3] = {"Software","MCD","ICD"}; 00381 00382 //////////////////////////////////////////////////////////////////// 00383 // Function: wglGraphicsWindow::print_pfd 00384 // Access: Private, Static 00385 // Description: Reports information about the selected pixel format 00386 // descriptor, along with the indicated message. 00387 //////////////////////////////////////////////////////////////////// 00388 void wglGraphicsWindow:: 00389 print_pfd(PIXELFORMATDESCRIPTOR *pfd, char *msg) { 00390 if (!wgldisplay_cat.is_debug()) { 00391 return; 00392 } 00393 00394 OGLDriverType drvtype; 00395 if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && 00396 (pfd->dwFlags & PFD_GENERIC_FORMAT)) { 00397 drvtype=MCD; 00398 } else if (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT)) { 00399 drvtype=ICD; 00400 } else { 00401 drvtype=Software; 00402 } 00403 00404 #define PRINT_FLAG(FLG) ((pfd->dwFlags & PFD_##FLG) ? (" PFD_" #FLG "|") : "") 00405 wgldisplay_cat.debug() 00406 << "================================\n"; 00407 00408 wgldisplay_cat.debug() 00409 << msg << ", " << OGLDrvStrings[drvtype] << " driver\n" 00410 << "PFD flags: 0x" << (void*)pfd->dwFlags << " (" 00411 << PRINT_FLAG(GENERIC_ACCELERATED) 00412 << PRINT_FLAG(GENERIC_FORMAT) 00413 << PRINT_FLAG(DOUBLEBUFFER) 00414 << PRINT_FLAG(SUPPORT_OPENGL) 00415 << PRINT_FLAG(SUPPORT_GDI) 00416 << PRINT_FLAG(STEREO) 00417 << PRINT_FLAG(DRAW_TO_WINDOW) 00418 << PRINT_FLAG(DRAW_TO_BITMAP) 00419 << PRINT_FLAG(SWAP_EXCHANGE) 00420 << PRINT_FLAG(SWAP_COPY) 00421 << PRINT_FLAG(SWAP_LAYER_BUFFERS) 00422 << PRINT_FLAG(NEED_PALETTE) 00423 << PRINT_FLAG(NEED_SYSTEM_PALETTE) 00424 << PRINT_FLAG(SUPPORT_DIRECTDRAW) << ")\n" 00425 << "PFD iPixelType: " 00426 << ((pfd->iPixelType==PFD_TYPE_RGBA) ? "PFD_TYPE_RGBA":"PFD_TYPE_COLORINDEX") 00427 << endl 00428 << "PFD cColorBits: " << (DWORD)pfd->cColorBits 00429 << " R: " << (DWORD)pfd->cRedBits 00430 <<" G: " << (DWORD)pfd->cGreenBits 00431 <<" B: " << (DWORD)pfd->cBlueBits << endl 00432 << "PFD cAlphaBits: " << (DWORD)pfd->cAlphaBits 00433 << " DepthBits: " << (DWORD)pfd->cDepthBits 00434 <<" StencilBits: " << (DWORD)pfd->cStencilBits 00435 <<" AccumBits: " << (DWORD)pfd->cAccumBits 00436 << endl; 00437 } 00438 #endif 00439