Panda3D
|
00001 // Filename: wdxGraphicsPipe9.cxx 00002 // Created by: drose (20Dec02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "wdxGraphicsPipe9.h" 00016 #include "dxGraphicsDevice9.h" 00017 #include "wdxGraphicsWindow9.h" 00018 #include "wdxGraphicsBuffer9.h" 00019 #include "config_dxgsg9.h" 00020 00021 TypeHandle wdxGraphicsPipe9::_type_handle; 00022 00023 #define LOWVIDMEMTHRESHOLD 5700000 // 4MB cards should fall below this 00024 #define CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 1000000 // if # is > 1MB, card is lying and I cant tell what it is 00025 #define UNKNOWN_VIDMEM_SIZE 0xFFFFFFFF 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: wdxGraphicsPipe9::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 wdxGraphicsPipe9:: 00033 wdxGraphicsPipe9() { 00034 _hDDrawDLL = NULL; 00035 _hD3D9_DLL = NULL; 00036 __d3d9 = NULL; 00037 _is_valid = init(); 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: wdxGraphicsPipe9::Destructor 00042 // Access: Public, Virtual 00043 // Description: 00044 //////////////////////////////////////////////////////////////////// 00045 wdxGraphicsPipe9:: 00046 ~wdxGraphicsPipe9() { 00047 RELEASE(__d3d9, wdxdisplay9, "ID3D9", RELEASE_DOWN_TO_ZERO); 00048 SAFE_FREELIB(_hD3D9_DLL); 00049 SAFE_FREELIB(_hDDrawDLL); 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: wdxGraphicsPipe9::get_interface_name 00054 // Access: Published, Virtual 00055 // Description: Returns the name of the rendering interface 00056 // associated with this GraphicsPipe. This is used to 00057 // present to the user to allow him/her to choose 00058 // between several possible GraphicsPipes available on a 00059 // particular platform, so the name should be meaningful 00060 // and unique for a given platform. 00061 //////////////////////////////////////////////////////////////////// 00062 string wdxGraphicsPipe9:: 00063 get_interface_name() const { 00064 return "DirectX9"; 00065 } 00066 00067 //////////////////////////////////////////////////////////////////// 00068 // Function: wdxGraphicsPipe9::pipe_constructor 00069 // Access: Public, Static 00070 // Description: This function is passed to the GraphicsPipeSelection 00071 // object to allow the user to make a default 00072 // wdxGraphicsPipe9. 00073 //////////////////////////////////////////////////////////////////// 00074 PT(GraphicsPipe) wdxGraphicsPipe9:: 00075 pipe_constructor() { 00076 return new wdxGraphicsPipe9; 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: wdxGraphicsPipe9::make_output 00081 // Access: Protected, Virtual 00082 // Description: Creates a new window on the pipe, if possible. 00083 //////////////////////////////////////////////////////////////////// 00084 PT(GraphicsOutput) wdxGraphicsPipe9:: 00085 make_output(const string &name, 00086 const FrameBufferProperties &fb_prop, 00087 const WindowProperties &win_prop, 00088 int flags, 00089 GraphicsEngine *engine, 00090 GraphicsStateGuardian *gsg, 00091 GraphicsOutput *host, 00092 int retry, 00093 bool &precertify) { 00094 00095 if (!_is_valid) { 00096 return NULL; 00097 } 00098 00099 DXGraphicsStateGuardian9 *wdxgsg = 0; 00100 if (gsg != 0) { 00101 DCAST_INTO_R(wdxgsg, gsg, NULL); 00102 } 00103 00104 // First thing to try: a visible window. 00105 00106 if (retry == 0) { 00107 if (((flags&BF_require_parasite)!=0)|| 00108 ((flags&BF_refuse_window)!=0)|| 00109 ((flags&BF_resizeable)!=0)|| 00110 ((flags&BF_size_track_host)!=0)|| 00111 ((flags&BF_rtt_cumulative)!=0)|| 00112 ((flags&BF_can_bind_color)!=0)|| 00113 ((flags&BF_can_bind_every)!=0)) { 00114 return NULL; 00115 } 00116 // Early failure - if we are sure that this buffer WONT 00117 // meet specs, we can bail out early. 00118 if ((flags & BF_fb_props_optional) == 0) { 00119 if ((fb_prop.get_aux_rgba() > 0)|| 00120 (fb_prop.get_aux_rgba() > 0)|| 00121 (fb_prop.get_aux_float() > 0)) { 00122 return NULL; 00123 } 00124 } 00125 return new wdxGraphicsWindow9(engine, this, name, fb_prop, win_prop, 00126 flags, gsg, host); 00127 } 00128 00129 // Second thing to try: a wdxGraphicsBuffer9 00130 00131 if (retry == 1) { 00132 if ((!support_render_texture)|| 00133 ((flags&BF_require_parasite)!=0)|| 00134 ((flags&BF_require_window)!=0)|| 00135 ((flags&BF_rtt_cumulative)!=0)|| 00136 ((flags&BF_can_bind_every)!=0)) { 00137 return NULL; 00138 } 00139 // Early failure - if we are sure that this buffer WONT 00140 // meet specs, we can bail out early. 00141 if ((flags & BF_fb_props_optional) == 0) { 00142 if ((fb_prop.get_indexed_color() > 0)|| 00143 (fb_prop.get_back_buffers() > 0)|| 00144 (fb_prop.get_accum_bits() > 0)|| 00145 (fb_prop.get_multisamples() > 0)) { 00146 return NULL; 00147 } 00148 } 00149 00150 // Early success - if we are sure that this buffer WILL 00151 // meet specs, we can precertify it. 00152 // This looks rather overly optimistic -- ie, buggy. 00153 if ((gsg != 0)&& 00154 (gsg->is_valid())&& 00155 (!gsg->needs_reset())&& 00156 (DCAST(DXGraphicsStateGuardian9, gsg)->get_supports_render_texture())) { 00157 precertify = true; 00158 } 00159 return new wdxGraphicsBuffer9(engine, this, name, fb_prop, win_prop, 00160 flags, gsg, host); 00161 } 00162 00163 // Nothing else left to try. 00164 return NULL; 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: wdxGraphicsPipe9::init 00169 // Access: Private 00170 // Description: Performs some initialization steps to load up 00171 // function pointers from the relevant DLL's, and 00172 // determine the number and type of available graphics 00173 // adapters, etc. Returns true on success, false on 00174 // failure. 00175 //////////////////////////////////////////////////////////////////// 00176 bool wdxGraphicsPipe9:: 00177 init() { 00178 if (!MyLoadLib(_hDDrawDLL, "ddraw.dll")) { 00179 goto error; 00180 } 00181 00182 if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawCreateEx, "DirectDrawCreateEx")) { 00183 goto error; 00184 } 00185 00186 if (!MyGetProcAddr(_hDDrawDLL, (FARPROC*)&_DirectDrawEnumerateExA, "DirectDrawEnumerateExA")) { 00187 goto error; 00188 } 00189 00190 if (!MyLoadLib(_hD3D9_DLL, "d3d9.dll")) { 00191 goto error; 00192 } 00193 00194 if (!MyGetProcAddr(_hD3D9_DLL, (FARPROC*)&_Direct3DCreate9, "Direct3DCreate9")) { 00195 goto error; 00196 } 00197 00198 // Create a Direct3D object. 00199 00200 // these were taken from the 8.0 and 8.1 d3d8.h SDK headers 00201 __is_dx9_1 = false; 00202 00203 #define D3D_SDK_VERSION_9_0 D3D_SDK_VERSION 00204 #define D3D_SDK_VERSION_9_1 D3D_SDK_VERSION 00205 00206 // are we using 9.0 or 9.1? 00207 WIN32_FIND_DATA TempFindData; 00208 HANDLE hFind; 00209 char tmppath[_MAX_PATH + 128]; 00210 GetSystemDirectory(tmppath, MAX_PATH); 00211 strcat(tmppath, "\\dpnhpast.dll"); 00212 hFind = FindFirstFile (tmppath, &TempFindData); 00213 if (hFind != INVALID_HANDLE_VALUE) { 00214 FindClose(hFind); 00215 // ??? This was from DX8 00216 // __is_dx9_1 = true; 00217 __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_1); 00218 } else { 00219 __is_dx9_1 = false; 00220 __d3d9 = (*_Direct3DCreate9)(D3D_SDK_VERSION_9_0); 00221 } 00222 if (__d3d9 == NULL) { 00223 wdxdisplay9_cat.error() << "Direct3DCreate9(9." << (__is_dx9_1 ? "1" : "0") << ") failed!, error = " << GetLastError() << endl; 00224 //release_gsg(); 00225 goto error; 00226 } 00227 00228 Init_D3DFORMAT_map(); 00229 00230 if (dx_count_all_cards_memory){ 00231 return find_all_card_memavails(); 00232 } 00233 00234 return true; 00235 00236 error: 00237 return false; 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: wdxGraphicsPipe9::find_all_card_memavails 00242 // Access: Private 00243 // Description: Uses DX7 calls to determine how much video memory is 00244 // available for each video adapter in the system. 00245 // Returns true on success, false on failure. 00246 //////////////////////////////////////////////////////////////////// 00247 bool wdxGraphicsPipe9:: 00248 find_all_card_memavails() { 00249 HRESULT hr; 00250 00251 hr = (*_DirectDrawEnumerateExA)(dx7_driver_enum_callback, this, 00252 DDENUM_ATTACHEDSECONDARYDEVICES | DDENUM_NONDISPLAYDEVICES); 00253 if (FAILED(hr)) { 00254 wdxdisplay9_cat.fatal() 00255 << "DirectDrawEnumerateEx failed" << D3DERRORSTRING(hr); 00256 return false; 00257 } 00258 00259 if (_card_ids.empty()) { 00260 wdxdisplay9_cat.error() 00261 << "DirectDrawEnumerateEx enum'ed no devices!\n"; 00262 return false; 00263 } 00264 00265 GUID ZeroGUID; 00266 ZeroMemory(&ZeroGUID, sizeof(GUID)); 00267 00268 if (_card_ids.size() > 1) { 00269 assert(IsEqualGUID(ZeroGUID, _card_ids[0].DX7_DeviceGUID)); 00270 // delete enum of primary display (always the first), since it is 00271 // duplicated by explicit entry 00272 _card_ids.erase(_card_ids.begin()); 00273 } 00274 00275 for (UINT i = 0; i < _card_ids.size(); i++) { 00276 LPDIRECTDRAW7 pDD; 00277 BYTE ddd_space[sizeof(DDDEVICEIDENTIFIER2)+4]; //bug in DX7 requires 4 extra bytes for GetDeviceID 00278 DDDEVICEIDENTIFIER2 *pDX7DeviceID = (DDDEVICEIDENTIFIER2 *)&ddd_space[0]; 00279 GUID *pGUID = &(_card_ids[i].DX7_DeviceGUID); 00280 00281 if (IsEqualGUID(*pGUID, ZeroGUID)) { 00282 pGUID = NULL; 00283 } 00284 00285 // Create the Direct Draw Object 00286 hr = (*_DirectDrawCreateEx)(pGUID, (void **)&pDD, IID_IDirectDraw7, NULL); 00287 if (FAILED(hr)) { 00288 wdxdisplay9_cat.error() 00289 << "DirectDrawCreateEx failed for device (" << i 00290 << ")" << D3DERRORSTRING(hr); 00291 continue; 00292 } 00293 00294 ZeroMemory(ddd_space, sizeof(DDDEVICEIDENTIFIER2)); 00295 00296 hr = pDD->GetDeviceIdentifier(pDX7DeviceID, 0x0); 00297 if (FAILED(hr)) { 00298 wdxdisplay9_cat.error() 00299 << "GetDeviceID failed for device (" << i << ")" << D3DERRORSTRING(hr); 00300 continue; 00301 } 00302 00303 _card_ids[i].DeviceID = pDX7DeviceID->dwDeviceId; 00304 _card_ids[i].VendorID = pDX7DeviceID->dwVendorId; 00305 00306 // Get Current VidMem avail. Note this is only an estimate, when 00307 // we switch to fullscreen mode from desktop, more vidmem will be 00308 // available (typically 1.2 meg). I don't want to switch to 00309 // fullscreen more than once due to the annoying monitor flicker, 00310 // so try to figure out optimal mode using this estimate 00311 DDSCAPS2 ddsGAVMCaps; 00312 DWORD dwVidMemTotal, dwVidMemFree; 00313 dwVidMemTotal = dwVidMemFree = 0; 00314 { 00315 // print out total INCLUDING AGP just for information purposes 00316 // and future use. The real value I'm interested in for 00317 // purposes of measuring possible valid screen sizes shouldnt 00318 // include AGP. 00319 ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2)); 00320 ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY; 00321 00322 hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree); 00323 if (FAILED(hr)) { 00324 wdxdisplay9_cat.error() 00325 << "GetAvailableVidMem failed for device #" << i 00326 << D3DERRORSTRING(hr); 00327 //goto skip_device; 00328 //exit(1); // probably want to exit, since it may be my fault 00329 } 00330 } 00331 00332 wdxdisplay9_cat.info() 00333 << "DX 9.0c GetAvailableVidMem (including AGP) returns Total: " 00334 << dwVidMemTotal <<", Free: " << dwVidMemFree 00335 << " for device #" << i << endl; 00336 00337 ZeroMemory(&ddsGAVMCaps, sizeof(DDSCAPS2)); 00338 00339 // just want to measure localvidmem, not AGP texmem 00340 ddsGAVMCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM; 00341 00342 hr = pDD->GetAvailableVidMem(&ddsGAVMCaps, &dwVidMemTotal, &dwVidMemFree); 00343 if (FAILED(hr)) { 00344 wdxdisplay9_cat.error() << "GetAvailableVidMem failed for device #" << i<< D3DERRORSTRING(hr); 00345 // sometimes GetAvailableVidMem fails with hr = DDERR_NODIRECTDRAWHW for some unknown reason (bad drivers?) 00346 // see bugs: 15327, 18122, others. is it because D3D9 object has already been created? 00347 if (hr == DDERR_NODIRECTDRAWHW) 00348 continue; 00349 exit(1); // probably want to exit, since it may be my fault 00350 } 00351 00352 wdxdisplay9_cat.info() 00353 << "GetAvailableVidMem (no AGP) returns Total: " << dwVidMemTotal 00354 << ", Free: " << dwVidMemFree << " for device #" << i<< endl; 00355 00356 pDD->Release(); // release DD obj, since this is all we needed it for 00357 00358 if (!dx_do_vidmemsize_check) { 00359 // still calling the DD stuff to get deviceID, etc. is this necessary? 00360 _card_ids[i]._max_available_video_memory = UNKNOWN_VIDMEM_SIZE; 00361 _card_ids[i]._is_low_memory_card = false; 00362 continue; 00363 } 00364 00365 if (dwVidMemTotal == 0) { // unreliable driver 00366 dwVidMemTotal = UNKNOWN_VIDMEM_SIZE; 00367 } else { 00368 if (!ISPOW2(dwVidMemTotal)) { 00369 // assume they wont return a proper max value, so 00370 // round up to next pow of 2 00371 UINT count = 0; 00372 while ((dwVidMemTotal >> count) != 0x0) { 00373 count++; 00374 } 00375 dwVidMemTotal = (1 << count); 00376 } 00377 } 00378 00379 // after Set_display_mode, GetAvailVidMem totalmem seems to go down 00380 // by 1.2 meg (contradicting above comment and what I think would 00381 // be correct behavior (shouldnt FS mode release the desktop 00382 // vidmem?), so this is the true value 00383 _card_ids[i]._max_available_video_memory = dwVidMemTotal; 00384 00385 // I can never get this stuff to work reliably, so I'm just 00386 // rounding up to nearest pow2. Could try to get 00387 // HardwareInformation.Memory_size MB number from registry like 00388 // video control panel, but its not clear how to find the proper 00389 // registry location for a given card 00390 00391 // assume buggy drivers (this means you, FireGL2) may return zero 00392 // (or small amts) for dwVidMemTotal, so ignore value if its < CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD 00393 bool bLowVidMemFlag = 00394 ((dwVidMemTotal > CRAPPY_DRIVER_IS_LYING_VIDMEMTHRESHOLD) && 00395 (dwVidMemTotal< LOWVIDMEMTHRESHOLD)); 00396 00397 _card_ids[i]._is_low_memory_card = bLowVidMemFlag; 00398 wdxdisplay9_cat.info() 00399 << "SetLowVidMem flag to " << bLowVidMemFlag 00400 << " based on adjusted VidMemTotal: " << dwVidMemTotal << endl; 00401 } 00402 return true; 00403 } 00404 00405 //////////////////////////////////////////////////////////////////// 00406 // Function: wdxGraphicsPipe9::dx7_driver_enum_callback 00407 // Access: Private, Static 00408 // Description: 00409 //////////////////////////////////////////////////////////////////// 00410 BOOL WINAPI wdxGraphicsPipe9:: 00411 dx7_driver_enum_callback(GUID *pGUID, TCHAR *strDesc, TCHAR *strName, 00412 VOID *argptr, HMONITOR hm) { 00413 wdxGraphicsPipe9 *self = (wdxGraphicsPipe9 *)argptr; 00414 00415 CardID card_id; 00416 ZeroMemory(&card_id, sizeof(CardID)); 00417 00418 if (hm == NULL) { 00419 card_id._monitor = MonitorFromWindow(GetDesktopWindow(), 00420 MONITOR_DEFAULTTOPRIMARY); 00421 } else { 00422 card_id._monitor = hm; 00423 } 00424 00425 if (pGUID != NULL) { 00426 memcpy(&card_id.DX7_DeviceGUID, pGUID, sizeof(GUID)); 00427 } 00428 00429 card_id._max_available_video_memory = UNKNOWN_VIDMEM_SIZE; 00430 00431 self->_card_ids.push_back(card_id); 00432 00433 return DDENUMRET_OK; 00434 } 00435 00436 ////////////////////////////////////////////////////////////////// 00437 // Function: wdxGraphicsWindow9::find_best_depth_format 00438 // Access: Private 00439 // Description: 00440 //////////////////////////////////////////////////////////////////// 00441 bool wdxGraphicsPipe9:: 00442 find_best_depth_format(DXScreenData &Display, D3DDISPLAYMODE &Test_display_mode, 00443 D3DFORMAT *pBestFmt, bool bWantStencil, 00444 bool bForce16bpp, bool bVerboseMode) const { 00445 if (dxgsg9_cat.is_debug()) { 00446 bVerboseMode = true; 00447 } 00448 00449 // list formats to try in order of preference. 00450 00451 #define NUM_TEST_ZFMTS 6 00452 #define FIRST_NON_STENCIL_ZFMT 3 00453 static D3DFORMAT FormatPrefList[NUM_TEST_ZFMTS] = { 00454 D3DFMT_D24S8, D3DFMT_D24X4S4, D3DFMT_D15S1, // with stencil 00455 D3DFMT_D32, D3DFMT_D24X8, D3DFMT_D16 // without stencil 00456 }; 00457 00458 // do not use Display._display_mode since that is probably not set yet, use Test_display_mode instead 00459 00460 *pBestFmt = D3DFMT_UNKNOWN; 00461 HRESULT hr; 00462 00463 // nvidia likes zbuf depth to match rendertarget depth 00464 bool bOnlySelect16bpp = (bForce16bpp || 00465 (IS_NVIDIA(Display._dx_device_id) && IS_16BPP_DISPLAY_FORMAT(Test_display_mode.Format))); 00466 00467 if (bVerboseMode) { 00468 wdxdisplay9_cat.info() 00469 << "FindBestDepthFmt: bSelectOnly16bpp: " << bOnlySelect16bpp << endl; 00470 } 00471 00472 int first_format = (bWantStencil ? 0 : FIRST_NON_STENCIL_ZFMT); 00473 for (int i = first_format; i < NUM_TEST_ZFMTS; i++) { 00474 D3DFORMAT TestDepthFmt = FormatPrefList[i]; 00475 00476 if (bOnlySelect16bpp && !IS_16BPP_ZBUFFER(TestDepthFmt)) { 00477 continue; 00478 } 00479 00480 hr = Display._d3d9->CheckDeviceFormat(Display._card_id, 00481 D3DDEVTYPE_HAL, 00482 Test_display_mode.Format, 00483 D3DUSAGE_DEPTHSTENCIL, 00484 D3DRTYPE_SURFACE, TestDepthFmt); 00485 00486 if (FAILED(hr)) { 00487 if (hr == D3DERR_NOTAVAILABLE) { 00488 if (bVerboseMode) 00489 wdxdisplay9_cat.info() 00490 << "FindBestDepthFmt: ChkDevFmt returns NotAvail for " 00491 << D3DFormatStr(TestDepthFmt) << endl; 00492 continue; 00493 } 00494 00495 wdxdisplay9_cat.error() 00496 << "unexpected CheckDeviceFormat failure" << D3DERRORSTRING(hr) 00497 << endl; 00498 exit(1); 00499 } 00500 00501 hr = Display._d3d9->CheckDepthStencilMatch(Display._card_id, 00502 D3DDEVTYPE_HAL, 00503 Test_display_mode.Format, // adapter format 00504 Test_display_mode.Format, // backbuffer fmt (should be the same in my apps) 00505 TestDepthFmt); 00506 if (SUCCEEDED(hr)) { 00507 *pBestFmt = TestDepthFmt; 00508 break; 00509 } else { 00510 if (hr == D3DERR_NOTAVAILABLE) { 00511 if (bVerboseMode) { 00512 wdxdisplay9_cat.info() 00513 << "FindBestDepthFmt: ChkDepMatch returns NotAvail for " 00514 << D3DFormatStr(Test_display_mode.Format) << ", " 00515 << D3DFormatStr(TestDepthFmt) << endl; 00516 } 00517 } else { 00518 wdxdisplay9_cat.error() 00519 << "unexpected CheckDepthStencilMatch failure for " 00520 << D3DFormatStr(Test_display_mode.Format) << ", " 00521 << D3DFormatStr(TestDepthFmt) << endl; 00522 exit(1); 00523 } 00524 } 00525 } 00526 00527 if (bVerboseMode) { 00528 wdxdisplay9_cat.info() 00529 << "FindBestDepthFmt returns fmt " << D3DFormatStr(*pBestFmt) << endl; 00530 } 00531 00532 return (*pBestFmt != D3DFMT_UNKNOWN); 00533 } 00534 00535 00536 //////////////////////////////////////////////////////////////////// 00537 // Function: wdxGraphicsWindow9::special_check_fullscreen_resolution 00538 // Access: Private 00539 // Description: overrides of the general estimator for known working 00540 // cases 00541 //////////////////////////////////////////////////////////////////// 00542 bool wdxGraphicsPipe9:: 00543 special_check_fullscreen_resolution(DXScreenData &scrn, UINT x_size, UINT y_size) { 00544 DWORD VendorId = scrn._dx_device_id.VendorId; 00545 DWORD DeviceId = scrn._dx_device_id.DeviceId; 00546 00547 switch (VendorId) { 00548 case 0x8086: // Intel 00549 if ((x_size == 640) && (y_size == 480)) { 00550 return true; 00551 } 00552 if ((x_size == 800) && (y_size == 600)) { 00553 return true; 00554 } 00555 if ((x_size == 1024) && (y_size == 768)) { 00556 return true; 00557 } 00558 break; 00559 } 00560 00561 return false; 00562 } 00563 00564 //////////////////////////////////////////////////////////////////// 00565 // Function: wdxGraphicsWindow9::search_for_valid_displaymode 00566 // Access: Private 00567 // Description: All ptr args are output parameters. If no valid mode 00568 // found, returns *pSuggestedPixFmt = D3DFMT_UNKNOWN; 00569 //////////////////////////////////////////////////////////////////// 00570 void wdxGraphicsPipe9:: 00571 search_for_valid_displaymode(DXScreenData &scrn, 00572 UINT RequestedX_Size, UINT RequestedY_Size, 00573 bool bWantZBuffer, bool bWantStencil, 00574 UINT *p_supported_screen_depths_mask, 00575 bool *pCouldntFindAnyValidZBuf, 00576 D3DFORMAT *pSuggestedPixFmt, 00577 bool bForce16bppZBuffer, 00578 bool bVerboseMode) { 00579 if (dxgsg9_cat.is_debug()) { 00580 bVerboseMode = true; 00581 } 00582 00583 assert(IS_VALID_PTR(scrn._d3d9)); 00584 00585 HRESULT hr; 00586 00587 *pSuggestedPixFmt = D3DFMT_UNKNOWN; 00588 *p_supported_screen_depths_mask = 0x0; 00589 *pCouldntFindAnyValidZBuf = false; 00590 00591 #define TOTAL_D3D_FORMATS 5 00592 static D3DFORMAT d3d_format_array [TOTAL_D3D_FORMATS] = 00593 { 00594 D3DFMT_X8R8G8B8, 00595 D3DFMT_A8R8G8B8, 00596 D3DFMT_R5G6B5, 00597 D3DFMT_X1R5G5B5, 00598 D3DFMT_A2R10G10B10, // we may want this first in the list for XBOX 360 or HDR 00599 }; 00600 00601 // search for an adapter with a valid D3DFORMAT 00602 int format_index; 00603 for (format_index = 0; format_index < TOTAL_D3D_FORMATS; format_index++) { 00604 D3DFORMAT d3d_format; 00605 00606 d3d_format = d3d_format_array [format_index]; 00607 00608 int cNumModes = scrn._d3d9->GetAdapterModeCount(scrn._card_id, d3d_format); 00609 00610 D3DDISPLAYMODE BestDispMode; 00611 ZeroMemory(&BestDispMode, sizeof(BestDispMode)); 00612 00613 if (bVerboseMode) { 00614 wdxdisplay9_cat.info() 00615 << "searching for valid display modes at res: (" 00616 << RequestedX_Size << ", " << RequestedY_Size 00617 << "), TotalModes: " << cNumModes << endl; 00618 } 00619 00620 // ignore memory based checks for min res 640x480. some cards just 00621 // don't give accurate memavails. (should I do the check anyway for 00622 // 640x480 32bpp?) 00623 bool bDoMemBasedChecks = 00624 ((!((RequestedX_Size == 640)&&(RequestedY_Size == 480))) && 00625 (scrn._max_available_video_memory != UNKNOWN_VIDMEM_SIZE) && 00626 (!special_check_fullscreen_resolution(scrn, RequestedX_Size, RequestedY_Size))); 00627 00628 if (bVerboseMode) { 00629 wdxdisplay9_cat.info() 00630 << "DoMemBasedChecks = " << bDoMemBasedChecks << endl; 00631 } 00632 00633 for (int i = 0; i < cNumModes; i++) { 00634 D3DDISPLAYMODE dispmode; 00635 hr = scrn._d3d9->EnumAdapterModes(scrn._card_id, d3d_format, i, &dispmode); 00636 if (FAILED(hr)) { 00637 wdxdisplay9_cat.error() 00638 << "EnumAdapter_display_mode failed for device #" 00639 << scrn._card_id << D3DERRORSTRING(hr); 00640 continue; 00641 } 00642 00643 if ((dispmode.Width != RequestedX_Size) || 00644 (dispmode.Height != RequestedY_Size)) { 00645 if (bVerboseMode) { 00646 wdxdisplay9_cat.info() 00647 << "Mode dimension " << dispmode.Width << "x" << dispmode.Height 00648 << "; format " << D3DFormatStr(dispmode.Format) 00649 << ": onto next mode\n"; 00650 } 00651 continue; 00652 } 00653 00654 // disable refresh rate checking since SLI video cards may use 00655 // refresh rates less than 60 00656 if (0) { 00657 if ((dispmode.RefreshRate<60) && (dispmode.RefreshRate>1)) { 00658 // don't want refresh rates under 60Hz, but 0 or 1 might indicate 00659 // a default refresh rate, which is usually > = 60 00660 if (bVerboseMode) { 00661 wdxdisplay9_cat.info() 00662 << "skipping mode[" << i << "], bad refresh rate: " 00663 << dispmode.RefreshRate << endl; 00664 } 00665 continue; 00666 } 00667 } 00668 00669 // Note no attempt is made to verify if format will work at 00670 // requested size, so even if this call succeeds, could still get 00671 // an out-of-video-mem error 00672 00673 hr = scrn._d3d9->CheckDeviceFormat(scrn._card_id, D3DDEVTYPE_HAL, dispmode.Format, 00674 D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, 00675 dispmode.Format); 00676 if (FAILED(hr)) { 00677 if (hr == D3DERR_NOTAVAILABLE) { 00678 if (bVerboseMode) { 00679 wdxdisplay9_cat.info() 00680 << "skipping mode[" << i 00681 << "], CheckDevFmt returns NotAvail for fmt: " 00682 << D3DFormatStr(dispmode.Format) << endl; 00683 } 00684 continue; 00685 } else { 00686 wdxdisplay9_cat.error() 00687 << "CheckDeviceFormat failed for device #" 00688 << scrn._card_id << D3DERRORSTRING(hr); 00689 continue; 00690 } 00691 } 00692 00693 bool bIs16bppRenderTgt = IS_16BPP_DISPLAY_FORMAT(dispmode.Format); 00694 PN_stdfloat RendTgtMinMemReqmt = 0.0f; 00695 00696 // if we have a valid memavail value, try to determine if we have 00697 // enough space 00698 if (bDoMemBasedChecks) { 00699 // assume user is testing fullscreen, not windowed, so use the 00700 // dwTotal value see if 3 scrnbufs (front/back/z)at 16bpp at 00701 // x_size*y_size will fit with a few extra megs for texmem 00702 00703 // 8MB Rage Pro says it has 6.8 megs Total free and will run at 00704 // 1024x768, so formula makes it so that is OK 00705 00706 #define REQD_TEXMEM 1800000 00707 00708 PN_stdfloat bytes_per_pixel = (bIs16bppRenderTgt ? 2 : 4); 00709 00710 // *2 for double buffer 00711 00712 RendTgtMinMemReqmt = 00713 ((PN_stdfloat)RequestedX_Size) * ((PN_stdfloat)RequestedY_Size) * 00714 bytes_per_pixel * 2 + REQD_TEXMEM; 00715 00716 if (bVerboseMode) 00717 wdxdisplay9_cat.info() 00718 << "Testing Mode (" <<RequestedX_Size<<"x" << RequestedY_Size 00719 << ", " << D3DFormatStr(dispmode.Format) << ")\nReqdVidMem: " 00720 << (int)RendTgtMinMemReqmt << " AvailVidMem: " 00721 << scrn._max_available_video_memory << endl; 00722 00723 if (RendTgtMinMemReqmt > scrn._max_available_video_memory) { 00724 if (bVerboseMode) 00725 wdxdisplay9_cat.info() 00726 << "not enough VidMem for render tgt, skipping display fmt " 00727 << D3DFormatStr(dispmode.Format) << " (" 00728 << (int)RendTgtMinMemReqmt << " > " 00729 << scrn._max_available_video_memory << ")\n"; 00730 continue; 00731 } 00732 } 00733 00734 if (bWantZBuffer) { 00735 D3DFORMAT zformat; 00736 if (!find_best_depth_format(scrn, dispmode, &zformat, 00737 bWantStencil, bForce16bppZBuffer)) { 00738 *pCouldntFindAnyValidZBuf = true; 00739 continue; 00740 } 00741 00742 PN_stdfloat MinMemReqmt = 0.0f; 00743 00744 if (bDoMemBasedChecks) { 00745 // test memory again, this time including zbuf size 00746 PN_stdfloat zbytes_per_pixel = (IS_16BPP_ZBUFFER(zformat) ? 2 : 4); 00747 PN_stdfloat MinMemReqmt = RendTgtMinMemReqmt + ((PN_stdfloat)RequestedX_Size)*((PN_stdfloat)RequestedY_Size)*zbytes_per_pixel; 00748 00749 if (bVerboseMode) 00750 wdxdisplay9_cat.info() 00751 << "Testing Mode w/Z (" << RequestedX_Size << "x" 00752 << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format) 00753 << ")\nReqdVidMem: " << (int)MinMemReqmt << " AvailVidMem: " 00754 << scrn._max_available_video_memory << endl; 00755 00756 if (MinMemReqmt > scrn._max_available_video_memory) { 00757 if (bVerboseMode) 00758 wdxdisplay9_cat.info() 00759 << "not enough VidMem for RendTgt+zbuf, skipping display fmt " 00760 << D3DFormatStr(dispmode.Format) << " (" << (int)MinMemReqmt 00761 << " > " << scrn._max_available_video_memory << ")\n"; 00762 continue; 00763 } 00764 } 00765 00766 // Optimizing for 16-bit depth does not work in all cases so turn it off. 00767 if (false) { 00768 if ((!bDoMemBasedChecks) || (MinMemReqmt<scrn._max_available_video_memory)) { 00769 if (!IS_16BPP_ZBUFFER(zformat)) { 00770 // see if things fit with a 16bpp zbuffer 00771 00772 if (!find_best_depth_format(scrn, dispmode, &zformat, 00773 bWantStencil, true, bVerboseMode)) { 00774 if (bVerboseMode) 00775 wdxdisplay9_cat.info() 00776 << "FindBestDepthFmt rejected Mode[" << i << "] (" 00777 << RequestedX_Size << "x" << RequestedY_Size 00778 << ", " << D3DFormatStr(dispmode.Format) << endl; 00779 *pCouldntFindAnyValidZBuf = true; 00780 continue; 00781 } 00782 00783 // right now I'm not going to use these flags, just let the 00784 // create fail out-of-mem and retry at 16bpp 00785 *p_supported_screen_depths_mask |= 00786 (IS_16BPP_DISPLAY_FORMAT(dispmode.Format) ? DISPLAY_16BPP_REQUIRES_16BPP_ZBUFFER_FLAG : DISPLAY_32BPP_REQUIRES_16BPP_ZBUFFER_FLAG); 00787 } 00788 } 00789 } 00790 } 00791 00792 if (bVerboseMode) 00793 wdxdisplay9_cat.info() 00794 << "Validated Mode (" << RequestedX_Size << "x" 00795 << RequestedY_Size << ", " << D3DFormatStr(dispmode.Format) << endl; 00796 00797 /* 00798 // dx9 valid display modes for render targets. 00799 D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_A2R10G10B10 00800 */ 00801 00802 switch (dispmode.Format) { 00803 case D3DFMT_X1R5G5B5: 00804 *p_supported_screen_depths_mask |= X1R5G5B5_FLAG; 00805 break; 00806 case D3DFMT_X8R8G8B8: 00807 *p_supported_screen_depths_mask |= X8R8G8B8_FLAG; 00808 break; 00809 case D3DFMT_A8R8G8B8: 00810 *p_supported_screen_depths_mask |= A8R8G8B8_FLAG; 00811 break; 00812 case D3DFMT_R5G6B5: 00813 *p_supported_screen_depths_mask |= R5G6B5_FLAG; 00814 break; 00815 case D3DFMT_A2R10G10B10: 00816 *p_supported_screen_depths_mask |= A2B10G10R10_FLAG; 00817 break; 00818 default: 00819 wdxdisplay9_cat.error() 00820 << "unrecognized supported fmt " << D3DFormatStr(dispmode.Format) 00821 << " returned by EnumAdapter_display_modes!\n"; 00822 } 00823 } 00824 00825 // note: this chooses 32bpp, which may not be preferred over 16 for 00826 // memory & speed reasons on some older cards in particular 00827 if (*p_supported_screen_depths_mask & X8R8G8B8_FLAG) { 00828 *pSuggestedPixFmt = D3DFMT_X8R8G8B8; 00829 } else if (*p_supported_screen_depths_mask & A8R8G8B8_FLAG) { 00830 *pSuggestedPixFmt = D3DFMT_A8R8G8B8; 00831 } else if (*p_supported_screen_depths_mask & R5G6B5_FLAG) { 00832 *pSuggestedPixFmt = D3DFMT_R5G6B5; 00833 } else if (*p_supported_screen_depths_mask & X1R5G5B5_FLAG) { 00834 *pSuggestedPixFmt = D3DFMT_X1R5G5B5; 00835 } else if (*p_supported_screen_depths_mask & A2B10G10R10_FLAG) { 00836 *pSuggestedPixFmt = D3DFMT_A2R10G10B10; 00837 } 00838 00839 if (bVerboseMode) { 00840 wdxdisplay9_cat.info() 00841 << "search_for_valid_device returns fmt: " 00842 << D3DFormatStr(*pSuggestedPixFmt) << endl; 00843 } 00844 00845 if (*pSuggestedPixFmt != D3DFMT_UNKNOWN) { 00846 break; 00847 } 00848 } 00849 } 00850 00851 //////////////////////////////////////////////////////////////////// 00852 // Function: wdxGraphicsPipew9::make_device 00853 // Access: Public, Virtual 00854 // Description: Creates a new reference to a particular hardware 00855 // device and associates it with the pipe. 00856 //////////////////////////////////////////////////////////////////// 00857 PT(GraphicsDevice) wdxGraphicsPipe9:: 00858 make_device(void *scrn) { 00859 PT(DXGraphicsDevice9) device = new DXGraphicsDevice9(this); 00860 memcpy(&device->_Scrn, scrn, sizeof(device->_Scrn)); 00861 device->_d3d_device = device->_Scrn._d3d_device; 00862 00863 _device = device; 00864 wdxdisplay9_cat.info() << "walla: device" << device << "\n"; 00865 00866 return device.p(); 00867 } 00868 00869 pmap<D3DFORMAT_FLAG, D3DFORMAT> g_D3DFORMATmap; 00870 00871 void Init_D3DFORMAT_map() { 00872 if (g_D3DFORMATmap.size() != 0) 00873 return; 00874 00875 #define INSERT_ELEM(XX) g_D3DFORMATmap[XX##_FLAG] = D3DFMT_##XX; 00876 00877 INSERT_ELEM(R8G8B8); 00878 INSERT_ELEM(A8R8G8B8); 00879 INSERT_ELEM(X8R8G8B8); 00880 INSERT_ELEM(R5G6B5); 00881 INSERT_ELEM(X1R5G5B5); 00882 INSERT_ELEM(A1R5G5B5); 00883 INSERT_ELEM(A4R4G4B4); 00884 INSERT_ELEM(R3G3B2); 00885 INSERT_ELEM(A8); 00886 INSERT_ELEM(A8R3G3B2); 00887 INSERT_ELEM(X4R4G4B4); 00888 INSERT_ELEM(A2B10G10R10); 00889 INSERT_ELEM(G16R16); 00890 INSERT_ELEM(A8P8); 00891 INSERT_ELEM(P8); 00892 INSERT_ELEM(L8); 00893 INSERT_ELEM(A8L8); 00894 INSERT_ELEM(A4L4); 00895 INSERT_ELEM(V8U8); 00896 INSERT_ELEM(L6V5U5); 00897 INSERT_ELEM(X8L8V8U8); 00898 INSERT_ELEM(Q8W8V8U8); 00899 INSERT_ELEM(V16U16); 00900 // NOT IN DX9 00901 // INSERT_ELEM(W11V11U10); 00902 INSERT_ELEM(A2W10V10U10); 00903 INSERT_ELEM(UYVY); 00904 INSERT_ELEM(YUY2); 00905 INSERT_ELEM(DXT1); 00906 INSERT_ELEM(DXT2); 00907 INSERT_ELEM(DXT3); 00908 INSERT_ELEM(DXT4); 00909 INSERT_ELEM(DXT5); 00910 } 00911 00912 00913 00914 const char *D3DFormatStr(D3DFORMAT fmt) { 00915 00916 #define CASESTR(XX) case XX: return #XX; 00917 switch(fmt) { 00918 CASESTR(D3DFMT_UNKNOWN); 00919 CASESTR(D3DFMT_R8G8B8); 00920 CASESTR(D3DFMT_A8R8G8B8); 00921 CASESTR(D3DFMT_X8R8G8B8); 00922 CASESTR(D3DFMT_R5G6B5); 00923 CASESTR(D3DFMT_X1R5G5B5); 00924 CASESTR(D3DFMT_A1R5G5B5); 00925 CASESTR(D3DFMT_A4R4G4B4); 00926 CASESTR(D3DFMT_R3G3B2); 00927 CASESTR(D3DFMT_A8); 00928 CASESTR(D3DFMT_A8R3G3B2); 00929 CASESTR(D3DFMT_X4R4G4B4); 00930 CASESTR(D3DFMT_A2B10G10R10); 00931 CASESTR(D3DFMT_G16R16); 00932 CASESTR(D3DFMT_A8P8); 00933 CASESTR(D3DFMT_P8); 00934 CASESTR(D3DFMT_L8); 00935 CASESTR(D3DFMT_A8L8); 00936 CASESTR(D3DFMT_A4L4); 00937 CASESTR(D3DFMT_V8U8); 00938 CASESTR(D3DFMT_L6V5U5); 00939 CASESTR(D3DFMT_X8L8V8U8); 00940 CASESTR(D3DFMT_Q8W8V8U8); 00941 CASESTR(D3DFMT_V16U16); 00942 // NOT IN DX9 00943 // CASESTR(D3DFMT_W11V11U10); 00944 CASESTR(D3DFMT_A2W10V10U10); 00945 CASESTR(D3DFMT_UYVY); 00946 CASESTR(D3DFMT_YUY2); 00947 CASESTR(D3DFMT_DXT1); 00948 CASESTR(D3DFMT_DXT2); 00949 CASESTR(D3DFMT_DXT3); 00950 CASESTR(D3DFMT_DXT4); 00951 CASESTR(D3DFMT_DXT5); 00952 CASESTR(D3DFMT_D16_LOCKABLE); 00953 CASESTR(D3DFMT_D32); 00954 CASESTR(D3DFMT_D15S1); 00955 CASESTR(D3DFMT_D24S8); 00956 CASESTR(D3DFMT_D16); 00957 CASESTR(D3DFMT_D24X8); 00958 CASESTR(D3DFMT_D24X4S4); 00959 CASESTR(D3DFMT_VERTEXDATA); 00960 CASESTR(D3DFMT_INDEX16); 00961 CASESTR(D3DFMT_INDEX32); 00962 CASESTR(D3DFMT_A16B16G16R16F); 00963 CASESTR(D3DFMT_A32B32G32R32F); 00964 } 00965 00966 return "Invalid D3DFORMAT"; 00967 }