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