Panda3D
|
00001 // Filename: wdxGraphicsWindow9.cxx 00002 // Created by: mike (09Jan00) 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 "wdxGraphicsPipe9.h" 00016 #include "wdxGraphicsWindow9.h" 00017 #include "config_dxgsg9.h" 00018 #include "config_display.h" 00019 #include "keyboardButton.h" 00020 #include "mouseButton.h" 00021 #include "throw_event.h" 00022 #include "pStatTimer.h" 00023 #include "pmap.h" 00024 #include <ddraw.h> 00025 #include <errno.h> 00026 #include <time.h> 00027 #include <math.h> 00028 #include <tchar.h> 00029 00030 TypeHandle wdxGraphicsWindow9::_type_handle; 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Function: wdxGraphicsWindow9::Constructor 00034 // Access: Public 00035 // Description: 00036 //////////////////////////////////////////////////////////////////// 00037 wdxGraphicsWindow9:: 00038 wdxGraphicsWindow9(GraphicsEngine *engine, GraphicsPipe *pipe, 00039 const string &name, 00040 const FrameBufferProperties &fb_prop, 00041 const WindowProperties &win_prop, 00042 int flags, 00043 GraphicsStateGuardian *gsg, 00044 GraphicsOutput *host): 00045 WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host) 00046 { 00047 // don't actually create the window in the constructor. reason: 00048 // multi-threading requires panda C++ window object to exist in 00049 // separate thread from actual API window 00050 00051 _dxgsg = DCAST(DXGraphicsStateGuardian9, gsg); 00052 _depth_buffer_bpp = 0; 00053 _awaiting_restore = false; 00054 ZeroMemory(&_wcontext, sizeof(_wcontext)); 00055 } 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: wdxGraphicsWindow9::Destructor 00059 // Access: Public, Virtual 00060 // Description: 00061 //////////////////////////////////////////////////////////////////// 00062 wdxGraphicsWindow9:: 00063 ~wdxGraphicsWindow9() { 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: wdxGraphicsWindow9::make_current 00068 // Access: Public, Virtual 00069 // Description: 00070 //////////////////////////////////////////////////////////////////// 00071 void wdxGraphicsWindow9:: 00072 make_current() { 00073 PStatTimer timer(_make_current_pcollector); 00074 00075 _dxgsg->set_context(&_wcontext); 00076 00077 // Now that we have made the context current to a window, we can 00078 // reset the GSG state if this is the first time it has been used. 00079 // (We can't just call reset() when we construct the GSG, because 00080 // reset() requires having a current context.) 00081 _dxgsg->reset_if_new(); 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: wdxGraphicsWindow9::begin_frame 00086 // Access: Public, Virtual 00087 // Description: This function will be called within the draw thread 00088 // before beginning rendering for a given frame. It 00089 // should do whatever setup is required, and return true 00090 // if the frame should be rendered, or false if it 00091 // should be skipped. 00092 //////////////////////////////////////////////////////////////////// 00093 bool wdxGraphicsWindow9:: 00094 begin_frame(FrameMode mode, Thread *current_thread) { 00095 begin_frame_spam(mode); 00096 if (_gsg == (GraphicsStateGuardian *)NULL) { 00097 return false; 00098 } 00099 00100 if (!get_unexposed_draw() && !_got_expose_event) { 00101 if (wdxdisplay9_cat.is_spam()) { 00102 wdxdisplay9_cat.spam() 00103 << "Not drawing " << this << ": unexposed.\n"; 00104 } 00105 return false; 00106 } 00107 00108 if (_awaiting_restore) { 00109 // The fullscreen window was recently restored; we can't continue 00110 // until the GSG says we can. 00111 if (!_dxgsg->check_cooperative_level()) { 00112 // Keep waiting. 00113 return false; 00114 } 00115 _awaiting_restore = false; 00116 init_resized_window(); 00117 } 00118 00119 make_current(); 00120 00121 if (mode == FM_render) { 00122 clear_cube_map_selection(); 00123 } 00124 00125 _gsg->set_current_properties(&get_fb_properties()); 00126 bool return_val = _gsg->begin_frame(current_thread); 00127 _dxgsg->set_render_target(); 00128 return return_val; 00129 } 00130 00131 //////////////////////////////////////////////////////////////////// 00132 // Function: wdxGraphicsWindow9::end_frame 00133 // Access: Public, Virtual 00134 // Description: This function will be called within the draw thread 00135 // after rendering is completed for a given frame. It 00136 // should do whatever finalization is required. 00137 //////////////////////////////////////////////////////////////////// 00138 void wdxGraphicsWindow9:: 00139 end_frame(FrameMode mode, Thread *current_thread) { 00140 end_frame_spam(mode); 00141 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 00142 00143 if (mode == FM_render) { 00144 copy_to_textures(); 00145 } 00146 00147 _gsg->end_frame(current_thread); 00148 00149 if (mode == FM_render) { 00150 trigger_flip(); 00151 clear_cube_map_selection(); 00152 } 00153 } 00154 00155 //////////////////////////////////////////////////////////////////// 00156 // Function: wdxGraphicsWindow9::end_flip 00157 // Access: Public, Virtual 00158 // Description: This function will be called within the draw thread 00159 // after begin_flip() has been called on all windows, to 00160 // finish the exchange of the front and back buffers. 00161 // 00162 // This should cause the window to wait for the flip, if 00163 // necessary. 00164 //////////////////////////////////////////////////////////////////// 00165 void wdxGraphicsWindow9:: 00166 end_flip() { 00167 if (_dxgsg != (DXGraphicsStateGuardian9 *)NULL && is_active()) { 00168 _dxgsg->show_frame(); 00169 } 00170 WinGraphicsWindow::end_flip(); 00171 } 00172 00173 //////////////////////////////////////////////////////////////////// 00174 // Function: wdxGraphicsWindow9::verify_window_sizes 00175 // Access: Public, Virtual 00176 // Description: Determines which of the indicated window sizes are 00177 // supported by available hardware (e.g. in fullscreen 00178 // mode). 00179 // 00180 // On entry, dimen is an array containing contiguous x, y 00181 // pairs specifying possible display sizes; it is 00182 // numsizes*2 words long. The function will zero out 00183 // any invalid x, y size pairs. The return value is the 00184 // number of valid sizes that were found. 00185 //////////////////////////////////////////////////////////////////// 00186 int wdxGraphicsWindow9:: 00187 verify_window_sizes(int numsizes, int *dimen) { 00188 // unfortunately this only works AFTER you make the window 00189 // initially, so its really mostly useful for resizes only 00190 nassertr(IS_VALID_PTR(_dxgsg), 0); 00191 00192 int num_valid_modes = 0; 00193 00194 wdxGraphicsPipe9 *dxpipe; 00195 DCAST_INTO_R(dxpipe, _pipe, 0); 00196 00197 // not requesting same refresh rate since changing res might not 00198 // support same refresh rate at new size 00199 00200 int *pCurDim = dimen; 00201 00202 for (int i = 0; i < numsizes; i++, pCurDim += 2) { 00203 int x_size = pCurDim[0]; 00204 int y_size = pCurDim[1]; 00205 00206 bool bIsGoodMode = false; 00207 bool CouldntFindAnyValidZBuf; 00208 D3DFORMAT newPixFmt = D3DFMT_UNKNOWN; 00209 00210 if (dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) { 00211 // bypass the test below for certain cards we know have valid modes 00212 bIsGoodMode = true; 00213 00214 } else { 00215 if (_wcontext._is_low_memory_card) { 00216 bIsGoodMode = ((x_size == 640) && (y_size == 480)); 00217 } else { 00218 dxpipe->search_for_valid_displaymode 00219 (_wcontext, x_size, y_size, _wcontext._presentation_params.EnableAutoDepthStencil != false, 00220 IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat), 00221 &_wcontext._supported_screen_depths_mask, 00222 &CouldntFindAnyValidZBuf, &newPixFmt, dx_force_16bpp_zbuffer, true); 00223 bIsGoodMode = (newPixFmt != D3DFMT_UNKNOWN); 00224 } 00225 } 00226 00227 if (bIsGoodMode) { 00228 num_valid_modes++; 00229 } else { 00230 // tell caller the mode is invalid 00231 pCurDim[0] = 0; 00232 pCurDim[1] = 0; 00233 } 00234 00235 if (wdxdisplay9_cat.is_spam()) { 00236 wdxdisplay9_cat.spam() 00237 << "Fullscrn Mode (" << x_size << ", " << y_size << ")\t" 00238 << (bIsGoodMode ? "V" : "Inv") << "alid\n"; 00239 } 00240 } 00241 00242 return num_valid_modes; 00243 } 00244 00245 ////////////////////////////////////////////////////////////////// 00246 // Function: wdxGraphicsWindow::close_window 00247 // Access: Public 00248 // Description: Some cleanup is necessary for directx closeup of window. 00249 // Handle close window events for this particular 00250 // window. 00251 //////////////////////////////////////////////////////////////////// 00252 void wdxGraphicsWindow9:: 00253 close_window() { 00254 if (wdxdisplay9_cat.is_debug()) { 00255 wdxdisplay9_cat.debug() 00256 << "wdxGraphicsWindow9::close_window() " << this << "\n"; 00257 } 00258 00259 if (_gsg != (GraphicsStateGuardian *)NULL) { 00260 _gsg.clear(); 00261 } 00262 00263 DXGraphicsStateGuardian9::set_cg_device(NULL); 00264 00265 _dxgsg->release_swap_chain(&_wcontext); 00266 WinGraphicsWindow::close_window(); 00267 } 00268 00269 //////////////////////////////////////////////////////////////////// 00270 // Function: wdxGraphicsWindow9::open_window 00271 // Access: Protected, Virtual 00272 // Description: Opens the window right now. Called from the window 00273 // thread. Returns true if the window is successfully 00274 // opened, or false if there was a problem. 00275 //////////////////////////////////////////////////////////////////// 00276 bool wdxGraphicsWindow9:: 00277 open_window() { 00278 PT(DXGraphicsDevice9) dxdev; 00279 WindowProperties props; 00280 00281 // For now, let's make this configurable. If this is true, then you 00282 // can't open multiple different windows with the same GSG, but you 00283 // may have more luck opening different windows with different 00284 // GSG's. 00285 static ConfigVariableBool always_discard_device("always-discard-device", true); 00286 bool discard_device = always_discard_device; 00287 00288 if (_gsg == 0) { 00289 _dxgsg = new DXGraphicsStateGuardian9(_engine, _pipe); 00290 _gsg = _dxgsg; 00291 } else { 00292 DCAST_INTO_R(_dxgsg, _gsg, false); 00293 } 00294 00295 if (!choose_device()) { 00296 return false; 00297 } 00298 00299 // Ensure the window properties get set to the actual size of the 00300 // window. 00301 { 00302 WindowProperties resized_props; 00303 resized_props.set_size(_wcontext._display_mode.Width, 00304 _wcontext._display_mode.Height); 00305 _properties.add_properties(resized_props); 00306 } 00307 00308 wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n"; 00309 if (!WinGraphicsWindow::open_window()) { 00310 return false; 00311 } 00312 _wcontext._window = _hWnd; 00313 00314 wdxdisplay9_cat.debug() << "_wcontext._window is " << _wcontext._window << "\n"; 00315 00316 // Here check if a device already exists. If so, then this open_window 00317 // call may be an extension to create multiple windows on same device 00318 // In that case just create an additional swapchain for this window 00319 00320 while (true) { 00321 if (_dxgsg->get_pipe()->get_device() == NULL || discard_device) { 00322 wdxdisplay9_cat.debug() << "device is null or fullscreen\n"; 00323 00324 // If device exists, free it 00325 if (_dxgsg->get_pipe()->get_device()) { 00326 _dxgsg->dx_cleanup(); 00327 } 00328 00329 wdxdisplay9_cat.debug() << "device width " << _wcontext._display_mode.Width << "\n"; 00330 if (!create_screen_buffers_and_device(_wcontext, dx_force_16bpp_zbuffer)) { 00331 wdxdisplay9_cat.error() << "Unable to create window with specified parameters.\n"; 00332 close_window(); 00333 return false; 00334 } 00335 _dxgsg->get_pipe()->make_device((void*)(&_wcontext)); 00336 _dxgsg->copy_pres_reset(&_wcontext); 00337 _dxgsg->create_swap_chain(&_wcontext); 00338 break; 00339 00340 } else { 00341 // fill in the DXScreenData from dxdevice here and change the 00342 // reference to _window. 00343 wdxdisplay9_cat.debug() << "device is not null\n"; 00344 00345 dxdev = (DXGraphicsDevice9*)_dxgsg->get_pipe()->get_device(); 00346 memcpy(&_wcontext, &dxdev->_Scrn, sizeof(DXScreenData)); 00347 00348 _wcontext._presentation_params.Windowed = !is_fullscreen(); 00349 _wcontext._presentation_params.hDeviceWindow = _wcontext._window = _hWnd; 00350 _wcontext._presentation_params.BackBufferWidth = _wcontext._display_mode.Width = _properties.get_x_size(); 00351 _wcontext._presentation_params.BackBufferHeight = _wcontext._display_mode.Height = _properties.get_y_size(); 00352 00353 wdxdisplay9_cat.debug() << "device width " << _wcontext._presentation_params.BackBufferWidth << "\n"; 00354 if (!_dxgsg->create_swap_chain(&_wcontext)) { 00355 discard_device = true; 00356 continue; // try again 00357 } 00358 init_resized_window(); 00359 break; 00360 } 00361 } 00362 wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n"; 00363 return true; 00364 } 00365 00366 //////////////////////////////////////////////////////////////////// 00367 // Function: wdxGraphicsWindow9::reset_window 00368 // Access: Public, Virtual 00369 // Description: Resets the window framebuffer right now. Called 00370 // from graphicsEngine. It releases the current swap 00371 // chain / creates a new one. If this is the initial 00372 // window and swapchain is false, then it calls reset_ 00373 // main_device to Reset the device. 00374 //////////////////////////////////////////////////////////////////// 00375 void wdxGraphicsWindow9:: 00376 reset_window(bool swapchain) { 00377 if (swapchain) { 00378 if (_wcontext._swap_chain) { 00379 _dxgsg->create_swap_chain(&_wcontext); 00380 wdxdisplay9_cat.debug() << "created swapchain " << _wcontext._swap_chain << "\n"; 00381 } 00382 } 00383 else { 00384 if (_wcontext._swap_chain) { 00385 _dxgsg->release_swap_chain(&_wcontext); 00386 wdxdisplay9_cat.debug() << "released swapchain " << _wcontext._swap_chain << "\n"; 00387 } 00388 } 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: wdxGraphicsWindow9::fullscreen_restored 00393 // Access: Protected, Virtual 00394 // Description: This is a hook for derived classes to do something 00395 // special, if necessary, when a fullscreen window has 00396 // been restored after being minimized. The given 00397 // WindowProperties struct will be applied to this 00398 // window's properties after this function returns. 00399 //////////////////////////////////////////////////////////////////// 00400 void wdxGraphicsWindow9:: 00401 fullscreen_restored(WindowProperties &properties) { 00402 // In DX8, unlike DX7, for some reason we can't immediately start 00403 // rendering as soon as the window is restored, even though 00404 // BeginScene() says we can. Instead, we have to wait until 00405 // TestCooperativeLevel() lets us in. We need to set a flag so we 00406 // can handle this special case in begin_frame(). 00407 if (_dxgsg != NULL) { 00408 _awaiting_restore = true; 00409 } 00410 } 00411 00412 //////////////////////////////////////////////////////////////////// 00413 // Function: wdxGraphicsWindow9::handle_reshape 00414 // Access: Protected, Virtual 00415 // Description: Called in the window thread when the window size or 00416 // location is changed, this updates the properties 00417 // structure accordingly. 00418 //////////////////////////////////////////////////////////////////// 00419 void wdxGraphicsWindow9:: 00420 handle_reshape() { 00421 GdiFlush(); 00422 WinGraphicsWindow::handle_reshape(); 00423 00424 if (_dxgsg != NULL) { 00425 // create the new resized rendertargets 00426 WindowProperties props = get_properties(); 00427 int x_size = props.get_x_size(); 00428 int y_size = props.get_y_size(); 00429 00430 if (_wcontext._presentation_params.BackBufferWidth != x_size || 00431 _wcontext._presentation_params.BackBufferHeight != y_size) { 00432 bool resize_succeeded = reset_device_resize_window(x_size, y_size); 00433 00434 if (wdxdisplay9_cat.is_debug()) { 00435 if (!resize_succeeded) { 00436 wdxdisplay9_cat.debug() 00437 << "windowed_resize to size: (" << x_size << ", " << y_size 00438 << ") failed due to out-of-memory\n"; 00439 } else { 00440 int x_origin = props.get_x_origin(); 00441 int y_origin = props.get_y_origin(); 00442 wdxdisplay9_cat.debug() 00443 << "windowed_resize to origin: (" << x_origin << ", " 00444 << y_origin << "), size: (" << x_size 00445 << ", " << y_size << ")\n"; 00446 } 00447 } 00448 } 00449 } 00450 } 00451 00452 //////////////////////////////////////////////////////////////////// 00453 // Function: wdxGraphicsWindow9::do_fullscreen_resize 00454 // Access: Protected, Virtual 00455 // Description: Called in the window thread to resize a fullscreen 00456 // window. 00457 //////////////////////////////////////////////////////////////////// 00458 bool wdxGraphicsWindow9:: 00459 do_fullscreen_resize(int x_size, int y_size) { 00460 if (!WinGraphicsWindow::do_fullscreen_resize(x_size, y_size)) { 00461 return false; 00462 } 00463 00464 bool bCouldntFindValidZBuf; 00465 D3DFORMAT pixFmt; 00466 bool bNeedZBuffer = (_wcontext._presentation_params.EnableAutoDepthStencil != false); 00467 bool bNeedStencilBuffer = IS_STENCIL_FORMAT(_wcontext._presentation_params.AutoDepthStencilFormat); 00468 00469 wdxGraphicsPipe9 *dxpipe; 00470 DCAST_INTO_R(dxpipe, _pipe, false); 00471 00472 bool bIsGoodMode = false; 00473 bool bResizeSucceeded = false; 00474 00475 if (!dxpipe->special_check_fullscreen_resolution(_wcontext, x_size, y_size)) { 00476 // bypass the lowvidmem test below for certain "lowmem" cards we know have valid modes 00477 00478 if (_wcontext._is_low_memory_card && (!((x_size == 640) && (y_size == 480)))) { 00479 wdxdisplay9_cat.error() << "resize() failed: will not try to resize low vidmem device #" << _wcontext._card_id << " to non-640x480!\n"; 00480 return bResizeSucceeded; 00481 } 00482 } 00483 00484 // must ALWAYS use search_for_valid_displaymode even if we know 00485 // a-priori that res is valid so we can get a valid pixfmt 00486 dxpipe->search_for_valid_displaymode(_wcontext, x_size, y_size, 00487 bNeedZBuffer, bNeedStencilBuffer, 00488 &_wcontext._supported_screen_depths_mask, 00489 &bCouldntFindValidZBuf, 00490 &pixFmt, dx_force_16bpp_zbuffer, true); 00491 bIsGoodMode = (pixFmt != D3DFMT_UNKNOWN); 00492 00493 if (!bIsGoodMode) { 00494 wdxdisplay9_cat.error() << "resize() failed: " 00495 << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") 00496 << " at " << x_size << "x" << y_size << " for device #" << _wcontext._card_id << endl; 00497 return bResizeSucceeded; 00498 } 00499 00500 // reset_device_resize_window handles both windowed & fullscrn, 00501 // so need to set new displaymode manually here 00502 _wcontext._display_mode.Width = x_size; 00503 _wcontext._display_mode.Height = y_size; 00504 _wcontext._display_mode.Format = pixFmt; 00505 _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT; 00506 // keep the previous setting for _wcontext._presentation_params.BackBufferFormat 00507 00508 bResizeSucceeded = reset_device_resize_window(x_size, y_size); 00509 00510 if (!bResizeSucceeded) { 00511 wdxdisplay9_cat.error() << "resize() failed with OUT-OF-MEMORY error!\n"; 00512 00513 if ((!IS_16BPP_DISPLAY_FORMAT(_wcontext._presentation_params.BackBufferFormat)) && 00514 (_wcontext._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { 00515 // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers 00516 _wcontext._display_mode.Format = ((_wcontext._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); 00517 dx_force_16bpp_zbuffer = true; 00518 if (wdxdisplay9_cat.info()) 00519 wdxdisplay9_cat.info() << "CreateDevice failed with out-of-vidmem, retrying w/16bpp buffers on device #" << _wcontext._card_id << endl; 00520 00521 bResizeSucceeded = reset_device_resize_window(x_size, y_size); // create the new resized rendertargets 00522 } 00523 } 00524 00525 return bResizeSucceeded; 00526 } 00527 00528 //////////////////////////////////////////////////////////////////// 00529 // Function: wdxGraphicsWindow9::create_screen_buffers_and_device 00530 // Access: Private 00531 // Description: Called whenever the window is resized, this recreates 00532 // the necessary buffers for rendering. 00533 // 00534 // Sets _depth_buffer_bpp appropriately. 00535 //////////////////////////////////////////////////////////////////// 00536 bool wdxGraphicsWindow9:: 00537 create_screen_buffers_and_device(DXScreenData &display, bool force_16bpp_zbuffer) { 00538 wdxGraphicsPipe9 *dxpipe; 00539 DCAST_INTO_R(dxpipe, _pipe, false); 00540 00541 DWORD dwRenderWidth = display._display_mode.Width; 00542 DWORD dwRenderHeight = display._display_mode.Height; 00543 DWORD dwBehaviorFlags = 0x0; 00544 LPDIRECT3D9 _d3d9 = display._d3d9; 00545 D3DCAPS9 *pD3DCaps = &display._d3dcaps; 00546 D3DPRESENT_PARAMETERS* presentation_params = &display._presentation_params; 00547 RECT view_rect; 00548 UINT adapter; 00549 D3DDEVTYPE device_type; 00550 HRESULT hr; 00551 00552 adapter = display._card_id; 00553 device_type = D3DDEVTYPE_HAL; 00554 00555 // NVIDIA NVPerfHUD 00556 if (dx_use_nvperfhud) { 00557 UINT adapter_id; 00558 UINT total_adapters; 00559 00560 total_adapters = _d3d9 -> GetAdapterCount ( ); 00561 for (adapter_id = 0; adapter_id < total_adapters; adapter_id++) { 00562 D3DADAPTER_IDENTIFIER9 identifier; 00563 00564 _d3d9 -> GetAdapterIdentifier (adapter_id, 0, &identifier); 00565 if (strcmp ("NVIDIA NVPerfHUD", identifier.Description) == 0) { 00566 adapter = adapter_id; 00567 device_type = D3DDEVTYPE_REF; 00568 break; 00569 } 00570 } 00571 } 00572 00573 wdxdisplay9_cat.debug() << "Display Width " << dwRenderWidth << " and PresParam Width " << _wcontext._presentation_params.BackBufferWidth << "\n"; 00574 00575 // BUGBUG: need to change panda to put frame buffer properties with GraphicsWindow, not GSG!! 00576 // Update: Did I fix the bug? - Josh 00577 bool bWantStencil = (_fb_properties.get_stencil_bits() > 0); 00578 bool bWantAlpha = (_fb_properties.get_alpha_bits() > 0); 00579 00580 PRINT_REFCNT(wdxdisplay9, _d3d9); 00581 00582 nassertr(_d3d9 != NULL, false); 00583 nassertr(pD3DCaps->DevCaps & D3DDEVCAPS_HWRASTERIZATION, false); 00584 00585 bool do_sync = sync_video; 00586 00587 if (do_sync && !(pD3DCaps->Caps & D3DCAPS_READ_SCANLINE)) { 00588 wdxdisplay9_cat.info() 00589 << "HW doesnt support syncing to vertical refresh, ignoring sync-video\n"; 00590 do_sync = false; 00591 } 00592 00593 presentation_params->BackBufferFormat = display._display_mode.Format; 00594 00595 // check for D3DFMT_A8R8G8B8 first 00596 if (bWantAlpha) { 00597 if (!FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET, 00598 D3DRTYPE_SURFACE, D3DFMT_A8R8G8B8))) { 00599 if (!FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, D3DFMT_A8R8G8B8, 00600 is_fullscreen()))) { 00601 // We can accept D3DFMT_A8R8G8B8, so use it. 00602 presentation_params->BackBufferFormat = D3DFMT_A8R8G8B8; 00603 } 00604 } 00605 } 00606 00607 // check for same format as display_mode 00608 // verify the rendertarget fmt 00609 if (FAILED(_d3d9->CheckDeviceFormat(adapter, device_type, display._display_mode.Format, D3DUSAGE_RENDERTARGET, 00610 D3DRTYPE_SURFACE, presentation_params->BackBufferFormat))) { 00611 wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceFmt failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl; 00612 goto Fallback_to_16bpp_buffers; 00613 } 00614 00615 if (FAILED(_d3d9->CheckDeviceType(adapter, device_type, display._display_mode.Format, presentation_params->BackBufferFormat, 00616 is_fullscreen()))) { 00617 wdxdisplay9_cat.error() << "adapter #" << adapter << " CheckDeviceType failed for surface fmt " << D3DFormatStr(presentation_params->BackBufferFormat) << endl; 00618 goto Fallback_to_16bpp_buffers; 00619 } 00620 00621 if (display._presentation_params.EnableAutoDepthStencil) { 00622 if (!dxpipe->find_best_depth_format(display, display._display_mode, 00623 &display._presentation_params.AutoDepthStencilFormat, 00624 bWantStencil, false)) { 00625 wdxdisplay9_cat.error() 00626 << "find_best_depth_format failed in CreateScreenBuffers for device #" 00627 << adapter << endl; 00628 goto Fallback_to_16bpp_buffers; 00629 } 00630 _depth_buffer_bpp = D3DFMT_to_DepthBits(display._presentation_params.AutoDepthStencilFormat); 00631 } else { 00632 _depth_buffer_bpp = 0; 00633 } 00634 00635 presentation_params->Windowed = !is_fullscreen(); 00636 00637 int supported_multisamples = 0; 00638 if (framebuffer_multisample.get_value()){ 00639 supported_multisamples = multisamples.get_value(); 00640 } 00641 00642 while (supported_multisamples > 1){ 00643 // need to check both rendertarget and zbuffer fmts 00644 hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._display_mode.Format, 00645 is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL); 00646 if (FAILED(hr)) { 00647 supported_multisamples--; 00648 continue; 00649 } 00650 00651 if (display._presentation_params.EnableAutoDepthStencil) { 00652 hr = _d3d9->CheckDeviceMultiSampleType(adapter, D3DDEVTYPE_HAL, display._presentation_params.AutoDepthStencilFormat, 00653 is_fullscreen(), D3DMULTISAMPLE_TYPE(supported_multisamples), NULL); 00654 if (FAILED(hr)) { 00655 supported_multisamples--; 00656 continue; 00657 } 00658 } 00659 00660 presentation_params->MultiSampleType = D3DMULTISAMPLE_TYPE(supported_multisamples); 00661 00662 if (wdxdisplay9_cat.is_info()) 00663 wdxdisplay9_cat.info() << "adapter #" << adapter << " using multisample antialiasing level: " << supported_multisamples << 00664 ". Requested level was: " << multisamples.get_value() << endl; 00665 break; 00666 } 00667 00668 presentation_params->BackBufferCount = 1; 00669 presentation_params->Flags = 0x0; 00670 presentation_params->hDeviceWindow = display._window; 00671 presentation_params->BackBufferWidth = display._display_mode.Width; 00672 presentation_params->BackBufferHeight = display._display_mode.Height; 00673 00674 if (_wcontext._is_tnl_device) { 00675 dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; 00676 // note: we could create a pure device in this case if I 00677 // eliminated the GetRenderState calls in dxgsg 00678 00679 // also, no software vertex processing available since I specify 00680 // D3DCREATE_HARDWARE_VERTEXPROCESSING and not 00681 // D3DCREATE_MIXED_VERTEXPROCESSING 00682 } else { 00683 dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; 00684 } 00685 00686 if (dx_preserve_fpu_state) 00687 dwBehaviorFlags |= D3DCREATE_FPU_PRESERVE; 00688 00689 // if window is not foreground in exclusive mode, ddraw thinks you 00690 // are 'not active', so it changes your WM_ACTIVATEAPP from true to 00691 // false, causing us to go into a 'wait-for WM_ACTIVATEAPP true' 00692 // loop, and the event never comes so we hang in fullscreen wait. 00693 // also doing this for windowed mode since it was requested. 00694 if (!SetForegroundWindow(display._window)) { 00695 wdxdisplay9_cat.warning() << "SetForegroundWindow() failed!\n"; 00696 } 00697 00698 if (dx_use_multithread) { 00699 dwBehaviorFlags |= D3DCREATE_MULTITHREADED; 00700 } 00701 if (dx_use_puredevice) { 00702 dwBehaviorFlags |= D3DCREATE_PUREDEVICE; 00703 } 00704 00705 if (dx_disable_driver_management) { 00706 dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT; 00707 } 00708 if (dx_disable_driver_management_ex) { 00709 dwBehaviorFlags |= D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX; 00710 } 00711 00712 if (is_fullscreen()) { 00713 // CREATE FULLSCREEN BUFFERS 00714 00715 presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; // we don't care about preserving contents of old frame 00716 presentation_params->PresentationInterval = (do_sync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE); 00717 presentation_params->FullScreen_RefreshRateInHz = display._display_mode.RefreshRate; 00718 00719 ClearToBlack(display._window, get_properties()); 00720 00721 hr = _d3d9->CreateDevice(adapter, device_type, _hWnd, 00722 dwBehaviorFlags, presentation_params, &display._d3d_device); 00723 00724 if (FAILED(hr)) { 00725 wdxdisplay9_cat.fatal() << "D3D CreateDevice failed for adapter #" << adapter << ", " << D3DERRORSTRING(hr); 00726 00727 if (hr == D3DERR_OUTOFVIDEOMEMORY) 00728 goto Fallback_to_16bpp_buffers; 00729 else 00730 return false; 00731 } 00732 00733 SetRect(&view_rect, 0, 0, dwRenderWidth, dwRenderHeight); 00734 00735 } else { 00736 // CREATE WINDOWED BUFFERS 00737 00738 D3DDISPLAYMODE dispmode; 00739 hr = display._d3d9->GetAdapterDisplayMode(adapter, &dispmode); 00740 00741 if (FAILED(hr)) { 00742 wdxdisplay9_cat.fatal() 00743 << "GetAdapterDisplayMode failed" << D3DERRORSTRING(hr); 00744 return false; 00745 } 00746 00747 if (dispmode.Format == D3DFMT_P8) { 00748 wdxdisplay9_cat.fatal() 00749 << "Can't run windowed in an 8-bit or less display mode" << endl; 00750 return false; 00751 } 00752 00753 //From d3d8caps.h 00754 //D3DPRESENT_INTERVAL_DEFAULT = 0x00000000L 00755 //#define D3DPRESENT_INTERVAL_ONE 0x00000001L 00756 //Next line is really sloppy, should either be D3DPRESENT_INTERVAL_DEFAULT or D3DPRESENT_INTERVAL_ONE 00757 //not a direct number! but I'm not going to touch it because it's working as is. Zhao 12/15/2011 00758 presentation_params->PresentationInterval = 0; 00759 00760 //ATI 5450 doesn't like D3DSWAPEFFECT_FLIP 00761 presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; 00762 if (do_sync == false) { 00763 presentation_params->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 00764 } 00765 // if (supported_multisamples<2) { 00766 // if (do_sync) { 00767 // // It turns out that COPY_VSYNC has real performance problems 00768 // // on many nVidia cards--it syncs at some random interval, 00769 // // possibly skipping over several video syncs. Screw it, 00770 // // we'll effectively disable sync-video with windowed mode 00771 // // using DirectX8. 00772 // //presentation_params->SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; 00773 // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; 00774 // } else { 00775 // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; 00776 // } 00777 00778 // // override presentation parameters for windowed mode, render and display at maximum speed 00779 // if (do_sync == false) { 00780 // presentation_params->SwapEffect = D3DSWAPEFFECT_FLIP; 00781 // presentation_params->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 00782 // } 00783 // } else { 00784 // presentation_params->SwapEffect = D3DSWAPEFFECT_DISCARD; 00785 // } 00786 00787 //assert((dwRenderWidth == presentation_params->BackBufferWidth)&&(dwRenderHeight == presentation_params->BackBufferHeight)); 00788 00789 hr = _d3d9->CreateDevice(adapter, device_type, _hWnd, 00790 dwBehaviorFlags, presentation_params, &display._d3d_device); 00791 00792 if (FAILED(hr)) { 00793 wdxdisplay9_cat.warning() << "presentation_params->BackBufferWidth : " << presentation_params->BackBufferWidth << endl; 00794 wdxdisplay9_cat.warning() << "presentation_params->BackBufferHeight : " << presentation_params->BackBufferHeight << endl; 00795 wdxdisplay9_cat.warning() << "presentation_params->BackBufferFormat : " << presentation_params->BackBufferFormat << endl; 00796 wdxdisplay9_cat.warning() << "presentation_params->BackBufferCount : " << presentation_params->BackBufferCount << endl; 00797 wdxdisplay9_cat.warning() << "D3D CreateDevice failed for adapter #" << adapter << D3DERRORSTRING(hr); 00798 goto Fallback_to_16bpp_buffers; 00799 } 00800 } // end create windowed buffers 00801 00802 // ======================================================== 00803 00804 PRINT_REFCNT(wdxdisplay9, _wcontext._d3d_device); 00805 00806 if (presentation_params->EnableAutoDepthStencil) { 00807 int depth_bits; 00808 int stencil_bits; 00809 00810 depth_bits = 1; 00811 stencil_bits = 0; 00812 switch (presentation_params->AutoDepthStencilFormat) 00813 { 00814 case D3DFMT_D16_LOCKABLE: 00815 depth_bits = 16; 00816 break; 00817 case D3DFMT_D32: 00818 depth_bits = 32; 00819 break; 00820 case D3DFMT_D15S1: 00821 depth_bits = 15; 00822 stencil_bits = 1; 00823 break; 00824 case D3DFMT_D24S8: 00825 depth_bits = 24; 00826 stencil_bits = 8; 00827 break; 00828 case D3DFMT_D24X8: 00829 depth_bits = 24; 00830 break; 00831 case D3DFMT_D24X4S4: 00832 depth_bits = 24; 00833 stencil_bits = 4; 00834 break; 00835 case D3DFMT_D32F_LOCKABLE: 00836 depth_bits = 32; 00837 break; 00838 case D3DFMT_D24FS8: 00839 depth_bits = 24; 00840 stencil_bits = 8; 00841 break; 00842 case D3DFMT_D16: 00843 depth_bits = 16; 00844 break; 00845 default: 00846 wdxdisplay9_cat.error() << "unknown depth stencil format " << presentation_params->AutoDepthStencilFormat; 00847 break; 00848 } 00849 00850 _fb_properties.set_stencil_bits(stencil_bits); 00851 _fb_properties.set_depth_bits(depth_bits); 00852 } else { 00853 _fb_properties.set_depth_bits(0); 00854 _fb_properties.set_stencil_bits(0); 00855 } 00856 00857 init_resized_window(); 00858 00859 return true; 00860 00861 Fallback_to_16bpp_buffers: 00862 if ((!IS_16BPP_DISPLAY_FORMAT(presentation_params->BackBufferFormat)) && 00863 (display._supported_screen_depths_mask & (R5G6B5_FLAG|X1R5G5B5_FLAG))) { 00864 // fallback strategy, if we trying >16bpp, fallback to 16bpp buffers 00865 00866 display._display_mode.Format = ((display._supported_screen_depths_mask & R5G6B5_FLAG) ? D3DFMT_R5G6B5 : D3DFMT_X1R5G5B5); 00867 00868 if (wdxdisplay9_cat.info()) { 00869 wdxdisplay9_cat.info() 00870 << "CreateDevice failed with out-of-vidmem or invalid BackBufferFormat, retrying w/16bpp buffers on adapter #" 00871 << adapter << endl; 00872 } 00873 return create_screen_buffers_and_device(display, true); 00874 //return; 00875 00876 } else if (!((dwRenderWidth == 640)&&(dwRenderHeight == 480))) { 00877 if (wdxdisplay9_cat.info()) 00878 wdxdisplay9_cat.info() << "CreateDevice failed w/out-of-vidmem, retrying at 640x480 w/16bpp buffers on adapter #" << adapter << endl; 00879 // try final fallback to 640x480x16 00880 display._display_mode.Width = 640; 00881 display._display_mode.Height = 480; 00882 return create_screen_buffers_and_device(display, true); 00883 //return; 00884 00885 } else { 00886 wdxdisplay9_cat.fatal() 00887 << "Can't create any screen buffers, bailing out.\n"; 00888 return false; 00889 } 00890 } 00891 00892 //////////////////////////////////////////////////////////////////// 00893 // Function: wdxGraphicsWindow9::choose_device 00894 // Access: Private 00895 // Description: Looks at the list of available graphics adapters and 00896 // chooses a suitable one for the window. 00897 // 00898 // Returns true if successful, false on failure. 00899 //////////////////////////////////////////////////////////////////// 00900 bool wdxGraphicsWindow9:: 00901 choose_device() { 00902 HRESULT hr; 00903 00904 wdxGraphicsPipe9 *dxpipe; 00905 DCAST_INTO_R(dxpipe, _pipe, false); 00906 00907 int num_adapters = dxpipe->__d3d9->GetAdapterCount(); 00908 DXDeviceInfoVec device_infos; 00909 00910 for (int i = 0; i < num_adapters; i++) { 00911 D3DADAPTER_IDENTIFIER9 adapter_info; 00912 ZeroMemory(&adapter_info, sizeof(D3DADAPTER_IDENTIFIER9)); 00913 hr = dxpipe->__d3d9->GetAdapterIdentifier(i, 0, &adapter_info); 00914 if (FAILED(hr)) { 00915 wdxdisplay9_cat.fatal() 00916 << "D3D GetAdapterID(" << i << ") failed: " 00917 << D3DERRORSTRING(hr) << endl; 00918 continue; 00919 } 00920 00921 LARGE_INTEGER *DrvVer = &adapter_info.DriverVersion; 00922 00923 wdxdisplay9_cat.info() 00924 << "D3D9." << (dxpipe->__is_dx9_1 ?"1":"0") << " Adapter[" << i << "]: " << adapter_info.Description 00925 << ", Driver: " << adapter_info.Driver << ", DriverVersion: (" 00926 << HIWORD(DrvVer->HighPart) << "." << LOWORD(DrvVer->HighPart) << "." 00927 << HIWORD(DrvVer->LowPart) << "." << LOWORD(DrvVer->LowPart) 00928 << ")\nVendorID: 0x" << (void*) adapter_info.VendorId 00929 << " DeviceID: 0x" << (void*) adapter_info.DeviceId 00930 << " SubsysID: 0x" << (void*) adapter_info.SubSysId 00931 << " Revision: 0x" << (void*) adapter_info.Revision << endl; 00932 00933 HMONITOR _monitor = dxpipe->__d3d9->GetAdapterMonitor(i); 00934 if (_monitor == NULL) { 00935 wdxdisplay9_cat.info() 00936 << "D3D9 Adapter[" << i << "]: seems to be disabled, skipping it\n"; 00937 continue; 00938 } 00939 00940 DXDeviceInfo devinfo; 00941 ZeroMemory(&devinfo, sizeof(devinfo)); 00942 memcpy(&devinfo.guidDeviceIdentifier, &adapter_info.DeviceIdentifier, 00943 sizeof(GUID)); 00944 strncpy(devinfo.szDescription, adapter_info.Description, 00945 MAX_DEVICE_IDENTIFIER_STRING); 00946 strncpy(devinfo.szDriver, adapter_info.Driver, 00947 MAX_DEVICE_IDENTIFIER_STRING); 00948 devinfo.VendorID = adapter_info.VendorId; 00949 devinfo.DeviceID = adapter_info.DeviceId; 00950 devinfo._driver_version = adapter_info.DriverVersion; 00951 devinfo._monitor = _monitor; 00952 devinfo.cardID = i; 00953 00954 device_infos.push_back(devinfo); 00955 } 00956 00957 if (device_infos.empty()) { 00958 wdxdisplay9_cat.error() 00959 << "No available D3D9 devices found.\n"; 00960 return false; 00961 } 00962 00963 // Since some adapters may have been disabled, we should re-obtain 00964 // the number of available adapters. 00965 num_adapters = (int)device_infos.size(); 00966 00967 // Now choose a suitable adapter. 00968 00969 int adapter_num = D3DADAPTER_DEFAULT; 00970 00971 // Eventually, we should have some interface for specifying a device 00972 // index interactively, instead of only via Configrc. 00973 if (dx_preferred_device_id != -1) { 00974 if (dx_preferred_device_id < 0 || dx_preferred_device_id >= num_adapters) { 00975 wdxdisplay9_cat.error() 00976 << "invalid 'dx-preferred-device-id', valid values are 0-" 00977 << num_adapters - 1 << ", using default adapter instead.\n"; 00978 } else { 00979 adapter_num = dx_preferred_device_id; 00980 } 00981 } 00982 00983 // Try to select the default or requested device. 00984 if (adapter_num >= 0 && adapter_num < (int)device_infos.size()) { 00985 if (consider_device(dxpipe, &device_infos[adapter_num])) { 00986 wdxdisplay9_cat.info() 00987 << "Selected device " << adapter_num << " (of " 00988 << device_infos.size() << ", zero-based)\n"; 00989 return true; 00990 } 00991 wdxdisplay9_cat.info() 00992 << "Could not select device " << adapter_num << "\n"; 00993 } 00994 00995 // Iterate through all available devices to find the first suitable 00996 // one. 00997 for (UINT devnum = 0; devnum < device_infos.size(); ++devnum) { 00998 if (consider_device(dxpipe, &device_infos[devnum])) { 00999 wdxdisplay9_cat.info() 01000 << "Chose device " << devnum << " (of " 01001 << device_infos.size() << ", zero-based): first one that works.\n"; 01002 return true; 01003 } 01004 } 01005 01006 wdxdisplay9_cat.error() << "no usable display devices.\n"; 01007 return false; 01008 } 01009 01010 //////////////////////////////////////////////////////////////////// 01011 // Function: wdxGraphicsWindow9::consider_device 01012 // Access: Private 01013 // Description: If the specified device is acceptable, sets it as the 01014 // current device and returns true; otherwise, returns 01015 // false. 01016 //////////////////////////////////////////////////////////////////// 01017 bool wdxGraphicsWindow9:: 01018 consider_device(wdxGraphicsPipe9 *dxpipe, DXDeviceInfo *device_info) { 01019 01020 nassertr(dxpipe != NULL, false); 01021 WindowProperties properties = get_properties(); 01022 DWORD dwRenderWidth = properties.get_x_size(); 01023 DWORD dwRenderHeight = properties.get_y_size(); 01024 HRESULT hr; 01025 LPDIRECT3D9 _d3d9 = dxpipe->__d3d9; 01026 01027 nassertr(_dxgsg != NULL, false); 01028 _wcontext._d3d9 = _d3d9; 01029 _wcontext._is_dx9_1 = dxpipe->__is_dx9_1; 01030 _wcontext._card_id = device_info->cardID; // could this change by end? 01031 01032 bool bWantStencil = (_fb_properties.get_stencil_bits() > 0); 01033 01034 hr = _d3d9->GetAdapterIdentifier(device_info->cardID, 0, 01035 &_wcontext._dx_device_id); 01036 if (FAILED(hr)) { 01037 wdxdisplay9_cat.error() 01038 << "D3D GetAdapterID failed" << D3DERRORSTRING(hr); 01039 return false; 01040 } 01041 01042 D3DCAPS9 _d3dcaps; 01043 hr = _d3d9->GetDeviceCaps(device_info->cardID, D3DDEVTYPE_HAL, &_d3dcaps); 01044 if (FAILED(hr)) { 01045 if ((hr == D3DERR_INVALIDDEVICE)||(hr == D3DERR_NOTAVAILABLE)) { 01046 wdxdisplay9_cat.error() 01047 << "No DirectX 9 D3D-capable 3D hardware detected for device # " 01048 << device_info->cardID << " (" << device_info->szDescription 01049 << ")!\n"; 01050 } else { 01051 wdxdisplay9_cat.error() 01052 << "GetDeviceCaps failed: " << D3DERRORSTRING(hr) << endl; 01053 } 01054 return false; 01055 } 01056 01057 //search_for_valid_displaymode needs these to be set 01058 memcpy(&_wcontext._d3dcaps, &_d3dcaps, sizeof(D3DCAPS9)); 01059 _wcontext._card_id = device_info->cardID; 01060 01061 _wcontext._max_available_video_memory = UNKNOWN_VIDMEM_SIZE; 01062 _wcontext._is_low_memory_card = false; 01063 01064 // bugbug: wouldnt we like to do GetAVailVidMem so we can do 01065 // upper-limit memory computation for dx8 cards too? otherwise 01066 // verify_window_sizes cant do much 01067 if (_d3dcaps.MaxStreams == 0) { 01068 if (wdxdisplay9_cat.is_debug()) { 01069 wdxdisplay9_cat.debug() 01070 << "checking vidmem size\n"; 01071 } 01072 01073 UINT IDnum; 01074 01075 // simple linear search to match DX7 card info w/DX8 card ID 01076 for (IDnum = 0; IDnum < dxpipe->_card_ids.size(); IDnum++) { 01077 if ((device_info->VendorID == dxpipe->_card_ids[IDnum].VendorID) && 01078 (device_info->DeviceID == dxpipe->_card_ids[IDnum].DeviceID) && 01079 (device_info->_monitor == dxpipe->_card_ids[IDnum]._monitor)) 01080 break; 01081 } 01082 01083 if (IDnum < dxpipe->_card_ids.size()) { 01084 _wcontext._max_available_video_memory = dxpipe->_card_ids[IDnum]._max_available_video_memory; 01085 _wcontext._is_low_memory_card = dxpipe->_card_ids[IDnum]._is_low_memory_card; 01086 } else { 01087 wdxdisplay9_cat.error() 01088 << "Error: couldnt find a CardID match in DX7 info, assuming card is not a lowmem card\n"; 01089 } 01090 } 01091 01092 if ((bWantStencil) && (_d3dcaps.StencilCaps == 0x0)) { 01093 wdxdisplay9_cat.fatal() 01094 << "Stencil ability requested, but device #" << device_info->cardID 01095 << " (" << _wcontext._dx_device_id.Description 01096 << "), has no stencil capability!\n"; 01097 return false; 01098 } 01099 01100 // just because TNL is true, it doesnt mean vtx shaders are 01101 // supported in HW (see GF2) for this case, you probably want MIXED 01102 // processing to use HW for fixed-fn vertex processing and SW for 01103 // vtx shaders 01104 _wcontext._is_tnl_device = 01105 ((_d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0); 01106 _wcontext._can_use_hw_vertex_shaders = 01107 (_d3dcaps.VertexShaderVersion >= D3DVS_VERSION(1, 0)); 01108 _wcontext._can_use_pixel_shaders = 01109 (_d3dcaps.PixelShaderVersion >= D3DPS_VERSION(1, 0)); 01110 01111 bool bNeedZBuffer = 01112 ((!(_d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )) && 01113 (_fb_properties.get_depth_bits() > 0)); 01114 01115 _wcontext._presentation_params.EnableAutoDepthStencil = bNeedZBuffer; 01116 01117 D3DFORMAT pixFmt = D3DFMT_UNKNOWN; 01118 01119 if (is_fullscreen()) { 01120 bool bCouldntFindValidZBuf; 01121 01122 dxpipe->search_for_valid_displaymode(_wcontext, dwRenderWidth, dwRenderHeight, 01123 bNeedZBuffer, bWantStencil, 01124 &_wcontext._supported_screen_depths_mask, 01125 &bCouldntFindValidZBuf, 01126 &pixFmt, dx_force_16bpp_zbuffer, true); 01127 01128 // note I'm not saving refresh rate, will just use adapter 01129 // default at given res for now 01130 01131 if (pixFmt == D3DFMT_UNKNOWN) { 01132 wdxdisplay9_cat.error() 01133 << (bCouldntFindValidZBuf ? "Couldnt find valid zbuffer format to go with FullScreen mode" : "No supported FullScreen modes") 01134 << " at " << dwRenderWidth << "x" << dwRenderHeight << " for device #" << _wcontext._card_id << endl; 01135 return false; 01136 } 01137 } else { 01138 // Windowed Mode 01139 01140 D3DDISPLAYMODE dispmode; 01141 hr = _d3d9->GetAdapterDisplayMode(device_info->cardID, &dispmode); 01142 if (FAILED(hr)) { 01143 wdxdisplay9_cat.error() 01144 << "GetAdapterDisplayMode(" << device_info->cardID 01145 << ") failed" << D3DERRORSTRING(hr); 01146 return false; 01147 } 01148 pixFmt = dispmode.Format; 01149 } 01150 01151 _wcontext._display_mode.Width = dwRenderWidth; 01152 _wcontext._display_mode.Height = dwRenderHeight; 01153 _wcontext._display_mode.Format = pixFmt; 01154 _wcontext._display_mode.RefreshRate = D3DPRESENT_RATE_DEFAULT; 01155 _wcontext._monitor = device_info->_monitor; 01156 01157 if (strcmp(device_info->szDriver, "igdumd32.dll") == 0 && 01158 device_info->_driver_version.QuadPart <= 0x0007000e000affffLL && 01159 dx_intel_compressed_texture_bug) { 01160 // Disable compressed textures for this buggy driver (7.14.10.65535 01161 // and earlier--I don't know whether any other drivers also 01162 // exhibit the bug). 01163 _wcontext._intel_compressed_texture_bug = true; 01164 } 01165 01166 return true; 01167 } 01168 01169 //////////////////////////////////////////////////////////////////// 01170 // Function: wdxGraphicsWindow9::reset_device_resize_window 01171 // Access: Private 01172 // Description: Called after a window (either fullscreen or windowed) 01173 // has been resized, this recreates the D3D structures 01174 // to match the new size. 01175 //////////////////////////////////////////////////////////////////// 01176 bool wdxGraphicsWindow9:: 01177 reset_device_resize_window(UINT new_xsize, UINT new_ysize) { 01178 bool retval = true; 01179 01180 DXScreenData *screen = NULL; 01181 D3DPRESENT_PARAMETERS d3dpp; 01182 memcpy(&d3dpp, &_wcontext._presentation_params, sizeof(D3DPRESENT_PARAMETERS)); 01183 _wcontext._presentation_params.BackBufferWidth = new_xsize; 01184 _wcontext._presentation_params.BackBufferHeight = new_ysize; 01185 make_current(); 01186 HRESULT hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen); 01187 01188 if (FAILED(hr)) { 01189 retval = false; 01190 wdxdisplay9_cat.error() 01191 << "reset_device_resize_window Reset() failed" << D3DERRORSTRING(hr); 01192 if (hr == D3DERR_OUTOFVIDEOMEMORY) { 01193 memcpy(&_wcontext._presentation_params, &d3dpp, sizeof(D3DPRESENT_PARAMETERS)); 01194 hr = _dxgsg->reset_d3d_device(&_wcontext._presentation_params, &screen); 01195 if (FAILED(hr)) { 01196 wdxdisplay9_cat.error() 01197 << "reset_device_resize_window Reset() failed OutOfVidmem, then failed again doing Reset w/original params:" << D3DERRORSTRING(hr); 01198 throw_event("panda3d-render-error"); 01199 return false; 01200 01201 } else { 01202 if (wdxdisplay9_cat.is_info()) { 01203 wdxdisplay9_cat.info() 01204 << "reset of original size (" << _wcontext._presentation_params.BackBufferWidth 01205 << ", " << _wcontext._presentation_params.BackBufferHeight << ") succeeded\n"; 01206 } 01207 } 01208 } else { 01209 wdxdisplay9_cat.fatal() 01210 << "Can't reset device, bailing out.\n"; 01211 throw_event("panda3d-render-error"); 01212 return false; 01213 } 01214 } 01215 // before you init_resized_window you need to copy certain changes to _wcontext 01216 if (screen) { 01217 _wcontext._swap_chain = screen->_swap_chain; 01218 } 01219 wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n"; 01220 _gsg->mark_new(); 01221 init_resized_window(); 01222 return retval; 01223 } 01224 01225 //////////////////////////////////////////////////////////////////// 01226 // Function: wdxGraphicsWindow9::init_resized_window 01227 // Access: Private 01228 // Description: Reinitializes the window after it has been resized, 01229 // or after it is first created. 01230 // 01231 // Assumes CreateDevice or Device->Reset() has just been 01232 // called, and the new size is specified in 01233 // _wcontext._presentation_params. 01234 //////////////////////////////////////////////////////////////////// 01235 void wdxGraphicsWindow9:: 01236 init_resized_window() { 01237 HRESULT hr; 01238 01239 DWORD newWidth = _wcontext._presentation_params.BackBufferWidth; 01240 DWORD newHeight = _wcontext._presentation_params.BackBufferHeight; 01241 01242 nassertv((newWidth != 0) && (newHeight != 0)); 01243 nassertv(_wcontext._window != NULL); 01244 01245 if (_wcontext._presentation_params.Windowed) { 01246 POINT ul, lr; 01247 RECT client_rect; 01248 01249 // need to figure out x, y origin offset of window client area on screen 01250 // (we already know the client area size) 01251 01252 GetClientRect(_wcontext._window, &client_rect); 01253 ul.x = client_rect.left; 01254 ul.y = client_rect.top; 01255 lr.x = client_rect.right; 01256 lr.y = client_rect.bottom; 01257 ClientToScreen(_wcontext._window, &ul); 01258 ClientToScreen(_wcontext._window, &lr); 01259 client_rect.left = ul.x; 01260 client_rect.top = ul.y; 01261 client_rect.right = lr.x; 01262 client_rect.bottom = lr.y; 01263 } 01264 01265 // clear window to black ASAP 01266 nassertv(_wcontext._window != NULL); 01267 ClearToBlack(_wcontext._window, get_properties()); 01268 01269 // clear textures and VB's out of video&AGP mem, so cache is reset 01270 hr = _wcontext._d3d_device->EvictManagedResources ( ); 01271 if (FAILED(hr)) { 01272 wdxdisplay9_cat.error() 01273 << "EvictManagedResources failed for device #" 01274 << _wcontext._card_id << D3DERRORSTRING(hr); 01275 } 01276 01277 make_current(); 01278 01279 // set render target before clearing 01280 _dxgsg->set_render_target ( ); 01281 01282 // clear back buffers 01283 DWORD flags; 01284 D3DCOLOR clear_color; 01285 01286 flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER; 01287 clear_color = 0x00000000; 01288 hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0); 01289 if (FAILED(hr)) { 01290 wdxdisplay9_cat.error() 01291 << "Clear failed for device" 01292 << D3DERRORSTRING(hr); 01293 } 01294 hr = _wcontext._d3d_device-> Present (NULL, NULL, NULL, NULL); 01295 if (FAILED(hr)) { 01296 wdxdisplay9_cat.error() 01297 << "Present failed for device" 01298 << D3DERRORSTRING(hr); 01299 } 01300 hr = _wcontext._d3d_device-> Clear (0, NULL, flags, clear_color, 0.0f, 0); 01301 if (FAILED(hr)) { 01302 wdxdisplay9_cat.error() 01303 << "Clear failed for device" 01304 << D3DERRORSTRING(hr); 01305 } 01306 } 01307 01308 //////////////////////////////////////////////////////////////////// 01309 // Function: wdxGraphicsWindow9::D3DFMT_to_DepthBits 01310 // Access: Private, Static 01311 // Description: Returns the number of depth bits represented by the 01312 // indicated D3DFORMAT value. 01313 //////////////////////////////////////////////////////////////////// 01314 int wdxGraphicsWindow9:: 01315 D3DFMT_to_DepthBits(D3DFORMAT fmt) { 01316 switch(fmt) { 01317 case D3DFMT_D16: 01318 return 16; 01319 01320 case D3DFMT_D24X8: 01321 case D3DFMT_D24X4S4: 01322 case D3DFMT_D24S8: 01323 return 24; 01324 01325 case D3DFMT_D32: 01326 return 32; 01327 01328 case D3DFMT_D15S1: 01329 return 15; 01330 01331 default: 01332 wdxdisplay9_cat.debug() 01333 << "D3DFMT_DepthBits: unhandled D3DFMT!\n"; 01334 return 0; 01335 } 01336 } 01337 01338 //////////////////////////////////////////////////////////////////// 01339 // Function: wdxGraphicsWindow9::is_badvidmem_card 01340 // Access: Private, Static 01341 // Description: Returns true if the indicated video adapter card is 01342 // known to report an inaccurate figure for available 01343 // video memory. 01344 //////////////////////////////////////////////////////////////////// 01345 bool wdxGraphicsWindow9:: 01346 is_badvidmem_card(D3DADAPTER_IDENTIFIER9 *pDevID) { 01347 // don't trust Intel cards since they often use regular memory as vidmem 01348 if (pDevID->VendorId == 0x00008086) { 01349 return true; 01350 } 01351 01352 return false; 01353 } 01354