Panda3D
 All Classes Functions Variables Enumerations
wdxGraphicsPipe8.cxx
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 
 All Classes Functions Variables Enumerations