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