Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/dxgsg8/wdxGraphicsPipe8.cxx

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

Generated on Fri May 2 00:37:19 2003 for Panda by doxygen1.3