Panda3D

wdxGraphicsPipe9.cxx

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 }
 All Classes Functions Variables Enumerations