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