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