home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Riza / source / direct3d.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-24  |  40.7 KB  |  1,577 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    A/V interface library
  3. //    Copyright (C) 1998-2005 Avery Lee
  4. //
  5. //    This program is free software; you can redistribute it and/or modify
  6. //    it under the terms of the GNU General Public License as published by
  7. //    the Free Software Foundation; either version 2 of the License, or
  8. //    (at your option) any later version.
  9. //
  10. //    This program is distributed in the hope that it will be useful,
  11. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //    GNU General Public License for more details.
  14. //
  15. //    You should have received a copy of the GNU General Public License
  16. //    along with this program; if not, write to the Free Software
  17. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. //
  19. //
  20. //    This file is the DirectX 9 driver for the video display subsystem.
  21. //    It does traditional point sampled and bilinearly filtered upsampling
  22. //    as well as a special multipass algorithm for emulated bicubic
  23. //    filtering.
  24. //
  25.  
  26. #include <vd2/system/vdtypes.h>
  27.  
  28. #define DIRECTDRAW_VERSION 0x0900
  29. #define INITGUID
  30. #include <d3d9.h>
  31. #include <vd2/system/vdtypes.h>
  32. #include <vd2/system/vdalloc.h>
  33. #include <vd2/system/refcount.h>
  34. #include <vd2/system/math.h>
  35. #include <vd2/system/time.h>
  36. #include <vd2/system/vdstl.h>
  37. #include <vd2/system/w32assist.h>
  38. #include <vd2/Riza/direct3d.h>
  39.  
  40. ///////////////////////////////////////////////////////////////////////////
  41.  
  42. #define VDDEBUG_D3D VDDEBUG
  43.  
  44. using namespace nsVDD3D9;
  45.  
  46. ///////////////////////////////////////////////////////////////////////////
  47.  
  48. class VDD3D9Texture : public IVDD3D9Texture, public vdlist_node {
  49. public:
  50.     VDD3D9Texture();
  51.     ~VDD3D9Texture();
  52.  
  53.     int AddRef();
  54.     int Release();
  55.  
  56.     bool Init(VDD3D9Manager *pManager, IVDD3D9TextureGenerator *pGenerator);
  57.     void Shutdown();
  58.  
  59.     bool InitVRAMResources();
  60.     void ShutdownVRAMResources();
  61.  
  62.     const char *GetName() const { return mName.data(); }
  63.     void SetName(const char *name) { mName.assign(name, name+strlen(name)+1); }
  64.  
  65.     int GetWidth();
  66.     int GetHeight();
  67.  
  68.     void SetD3DTexture(IDirect3DTexture9 *pTexture);
  69.     IDirect3DTexture9 *GetD3DTexture();
  70.  
  71. protected:
  72.     vdfastvector<char> mName;
  73.     IDirect3DTexture9 *mpD3DTexture;
  74.     IVDD3D9TextureGenerator *mpGenerator;
  75.     VDD3D9Manager *mpManager;
  76.     int mWidth;
  77.     int mHeight;
  78.     int mRefCount;
  79.     bool mbVRAMTexture;
  80. };
  81.  
  82. VDD3D9Texture::VDD3D9Texture()
  83.     : mpD3DTexture(NULL)
  84.     , mpGenerator(NULL)
  85.     , mpManager(NULL)
  86.     , mWidth(0)
  87.     , mHeight(0)
  88.     , mRefCount(0)
  89.     , mbVRAMTexture(false)
  90. {
  91.     mListNodeNext = mListNodePrev = this;
  92. }
  93.  
  94. VDD3D9Texture::~VDD3D9Texture() {
  95. }
  96.  
  97. int VDD3D9Texture::AddRef() {
  98.     return ++mRefCount;
  99. }
  100.  
  101. int VDD3D9Texture::Release() {
  102.     int rc = --mRefCount;
  103.  
  104.     if (!rc) {
  105.         vdlist_base::unlink(*this);
  106.         Shutdown();
  107.         delete this;
  108.     }
  109.  
  110.     return rc;
  111. }
  112.  
  113. bool VDD3D9Texture::Init(VDD3D9Manager *pManager, IVDD3D9TextureGenerator *pGenerator) {
  114.     if (mpGenerator)
  115.         mpGenerator->Release();
  116.     if (pGenerator)
  117.         pGenerator->AddRef();
  118.     mpGenerator = pGenerator;
  119.     mpManager = pManager;
  120.  
  121.     if (mpGenerator) {
  122.         if (!mpGenerator->GenerateTexture(pManager, this))
  123.             return false;
  124.     }
  125.  
  126.     return true;
  127. }
  128.  
  129. void VDD3D9Texture::Shutdown() {
  130.     mpManager = NULL;
  131.  
  132.     if (mpGenerator) {
  133.         mpGenerator->Release();
  134.         mpGenerator = NULL;
  135.     }
  136.  
  137.     if (mpD3DTexture) {
  138.         mpD3DTexture->Release();
  139.         mpD3DTexture = NULL;
  140.     }
  141. }
  142.  
  143. bool VDD3D9Texture::InitVRAMResources() {
  144.     if (mbVRAMTexture && !mpD3DTexture && mpGenerator)
  145.         return mpGenerator->GenerateTexture(mpManager, this);
  146.  
  147.     return true;
  148. }
  149.  
  150. void VDD3D9Texture::ShutdownVRAMResources() {
  151.     if (mbVRAMTexture) {
  152.         if (mpD3DTexture) {
  153.             mpD3DTexture->Release();
  154.             mpD3DTexture = NULL;
  155.         }
  156.     }
  157. }
  158.  
  159. int VDD3D9Texture::GetWidth() {
  160.     return mWidth;
  161. }
  162.  
  163. int VDD3D9Texture::GetHeight() {
  164.     return mHeight;
  165. }
  166.  
  167. void VDD3D9Texture::SetD3DTexture(IDirect3DTexture9 *pTexture) {
  168.     if (mpD3DTexture)
  169.         mpD3DTexture->Release();
  170.     if (pTexture) {
  171.         pTexture->AddRef();
  172.  
  173.         D3DSURFACE_DESC desc;
  174.         HRESULT hr = pTexture->GetLevelDesc(0, &desc);
  175.  
  176.         if (SUCCEEDED(hr)) {
  177.             mWidth = desc.Width;
  178.             mHeight = desc.Height;
  179.             mbVRAMTexture = (desc.Pool == D3DPOOL_DEFAULT);
  180.         } else {
  181.             mWidth = 1;
  182.             mHeight = 1;
  183.             mbVRAMTexture = true;
  184.         }
  185.  
  186.     }
  187.     mpD3DTexture = pTexture;
  188. }
  189.  
  190. IDirect3DTexture9 *VDD3D9Texture::GetD3DTexture() {
  191.     return mpD3DTexture;
  192. }
  193.  
  194. ///////////////////////////////////////////////////////////////////////////
  195.  
  196. class VDD3D9SwapChain : public vdrefcounted<IVDD3D9SwapChain> {
  197. public:
  198.     VDD3D9SwapChain(IDirect3DSwapChain9 *pD3DSwapChain);
  199.     ~VDD3D9SwapChain();
  200.  
  201.     IDirect3DSwapChain9 *GetD3DSwapChain() const { return mpD3DSwapChain; }
  202. protected:
  203.     vdrefptr<IDirect3DSwapChain9> mpD3DSwapChain;
  204. };
  205.  
  206. VDD3D9SwapChain::VDD3D9SwapChain(IDirect3DSwapChain9 *pD3DSwapChain)
  207.     : mpD3DSwapChain(pD3DSwapChain)
  208. {
  209. }
  210.  
  211. VDD3D9SwapChain::~VDD3D9SwapChain() {
  212. }
  213.  
  214. ///////////////////////////////////////////////////////////////////////////
  215.  
  216. static VDCriticalSection g_csVDDirect3D9Managers;
  217. static vdlist<VDD3D9Manager> g_VDDirect3D9Managers;
  218.  
  219. VDD3D9Manager *VDInitDirect3D9(VDD3D9Client *pClient) {
  220.     VDD3D9Manager *pMgr = NULL;
  221.     bool firstClient = false;
  222.  
  223.     vdsynchronized(g_csVDDirect3D9Managers) {
  224.         vdlist<VDD3D9Manager>::iterator it(g_VDDirect3D9Managers.begin()), itEnd(g_VDDirect3D9Managers.end());
  225.  
  226.         VDThreadID tid = VDGetCurrentThreadID();
  227.  
  228.         for(; it != itEnd; ++it) {
  229.             VDD3D9Manager *mgr = *it;
  230.  
  231.             if (mgr->GetThreadID() == tid) {
  232.                 pMgr = mgr;
  233.                 break;
  234.             }
  235.         }
  236.  
  237.         if (!pMgr) {
  238.             pMgr = new_nothrow VDD3D9Manager;
  239.             if (!pMgr)
  240.                 return NULL;
  241.  
  242.             g_VDDirect3D9Managers.push_back(pMgr);
  243.             firstClient = true;
  244.         }
  245.     }
  246.  
  247.     bool success = pMgr->Attach(pClient);
  248.  
  249.     if (success)
  250.         return pMgr;
  251.  
  252.     if (firstClient) {
  253.         vdsynchronized(g_csVDDirect3D9Managers) {
  254.             g_VDDirect3D9Managers.erase(pMgr);
  255.         }
  256.     }
  257.  
  258.     return NULL;
  259. }
  260.  
  261. void VDDeinitDirect3D9(VDD3D9Manager *p, VDD3D9Client *pClient) {
  262.     if (p->Detach(pClient)) {
  263.         vdsynchronized(g_csVDDirect3D9Managers) {
  264.             g_VDDirect3D9Managers.erase(p);
  265.         }
  266.         delete p;
  267.     }
  268. }
  269.  
  270. VDD3D9Manager::VDD3D9Manager()
  271.     : mhmodDX9(NULL)
  272.     , mpD3D(NULL)
  273.     , mpD3DDevice(NULL)
  274.     , mpD3DRTMain(NULL)
  275.     , mDevWndClass(NULL)
  276.     , mhwndDevice(NULL)
  277.     , mThreadID(0)
  278.     , mbDeviceValid(false)
  279.     , mbInScene(false)
  280.     , mFullScreenCount(0)
  281.     , mpD3DVB(NULL)
  282.     , mpD3DIB(NULL)
  283.     , mpD3DQuery(NULL)
  284.     , mpD3DVD(NULL)
  285.     , mpImplicitSwapChain(NULL)
  286.     , mRefCount(0)
  287.     , mFenceQueueBase(0)
  288.     , mFenceQueueHeadIndex(0)
  289. {
  290. }
  291.  
  292. VDD3D9Manager::~VDD3D9Manager() {
  293.     VDASSERT(!mRefCount);
  294. }
  295.  
  296. bool VDD3D9Manager::Attach(VDD3D9Client *pClient) {
  297.     bool bSuccess = false;
  298.  
  299.     VDASSERT(mClients.find(pClient) == mClients.end());
  300.     mClients.push_back(pClient);
  301.  
  302.     if (++mRefCount == 1)
  303.         bSuccess = Init();
  304.     else {
  305.         VDASSERT(VDGetCurrentThreadID() == mThreadID);
  306.         bSuccess = CheckDevice();
  307.     }
  308.  
  309.     if (!bSuccess)
  310.         Detach(pClient);
  311.  
  312.     return bSuccess;
  313. }
  314.  
  315. bool VDD3D9Manager::Detach(VDD3D9Client *pClient) {
  316.     VDASSERT(mRefCount > 0);
  317.     VDASSERT(VDGetCurrentThreadID() == mThreadID);
  318.  
  319.     VDASSERT(mClients.find(pClient) != mClients.end());
  320.     mClients.erase(mClients.fast_find(pClient));
  321.  
  322.     if (!--mRefCount) {
  323.         Shutdown();
  324.         return true;
  325.     }
  326.  
  327.     return false;
  328. }
  329.  
  330. bool VDD3D9Manager::Init() {
  331.     HINSTANCE hInst = VDGetLocalModuleHandleW32();
  332.  
  333.     if (!mDevWndClass) {
  334.         WNDCLASS wc;
  335.  
  336.         wc.cbClsExtra        = 0;
  337.         wc.cbWndExtra        = 0;
  338.         wc.hbrBackground    = NULL;
  339.         wc.hCursor            = NULL;
  340.         wc.hIcon            = NULL;
  341.         wc.hInstance        = hInst;
  342.         wc.lpfnWndProc        = StaticDeviceWndProc;
  343.  
  344.         char buf[64];
  345.         sprintf(buf, "RizaD3DDeviceWindow_%p", this);
  346.         wc.lpszClassName    = buf;
  347.         wc.lpszMenuName        = NULL;
  348.         wc.style            = 0;
  349.  
  350.         mDevWndClass = RegisterClass(&wc);
  351.         if (!mDevWndClass)
  352.             return false;
  353.     }
  354.  
  355.     mThreadID = VDGetCurrentThreadID();
  356.  
  357.     mhwndDevice = CreateWindow(MAKEINTATOM(mDevWndClass), "", WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInst, NULL);
  358.     if (!mhwndDevice) {
  359.         Shutdown();
  360.         return false;
  361.     }
  362.  
  363.     // attempt to load D3D9.DLL
  364.     mhmodDX9 = LoadLibrary("d3d9.dll");
  365.     if (!mhmodDX9) {
  366.         Shutdown();
  367.         return false;
  368.     }
  369.  
  370.     IDirect3D9 *(APIENTRY *pDirect3DCreate9)(UINT) = (IDirect3D9 *(APIENTRY *)(UINT))GetProcAddress(mhmodDX9, "Direct3DCreate9");
  371.     if (!pDirect3DCreate9) {
  372.         Shutdown();
  373.         return false;
  374.     }
  375.  
  376.     // create Direct3D9 object
  377.     mpD3D = pDirect3DCreate9(D3D_SDK_VERSION);
  378.     if (!mpD3D) {
  379.         Shutdown();
  380.         return false;
  381.     }
  382.  
  383.     // create device
  384.     memset(&mPresentParms, 0, sizeof mPresentParms);
  385.     mPresentParms.Windowed            = TRUE;
  386.     mPresentParms.SwapEffect        = D3DSWAPEFFECT_COPY;
  387.     // BackBufferFormat is set below.
  388.     mPresentParms.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  389.  
  390.     HRESULT hr;
  391.  
  392.     // Look for the NVPerfHUD 2.0 driver
  393.     
  394.     const UINT adapters = mpD3D->GetAdapterCount();
  395.     DWORD dwFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
  396.     UINT adapter = D3DADAPTER_DEFAULT;
  397.     D3DDEVTYPE type = D3DDEVTYPE_HAL;
  398.  
  399.     for(UINT n=0; n<adapters; ++n) {
  400.         D3DADAPTER_IDENTIFIER9 ident;
  401.  
  402.         if (SUCCEEDED(mpD3D->GetAdapterIdentifier(n, 0, &ident))) {
  403.             if (strstr(ident.Description, "PerfHUD")) {
  404.                 adapter = n;
  405.                 type = D3DDEVTYPE_REF;
  406.                 break;
  407.             }
  408.         }
  409.     }
  410.  
  411.     mAdapter = adapter;
  412.     mDevType = type;
  413.  
  414.     D3DDISPLAYMODE mode;
  415.     hr = mpD3D->GetAdapterDisplayMode(adapter, &mode);
  416.     if (FAILED(hr)) {
  417.         VDDEBUG_D3D("VideoDisplay/DX9: Failed to get current adapter mode.\n");
  418.         Shutdown();
  419.         return false;
  420.     }
  421.  
  422. #if 1
  423.     mPresentParms.BackBufferWidth    = mode.Width;
  424.     mPresentParms.BackBufferHeight    = mode.Height;
  425. #else
  426.     mPresentParms.BackBufferWidth    = 1600;
  427.     mPresentParms.BackBufferHeight    = 1200;
  428.     mPresentParms.BackBufferCount    = 3;
  429. #endif
  430.  
  431.     // Make sure we have at least X8R8G8B8 for a texture format
  432.     hr = mpD3D->CheckDeviceFormat(adapter, type, D3DFMT_X8R8G8B8, 0, D3DRTYPE_TEXTURE, D3DFMT_X8R8G8B8);
  433.     if (FAILED(hr)) {
  434.         VDDEBUG_D3D("VideoDisplay/DX9: Device does not support X8R8G8B8 textures.\n");
  435.         Shutdown();
  436.         return false;
  437.     }
  438.  
  439.     // Make sure we have at least X8R8G8B8 or A8R8G8B8 for a backbuffer format
  440.     mPresentParms.BackBufferFormat    = D3DFMT_A8R8G8B8;
  441.     hr = mpD3D->CheckDeviceFormat(adapter, type, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_A8R8G8B8);
  442.     if (FAILED(hr)) {
  443.         mPresentParms.BackBufferFormat    = D3DFMT_A8R8G8B8;
  444.         hr = mpD3D->CheckDeviceFormat(adapter, type, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_X8R8G8B8);
  445.  
  446.         if (FAILED(hr)) {
  447.             VDDEBUG_D3D("VideoDisplay/DX9: Device does not support X8R8G8B8 or A8R8G8B8 render targets.\n");
  448.             Shutdown();
  449.             return false;
  450.         }
  451.     }
  452.  
  453.     // Check if at least vertex shader 1.1 is supported; if not, force SWVP.
  454.     hr = mpD3D->GetDeviceCaps(adapter, type, &mDevCaps);
  455.     if (FAILED(hr)) {
  456.         VDDEBUG_D3D("VideoDisplay/DX9: Couldn't retrieve device caps.\n");
  457.         Shutdown();
  458.         return false;
  459.     }
  460.  
  461.     if (mDevCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
  462.         dwFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  463.     else
  464.         dwFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  465.  
  466.     // Create the device.
  467.     hr = mpD3D->CreateDevice(adapter, type, mhwndDevice, dwFlags, &mPresentParms, &mpD3DDevice);
  468.     if (FAILED(hr)) {
  469.         VDDEBUG_D3D("VideoDisplay/DX9: Failed to create device.\n");
  470.         Shutdown();
  471.         return false;
  472.     }
  473.  
  474.     mbDeviceValid = true;
  475.  
  476.     // retrieve device caps
  477.     memset(&mDevCaps, 0, sizeof mDevCaps);
  478.     hr = mpD3DDevice->GetDeviceCaps(&mDevCaps);
  479.     if (FAILED(hr)) {
  480.         VDDEBUG_D3D("VideoDisplay/DX9: Failed to retrieve device caps.\n");
  481.         Shutdown();
  482.         return false;
  483.     }
  484.  
  485.     // Check for Virge/Rage Pro/Riva128
  486.     if (Is3DCardLame()) {
  487.         Shutdown();
  488.         return false;
  489.     }
  490.  
  491.     const D3DVERTEXELEMENT9 kVertexDecl[]={
  492.         { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  493.         { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
  494.         { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  495.         { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
  496.         D3DDECL_END()
  497.     };
  498.  
  499.     hr = mpD3DDevice->CreateVertexDeclaration(kVertexDecl, &mpD3DVD);
  500.     if (FAILED(hr)) {
  501.         Shutdown();
  502.         return false;
  503.     }
  504.  
  505.     if (!InitVRAMResources()) {
  506.         Shutdown();
  507.         return false;
  508.     }
  509.     return true;
  510. }
  511.  
  512. bool VDD3D9Manager::InitVRAMResources() {
  513.     // retrieve display mode
  514.     HRESULT hr = mpD3D->GetAdapterDisplayMode(mAdapter, &mDisplayMode);
  515.     if (FAILED(hr)) {
  516.         VDDEBUG_D3D("VideoDisplay/DX9: Failed to get current adapter mode.\n");
  517.         Shutdown();
  518.         return false;
  519.     }
  520.  
  521.     // retrieve back buffer
  522.     if (!mpD3DRTMain) {
  523.         hr = mpD3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &mpD3DRTMain);
  524.         if (FAILED(hr)) {
  525.             ShutdownVRAMResources();
  526.             return false;
  527.         }
  528.     }
  529.  
  530.     // create vertex buffer
  531.     if (!mpD3DVB) {
  532.         hr = mpD3DDevice->CreateVertexBuffer(kVertexBufferSize * sizeof(Vertex), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2, D3DPOOL_DEFAULT, &mpD3DVB, NULL);
  533.         if (FAILED(hr)) {
  534.             VDDEBUG_D3D("VideoDisplay/DX9: Failed to create vertex buffer.\n");
  535.             ShutdownVRAMResources();
  536.             return false;
  537.         }
  538.         mVertexBufferPt = 0;
  539.     }
  540.  
  541.     // create index buffer
  542.     if (!mpD3DIB) {
  543.         hr = mpD3DDevice->CreateIndexBuffer(kIndexBufferSize * sizeof(uint16), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &mpD3DIB, NULL);
  544.         if (FAILED(hr)) {
  545.             VDDEBUG_D3D("VideoDisplay/DX9: Failed to create index buffer.\n");
  546.             ShutdownVRAMResources();
  547.             return false;
  548.         }
  549.         mIndexBufferPt = 0;
  550.     }
  551.  
  552.     // create flush event
  553.     mbSupportsEventQueries = false;
  554.     if (!mpD3DQuery) {
  555.         hr = mpD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
  556.         if (SUCCEEDED(hr)) {
  557.             mbSupportsEventQueries = true;
  558.             hr = mpD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &mpD3DQuery);
  559.         }
  560.     }
  561.  
  562.     // get implicit swap chain
  563.     if (!mpImplicitSwapChain) {
  564.         vdrefptr<IDirect3DSwapChain9> pD3DSwapChain;
  565.         hr = mpD3DDevice->GetSwapChain(0, ~pD3DSwapChain);
  566.         if (FAILED(hr)) {
  567.             VDDEBUG_D3D("VideoDisplay/DX9: Failed to obtain implicit swap chain.\n");
  568.             ShutdownVRAMResources();
  569.             return false;
  570.         }
  571.  
  572.         mpImplicitSwapChain = new_nothrow VDD3D9SwapChain(pD3DSwapChain);
  573.         if (!mpImplicitSwapChain) {
  574.             VDDEBUG_D3D("VideoDisplay/DX9: Failed to obtain implicit swap chain.\n");
  575.             ShutdownVRAMResources();
  576.             return false;
  577.         }
  578.         mpImplicitSwapChain->AddRef();
  579.     }
  580.  
  581.     SharedTextures::iterator it(mSharedTextures.begin()), itEnd(mSharedTextures.end());
  582.     for(; it!=itEnd; ++it) {
  583.         VDD3D9Texture& texture = **it;
  584.  
  585.         texture.InitVRAMResources();
  586.     }
  587.  
  588.     return true;
  589. }
  590.  
  591. void VDD3D9Manager::ShutdownVRAMResources() {
  592.     SharedTextures::iterator it(mSharedTextures.begin()), itEnd(mSharedTextures.end());
  593.     for(; it!=itEnd; ++it) {
  594.         VDD3D9Texture& texture = **it;
  595.  
  596.         texture.ShutdownVRAMResources();
  597.     }
  598.  
  599.     if (mpImplicitSwapChain) {
  600.         mpImplicitSwapChain->Release();
  601.         mpImplicitSwapChain = NULL;
  602.     }
  603.  
  604.     mFenceQueueBase += mFenceQueue.size();
  605.     mFenceQueueHeadIndex = 0;
  606.  
  607.     while(!mFenceQueue.empty()) {
  608.         IDirect3DQuery9 *pQuery = mFenceQueue.back();
  609.         mFenceQueue.pop_back();
  610.  
  611.         if (pQuery)
  612.             pQuery->Release();
  613.     }
  614.  
  615.     while(!mFenceFreeList.empty()) {
  616.         IDirect3DQuery9 *pQuery = mFenceFreeList.back();
  617.         mFenceFreeList.pop_back();
  618.  
  619.         pQuery->Release();
  620.     }
  621.  
  622.     if (mpD3DQuery) {
  623.         mpD3DQuery->Release();
  624.         mpD3DQuery = NULL;
  625.     }
  626.  
  627.     if (mpD3DRTMain) {
  628.         mpD3DRTMain->Release();
  629.         mpD3DRTMain = NULL;
  630.     }
  631.  
  632.     if (mpD3DIB) {
  633.         mpD3DIB->Release();
  634.         mpD3DIB = NULL;
  635.     }
  636.  
  637.     if (mpD3DVB) {
  638.         mpD3DVB->Release();
  639.         mpD3DVB = NULL;
  640.     }
  641. }
  642.  
  643. void VDD3D9Manager::Shutdown() {
  644.     mbDeviceValid = false;
  645.  
  646.     ShutdownVRAMResources();
  647.  
  648.     for(vdlist<VDD3D9Client>::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  649.         VDD3D9Client& client = **it;
  650.  
  651.         client.OnPreDeviceReset();
  652.     }
  653.  
  654.     while(!mSharedTextures.empty()) {
  655.         VDD3D9Texture *pTexture = mSharedTextures.back();
  656.         mSharedTextures.pop_back();
  657.  
  658.         pTexture->mListNodePrev = pTexture->mListNodeNext = pTexture;
  659.         pTexture->Release();
  660.     }
  661.  
  662.     if (mpD3DVD) {
  663.         mpD3DVD->Release();
  664.         mpD3DVD = NULL;
  665.     }
  666.  
  667.     if (mpD3DDevice) {
  668.         mpD3DDevice->Release();
  669.         mpD3DDevice = NULL;
  670.     }
  671.  
  672.     if (mpD3D) {
  673.         mpD3D->Release();
  674.         mpD3D = NULL;
  675.     }
  676.  
  677.     if (mhmodDX9) {
  678.         FreeLibrary(mhmodDX9);
  679.         mhmodDX9 = NULL;
  680.     }
  681.  
  682.     if (mhwndDevice) {
  683.         DestroyWindow(mhwndDevice);
  684.         mhwndDevice = NULL;
  685.     }
  686.  
  687.     if (mDevWndClass) {
  688.         UnregisterClass(MAKEINTATOM(mDevWndClass), VDGetLocalModuleHandleW32());
  689.         mDevWndClass = NULL;
  690.     }
  691. }
  692.  
  693. void VDD3D9Manager::AdjustFullScreen(bool fs) {
  694.     if (fs) {
  695.         ++mFullScreenCount;
  696.     } else {
  697.         --mFullScreenCount;
  698.         VDASSERT(mFullScreenCount >= 0);
  699.     }
  700.  
  701.     bool newState = mFullScreenCount != 0;
  702.  
  703.     if ((!mPresentParms.Windowed) != newState) {
  704.         D3DDISPLAYMODE dm;
  705.         mpD3DDevice->GetDisplayMode(0, &dm);
  706.         if (newState) {
  707.             UINT count = mpD3D->GetAdapterModeCount(mAdapter, D3DFMT_X8R8G8B8);
  708.  
  709.             D3DDISPLAYMODE dm2;
  710.             D3DDISPLAYMODE dmbest={0};
  711.             int bestindex = -1;
  712.             
  713.             for(UINT mode=0; mode<count; ++mode) {
  714.                 HRESULT hr = mpD3D->EnumAdapterModes(mAdapter, D3DFMT_X8R8G8B8, mode, &dm2);
  715.                 if (FAILED(hr))
  716.                     break;
  717.  
  718.  
  719.                 if (dmbest.Width == 0 || abs((int)dm2.Width - (int)dm.Width) + abs((int)dm2.Height - (int)dm.Height) < abs((int)dmbest.Width - (int)dm.Width) + abs((int)dmbest.Height - (int)dm.Height)) {
  720.                     dmbest = dm2;
  721.                     bestindex = (int)mode;
  722.                 }
  723.             }
  724.  
  725.             if (bestindex < 0) {
  726.                 mPresentParms.BackBufferWidth = dm.Width;
  727.                 mPresentParms.BackBufferHeight = dm.Height;
  728.                 mPresentParms.BackBufferFormat = D3DFMT_X8R8G8B8;
  729.             } else {
  730.                 mPresentParms.BackBufferWidth = dmbest.Width;
  731.                 mPresentParms.BackBufferHeight = dmbest.Height;
  732.                 mPresentParms.BackBufferFormat = D3DFMT_X8R8G8B8;
  733.             }
  734.         } else {
  735.             mPresentParms.BackBufferWidth = dm.Width;
  736.             mPresentParms.BackBufferHeight = dm.Height;
  737.             mPresentParms.BackBufferFormat = D3DFMT_UNKNOWN;
  738.         }
  739.  
  740.         mPresentParms.Windowed = !newState;
  741.         mPresentParms.SwapEffect = newState ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY;
  742.         mPresentParms.BackBufferCount = newState ? 1 : 1;
  743.         mPresentParms.PresentationInterval = newState ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
  744.         mPresentParms.FullScreen_RefreshRateInHz = newState ? 60 : 0;
  745.  
  746.         Reset();
  747.     }
  748. }
  749.  
  750. bool VDD3D9Manager::Reset() {
  751.     if (!mPresentParms.Windowed) {
  752.         HRESULT hr = mpD3DDevice->TestCooperativeLevel();
  753.         if (FAILED(hr))
  754.             return false;
  755.  
  756.         // Do not reset the device if we do not have focus!
  757.         HWND hwndFore = GetForegroundWindow();
  758.         if (!hwndFore)
  759.             return false;
  760.  
  761.         DWORD pid;
  762.         DWORD tid = GetWindowThreadProcessId(hwndFore, &pid);
  763.  
  764.         if (GetCurrentProcessId() != pid)
  765.             return false;
  766.     }
  767.  
  768.     for(vdlist<VDD3D9Client>::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  769.         VDD3D9Client& client = **it;
  770.  
  771.         client.OnPreDeviceReset();
  772.     }
  773.  
  774.     ShutdownVRAMResources();
  775.  
  776.     HRESULT hr = mpD3DDevice->Reset(&mPresentParms);
  777.     if (FAILED(hr)) {
  778.         mbDeviceValid = false;
  779.         return false;
  780.     }
  781.  
  782.     mbInScene = false;
  783.     if (!InitVRAMResources())
  784.         return false;
  785.  
  786.     mbDeviceValid = true;
  787.  
  788.     for(vdlist<VDD3D9Client>::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  789.         VDD3D9Client& client = **it;
  790.  
  791.         client.OnPostDeviceReset();
  792.     }
  793.  
  794.     return true;
  795. }
  796.  
  797. bool VDD3D9Manager::CheckDevice() {
  798.     if (!mpD3DDevice)
  799.         return false;
  800.  
  801.     if (!mbDeviceValid) {
  802.         HRESULT hr = mpD3DDevice->TestCooperativeLevel();
  803.  
  804.         if (FAILED(hr)) {
  805.             if (hr != D3DERR_DEVICENOTRESET)
  806.                 return false;
  807.  
  808.             if (!Reset())
  809.                 return false;
  810.         }
  811.     }
  812.  
  813.     return InitVRAMResources();
  814. }
  815.  
  816. bool VDD3D9Manager::CheckReturn(HRESULT hr) {
  817.     if (hr == D3DERR_DEVICELOST)
  818.         mbDeviceValid = false;
  819.  
  820.     return SUCCEEDED(hr);
  821. }
  822.  
  823. bool VDD3D9Manager::AdjustTextureSize(int& texw, int& texh, bool nonPow2OK) {
  824.     int origw = texw;
  825.     int origh = texh;
  826.  
  827.     // check if we need to force a power of two
  828.     //
  829.     // flag combos:
  830.     //
  831.     //    None                    OK
  832.     //    POW2                    Constrain to pow2
  833.     //    NONPOW2CONDITIONAL        Invalid (but happens with some virtualization software)
  834.     //    POW2|NONPOW2CONDITIONAL    Constrain unless nonPow2OK is set
  835.  
  836.     if ((mDevCaps.TextureCaps & (D3DPTEXTURECAPS_POW2|D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) && (!nonPow2OK || !(mDevCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))) {
  837.         // make power of two
  838.         texw += texw - 1;
  839.         texh += texh - 1;
  840.  
  841.         while(int tmp = texw & (texw-1))
  842.             texw = tmp;
  843.         while(int tmp = texh & (texh-1))
  844.             texh = tmp;
  845.     }
  846.  
  847.     // enforce aspect ratio
  848.     if (mDevCaps.MaxTextureAspectRatio) {
  849.         while(texw * (int)mDevCaps.MaxTextureAspectRatio < texh)
  850.             texw += texw;
  851.         while(texh * (int)mDevCaps.MaxTextureAspectRatio < texw)
  852.             texh += texh;
  853.     }
  854.  
  855.     // enforce size limits
  856.     if ((unsigned)texw > mDevCaps.MaxTextureWidth)
  857.         texw = mDevCaps.MaxTextureWidth;
  858.  
  859.     if ((unsigned)texh > mDevCaps.MaxTextureHeight)
  860.         texh = mDevCaps.MaxTextureHeight;
  861.  
  862.     return texw >= origw && texh >= origh;
  863. }
  864.  
  865. bool VDD3D9Manager::IsTextureFormatAvailable(D3DFORMAT format) {
  866.     HRESULT hr = mpD3D->CheckDeviceFormat(mAdapter, mDevType, mDisplayMode.Format, 0, D3DRTYPE_TEXTURE, format);
  867.  
  868.     return SUCCEEDED(hr);
  869. }
  870.  
  871. bool VDD3D9Manager::CheckResourceFormat(DWORD usage, D3DRESOURCETYPE rtype, D3DFORMAT checkFormat) const {
  872.     HRESULT hr = mpD3D->CheckDeviceFormat(mAdapter, mDevType, mDisplayMode.Format, usage, rtype, checkFormat);
  873.  
  874.     return SUCCEEDED(hr);
  875. }
  876.  
  877. void VDD3D9Manager::ClearRenderTarget(IDirect3DTexture9 *pTexture) {
  878.     IDirect3DSurface9 *pRTSurface;
  879.     if (FAILED(pTexture->GetSurfaceLevel(0, &pRTSurface)))
  880.         return;
  881.     HRESULT hr = mpD3DDevice->SetRenderTarget(0, pRTSurface);
  882.     pRTSurface->Release();
  883.  
  884.     if (FAILED(hr))
  885.         return;
  886.  
  887.     if (SUCCEEDED(mpD3DDevice->BeginScene())) {
  888.         mpD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0, 0.f, 0);
  889.         mpD3DDevice->EndScene();
  890.     }
  891. }
  892.  
  893. void VDD3D9Manager::ResetBuffers() {
  894.     mVertexBufferPt = 0;
  895.     mIndexBufferPt = 0;
  896. }
  897.  
  898. Vertex *VDD3D9Manager::LockVertices(unsigned vertices) {
  899.     VDASSERT(vertices <= kVertexBufferSize);
  900.     if (mVertexBufferPt + vertices > kVertexBufferSize) {
  901.         mVertexBufferPt = 0;
  902.     }
  903.  
  904.     mVertexBufferLockSize = vertices;
  905.  
  906.     void *p = NULL;
  907.     HRESULT hr;
  908.     for(;;) {
  909.         hr = mpD3DVB->Lock(mVertexBufferPt * sizeof(Vertex), mVertexBufferLockSize * sizeof(Vertex), &p, mVertexBufferPt ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
  910.         if (hr != D3DERR_WASSTILLDRAWING)
  911.             break;
  912.         Sleep(1);
  913.     }
  914.     if (FAILED(hr)) {
  915.         VDASSERT(false);
  916.         return NULL;
  917.     }
  918.  
  919.     return (Vertex *)p;
  920. }
  921.  
  922. void VDD3D9Manager::UnlockVertices() {
  923.     mVertexBufferPt += mVertexBufferLockSize;
  924.  
  925.     VDVERIFY(SUCCEEDED(mpD3DVB->Unlock()));
  926. }
  927.  
  928. bool VDD3D9Manager::UploadVertices(unsigned vertices, const Vertex *data) {
  929.     Vertex *vx = LockVertices(vertices);
  930.     if (!vx)
  931.         return false;
  932.  
  933.     bool success = true;
  934.     __try {
  935.         memcpy(vx, data, sizeof(Vertex)*vertices);
  936.     } _except(1) {
  937.         // still happens with some video drivers on device loss.. #&$*(#$
  938.         success = false;
  939.     }
  940.  
  941.     UnlockVertices();
  942.     return success;
  943. }
  944.  
  945. uint16 *VDD3D9Manager::LockIndices(unsigned indices) {
  946.     VDASSERT(indices <= kIndexBufferSize);
  947.     if (mIndexBufferPt + indices > kIndexBufferSize) {
  948.         mIndexBufferPt = 0;
  949.     }
  950.  
  951.     mIndexBufferLockSize = indices;
  952.  
  953.     void *p;
  954.     HRESULT hr;
  955.     for(;;) {
  956.         hr = mpD3DIB->Lock(mIndexBufferPt * sizeof(uint16), mIndexBufferLockSize * sizeof(uint16), &p, mIndexBufferPt ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
  957.         if (hr != D3DERR_WASSTILLDRAWING)
  958.             break;
  959.         Sleep(1);
  960.     }
  961.     if (FAILED(hr)) {
  962.         VDASSERT(false);
  963.         return NULL;
  964.     }
  965.  
  966.     return (uint16 *)p;
  967. }
  968.  
  969. void VDD3D9Manager::UnlockIndices() {
  970.     mIndexBufferPt += mIndexBufferLockSize;
  971.  
  972.     VDVERIFY(SUCCEEDED(mpD3DIB->Unlock()));
  973. }
  974.  
  975. bool VDD3D9Manager::BeginScene() {
  976.     if (!mbInScene) {
  977.         HRESULT hr = mpD3DDevice->BeginScene();
  978.  
  979.         if (FAILED(hr)) {
  980.             VDDEBUG_D3D("VideoDisplay/DX9: BeginScene() failed! hr = %08x\n", hr);
  981.             return false;
  982.         }
  983.  
  984.         mbInScene = true;
  985.     }
  986.  
  987.     return true;
  988. }
  989.  
  990. bool VDD3D9Manager::EndScene() {
  991.     if (mbInScene) {
  992.         mbInScene = false;
  993.         HRESULT hr = mpD3DDevice->EndScene();
  994.  
  995.         if (FAILED(hr)) {
  996.             VDDEBUG_D3D("VideoDisplay/DX9: EndScene() failed! hr = %08x\n", hr);
  997.             return false;
  998.         }
  999.     }
  1000.  
  1001.     return true;
  1002. }
  1003.  
  1004. void VDD3D9Manager::Flush() {
  1005.     if (mpD3DQuery) {
  1006.         HRESULT hr = mpD3DQuery->Issue(D3DISSUE_END);
  1007.         if (SUCCEEDED(hr)) {
  1008.             mpD3DQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
  1009.         }
  1010.     }
  1011. }
  1012.  
  1013. void VDD3D9Manager::Finish() {
  1014.     if (mpD3DQuery) {
  1015.         HRESULT hr = mpD3DQuery->Issue(D3DISSUE_END);
  1016.         if (SUCCEEDED(hr)) {
  1017.             while(S_FALSE == mpD3DQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
  1018.                 ::Sleep(1);
  1019.         }
  1020.     }
  1021. }
  1022.  
  1023. uint32 VDD3D9Manager::InsertFence() {
  1024.     IDirect3DQuery9 *pQuery = NULL;
  1025.     if (mFenceFreeList.empty()) {
  1026.         HRESULT hr = mpD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pQuery);
  1027.         if (FAILED(hr)) {
  1028.             VDASSERT(!"Unable to create D3D query.");
  1029.             pQuery = NULL;
  1030.         }
  1031.     } else {
  1032.         pQuery = mFenceFreeList.back();
  1033.         mFenceFreeList.pop_back();
  1034.     }
  1035.  
  1036.     uint32 id = (mFenceQueueBase + (uint32)mFenceQueue.size()) | 0x80000000;
  1037.     mFenceQueue.push_back(pQuery);
  1038.  
  1039.     if (pQuery) {
  1040.         HRESULT hr = pQuery->Issue(D3DISSUE_END);
  1041.         if (SUCCEEDED(hr))
  1042.             pQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
  1043.     }
  1044.  
  1045.     return id;
  1046. }
  1047.  
  1048. void VDD3D9Manager::WaitFence(uint32 id) {
  1049.     while(!IsFencePassed(id))
  1050.         ::Sleep(1);
  1051. }
  1052.  
  1053. bool VDD3D9Manager::IsFencePassed(uint32 id) {
  1054.     if (!id)
  1055.         return true;
  1056.  
  1057.     uint32 offset = (id - mFenceQueueBase) & 0x7fffffff;
  1058.  
  1059.     uint32 fenceQueueSize = (uint32)mFenceQueue.size();
  1060.     if (offset >= fenceQueueSize)
  1061.         return true;
  1062.  
  1063.     IDirect3DQuery9 *pQuery = mFenceQueue[offset];
  1064.     if (pQuery) {
  1065.         if (S_FALSE == pQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
  1066.             return false;
  1067.  
  1068.         mFenceFreeList.push_back(pQuery);
  1069.         mFenceQueue[offset] = NULL;
  1070.     }
  1071.  
  1072.     while(mFenceQueueHeadIndex < fenceQueueSize) {
  1073.         IDirect3DQuery9 *pQuery = mFenceQueue[mFenceQueueHeadIndex];
  1074.         if (pQuery) {
  1075.             if (S_FALSE == pQuery->GetData(NULL, 0, 0))
  1076.                 break;
  1077.  
  1078.             mFenceFreeList.push_back(pQuery);
  1079.             mFenceQueue[mFenceQueueHeadIndex] = NULL;
  1080.         }
  1081.  
  1082.         ++mFenceQueueHeadIndex;
  1083.     }
  1084.  
  1085.     if (mFenceQueueHeadIndex >= 64 && mFenceQueueHeadIndex+mFenceQueueHeadIndex >= fenceQueueSize) {
  1086.         mFenceQueueBase += mFenceQueueHeadIndex;
  1087.         mFenceQueue.erase(mFenceQueue.begin(), mFenceQueue.begin() + mFenceQueueHeadIndex);
  1088.         mFenceQueueHeadIndex = 0;
  1089.     }
  1090.  
  1091.     return true;
  1092. }
  1093.  
  1094. HRESULT VDD3D9Manager::DrawArrays(D3DPRIMITIVETYPE type, UINT vertStart, UINT primCount) {
  1095.     HRESULT hr = mpD3DDevice->DrawPrimitive(type, mVertexBufferPt - mVertexBufferLockSize + vertStart, primCount);
  1096.  
  1097.     VDASSERT(SUCCEEDED(hr));
  1098.  
  1099.     return hr;
  1100. }
  1101.  
  1102. HRESULT VDD3D9Manager::DrawElements(D3DPRIMITIVETYPE type, UINT vertStart, UINT vertCount, UINT idxStart, UINT primCount) {
  1103.     // The documentation for IDirect3DDevice9::DrawIndexedPrimitive() was probably
  1104.     // written under a hallucinogenic state.
  1105.  
  1106.     HRESULT hr = mpD3DDevice->DrawIndexedPrimitive(type, mVertexBufferPt - mVertexBufferLockSize + vertStart, 0, vertCount, mIndexBufferPt - mIndexBufferLockSize + idxStart, primCount);
  1107.  
  1108.     VDASSERT(SUCCEEDED(hr));
  1109.  
  1110.     return hr;
  1111. }
  1112.  
  1113. HRESULT VDD3D9Manager::Present(const RECT *src, HWND hwndDest, bool vsync, float& syncdelta, VDD3DPresentHistory& history) {
  1114.     if (!mPresentParms.Windowed)
  1115.         return S_OK;
  1116.  
  1117.     HRESULT hr;
  1118.  
  1119.     if (vsync && (mDevCaps.Caps & D3DCAPS_READ_SCANLINE)) {
  1120.         if (mpD3DQuery) {
  1121.             hr = mpD3DQuery->Issue(D3DISSUE_END);
  1122.             if (SUCCEEDED(hr)) {
  1123.                 while(S_FALSE == mpD3DQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
  1124.                     ::Sleep(1);
  1125.             }
  1126.         }
  1127.  
  1128.         RECT r;
  1129.         if (GetWindowRect(hwndDest, &r)) {
  1130.             int top = 0;
  1131.             int bottom = GetSystemMetrics(SM_CYSCREEN);
  1132.  
  1133.             // GetMonitorInfo() requires Windows 98. We might never fail on this because
  1134.             // I think DirectX 9.0c requires 98+, but we have to dynamically link anyway
  1135.             // to avoid a startup link failure on 95.
  1136.             typedef BOOL (APIENTRY *tpGetMonitorInfo)(HMONITOR mon, LPMONITORINFO lpmi);
  1137.             static tpGetMonitorInfo spGetMonitorInfo = (tpGetMonitorInfo)GetProcAddress(GetModuleHandle("user32"), "GetMonitorInfo");
  1138.  
  1139.             if (spGetMonitorInfo) {
  1140.                 HMONITOR hmon = mpD3D->GetAdapterMonitor(mAdapter);
  1141.                 MONITORINFO monInfo = {sizeof(MONITORINFO)};
  1142.                 if (spGetMonitorInfo(hmon, &monInfo)) {
  1143.                     top = monInfo.rcMonitor.top;
  1144.                     bottom = monInfo.rcMonitor.bottom;
  1145.                 }
  1146.             }
  1147.  
  1148.             if (r.top < top)
  1149.                 r.top = top;
  1150.             if (r.bottom > bottom)
  1151.                 r.bottom = bottom;
  1152.  
  1153.             top += VDRoundToInt(history.mPresentDelay);
  1154.  
  1155.             r.top -= top;
  1156.             r.bottom -= top;
  1157.  
  1158.             // Poll raster status, and wait until we can safely blit. We assume that the
  1159.             // blit can outrace the beam. 
  1160.             D3DRASTER_STATUS rastStatus;
  1161.             UINT maxScanline = 0;
  1162.             int firstScan = -1;
  1163.             while(SUCCEEDED(mpD3DDevice->GetRasterStatus(0, &rastStatus))) {
  1164.                 if (firstScan < 0)
  1165.                     firstScan = rastStatus.InVBlank ? 0 : (int)rastStatus.ScanLine;
  1166.  
  1167.                 if (rastStatus.InVBlank) {
  1168.                     if (history.mVBlankSuccess >= 0.5f)
  1169.                         break;
  1170.  
  1171.                     rastStatus.ScanLine = 0;
  1172.                 }
  1173.  
  1174.                 // Check if we have wrapped around without seeing the VBlank. If this
  1175.                 // occurs, force an exit. This prevents us from potentially burning a lot
  1176.                 // of CPU time if the CPU becomes busy and can't poll the beam in a timely
  1177.                 // manner.
  1178.                 if (rastStatus.ScanLine < maxScanline)
  1179.                     break;
  1180.  
  1181.                 // Check if we're outside of the danger zone.
  1182.                 if ((int)rastStatus.ScanLine < r.top || (int)rastStatus.ScanLine >= r.bottom)
  1183.                     break;
  1184.  
  1185.                 // We're in the danger zone. If the delta is greater than one tenth of the
  1186.                 // display, do a sleep.
  1187.                 if ((r.bottom - (int)rastStatus.ScanLine) * 10 >= (int)mDisplayMode.Height)
  1188.                     ::Sleep(1);
  1189.  
  1190.                 maxScanline = rastStatus.ScanLine;
  1191.             }
  1192.  
  1193.             syncdelta = (float)(firstScan - r.bottom) / (float)(int)mDisplayMode.Height;
  1194.             syncdelta -= floorf(syncdelta);
  1195.             if (syncdelta > 0.5f)
  1196.                 syncdelta -= 1.0f;
  1197.  
  1198.             hr = mpD3DDevice->Present(src, NULL, hwndDest, NULL);
  1199.             if (FAILED(hr))
  1200.                 return hr;
  1201.  
  1202.             D3DRASTER_STATUS rastStatus2;
  1203.             hr = mpD3DDevice->GetRasterStatus(0, &rastStatus2);
  1204.             if (SUCCEEDED(hr)) {
  1205.                 if (rastStatus.InVBlank) {
  1206.                     float success = rastStatus2.InVBlank || (int)rastStatus2.ScanLine <= r.top || (int)rastStatus2.ScanLine >= r.bottom ? 1.0f : 0.0f;
  1207.  
  1208.                     history.mVBlankSuccess += (success - history.mVBlankSuccess) * 0.01f;
  1209.                 }
  1210.  
  1211.                 if (!rastStatus.InVBlank && !rastStatus2.InVBlank && rastStatus2.ScanLine > rastStatus.ScanLine) {
  1212.                     float delta = (float)(int)(rastStatus2.ScanLine - rastStatus.ScanLine);
  1213.  
  1214.                     history.mPresentDelay += (delta - history.mPresentDelay) * 0.01f;
  1215.                 }
  1216.             }
  1217.         }
  1218.     } else {
  1219.         syncdelta = 0.0f;
  1220.  
  1221.         hr = mpD3DDevice->Present(src, NULL, hwndDest, NULL);
  1222.     }
  1223.  
  1224.     return hr;
  1225. }
  1226.  
  1227. HRESULT VDD3D9Manager::PresentFullScreen(bool wait) {
  1228.     if (mPresentParms.Windowed)
  1229.         return S_OK;
  1230.  
  1231.     HRESULT hr;
  1232.     IDirect3DSwapChain9 *pSwapChain;
  1233.     hr = mpD3DDevice->GetSwapChain(0, &pSwapChain);
  1234.     if (FAILED(hr))
  1235.         return hr;
  1236.  
  1237.     for(;;) {
  1238.         hr = pSwapChain->Present(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTWAIT);
  1239.  
  1240.         if (SUCCEEDED(hr) || hr != D3DERR_WASSTILLDRAWING)
  1241.             break;
  1242.  
  1243.         if (!wait)
  1244.             return S_FALSE;
  1245.  
  1246.         ::Sleep(1);
  1247.     }
  1248.  
  1249.     // record raster status and time of this present
  1250.     mLastPresentTime = VDGetAccurateTick();
  1251.     mLastPresentScanLine = 0;
  1252.     if (mDevCaps.Caps & D3DCAPS_READ_SCANLINE) {
  1253.         D3DRASTER_STATUS rastStatus;
  1254.         hr = mpD3DDevice->GetRasterStatus(0, &rastStatus);
  1255.         if (SUCCEEDED(hr) && !rastStatus.InVBlank)
  1256.             mLastPresentScanLine = rastStatus.InVBlank;
  1257.     }
  1258.  
  1259.     pSwapChain->Release();
  1260.  
  1261.     return hr;
  1262. }
  1263.  
  1264. #define REQUIRE(x, reason) if (!(x)) { VDDEBUG_D3D("VideoDisplay/DX9: 3D device is lame -- reason: " reason "\n"); return true; } else ((void)0)
  1265. #define REQUIRECAPS(capsflag, bits, reason) REQUIRE(!(~mDevCaps.capsflag & (bits)), reason)
  1266.  
  1267. bool VDD3D9Manager::Is3DCardLame() {
  1268.     REQUIRE(mDevCaps.DeviceType != D3DDEVTYPE_SW, "software device detected");
  1269.     REQUIRECAPS(PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE, "primitive misc caps check failed");
  1270.     REQUIRECAPS(RasterCaps, D3DPRASTERCAPS_DITHER, "raster caps check failed");
  1271.     REQUIRECAPS(TextureCaps, D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_MIPMAP, "texture caps failed");
  1272.     REQUIRE(!(mDevCaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY), "device requires square textures");
  1273.     REQUIRECAPS(TextureFilterCaps, D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MAGFLINEAR
  1274.                                 | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MINFLINEAR
  1275.                                 | D3DPTFILTERCAPS_MIPFPOINT | D3DPTFILTERCAPS_MIPFLINEAR, "texture filtering modes insufficient");
  1276.     REQUIRECAPS(TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP, "texture addressing modes insufficient");
  1277.     REQUIRE(mDevCaps.MaxTextureBlendStages>0 && mDevCaps.MaxSimultaneousTextures>0, "not enough texture stages");
  1278.     return false;
  1279. }
  1280.  
  1281. bool VDD3D9Manager::CreateSharedTexture(const char *name, SharedTextureFactory factory, IVDD3D9Texture **ppTexture) {
  1282.     SharedTextures::iterator it(mSharedTextures.begin()), itEnd(mSharedTextures.end());
  1283.     for(; it!=itEnd; ++it) {
  1284.         VDD3D9Texture& texture = **it;
  1285.  
  1286.         if (!strcmp(texture.GetName(), name)) {
  1287.             *ppTexture = &texture;
  1288.             texture.AddRef();
  1289.             return true;
  1290.         }
  1291.     }
  1292.  
  1293.     vdrefptr<IVDD3D9TextureGenerator> pGenerator;
  1294.     if (factory) {
  1295.         if (!factory(~pGenerator))
  1296.             return false;
  1297.     }
  1298.  
  1299.     vdrefptr<VDD3D9Texture> pTexture(new_nothrow VDD3D9Texture);
  1300.     if (!pTexture)
  1301.         return false;
  1302.  
  1303.     pTexture->SetName(name);
  1304.  
  1305.     if (!pTexture->Init(this, pGenerator))
  1306.         return false;
  1307.  
  1308.     mSharedTextures.push_back(pTexture);
  1309.  
  1310.     *ppTexture = pTexture.release();
  1311.     return true;
  1312. }
  1313.  
  1314. bool VDD3D9Manager::CreateSwapChain(int width, int height, bool clipToMonitor, IVDD3D9SwapChain **ppSwapChain) {
  1315.     D3DPRESENT_PARAMETERS pparms={};
  1316.  
  1317.     pparms.Windowed            = TRUE;
  1318.     pparms.SwapEffect        = D3DSWAPEFFECT_COPY;
  1319.     pparms.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1320.     pparms.BackBufferWidth    = width;
  1321.     pparms.BackBufferHeight    = height;
  1322.     pparms.BackBufferCount    = 1;
  1323.     pparms.BackBufferFormat    = mPresentParms.BackBufferFormat;
  1324.     pparms.Flags = clipToMonitor ? D3DPRESENTFLAG_DEVICECLIP : 0;
  1325.  
  1326.     vdrefptr<IDirect3DSwapChain9> pD3DSwapChain;
  1327.     HRESULT hr = mpD3DDevice->CreateAdditionalSwapChain(&pparms, ~pD3DSwapChain);
  1328.     if (FAILED(hr))
  1329.         return false;
  1330.  
  1331.     vdrefptr<VDD3D9SwapChain> pSwapChain(new_nothrow VDD3D9SwapChain(pD3DSwapChain));
  1332.     if (!pSwapChain)
  1333.         return false;
  1334.  
  1335.     *ppSwapChain = pSwapChain.release();
  1336.     return true;
  1337. }
  1338.  
  1339. void VDD3D9Manager::SetSwapChainActive(IVDD3D9SwapChain *pSwapChain) {
  1340.     if (!pSwapChain)
  1341.         pSwapChain = mpImplicitSwapChain;
  1342.  
  1343.     IDirect3DSwapChain9 *pD3DSwapChain = static_cast<VDD3D9SwapChain *>(pSwapChain)->GetD3DSwapChain();
  1344.  
  1345.     IDirect3DSurface9 *pD3DBackBuffer;
  1346.     HRESULT hr = pD3DSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pD3DBackBuffer);
  1347.     if (FAILED(hr))
  1348.         return;
  1349.  
  1350.     hr = mpD3DDevice->SetRenderTarget(0, pD3DBackBuffer);
  1351.     pD3DBackBuffer->Release();
  1352. }
  1353.  
  1354. HRESULT VDD3D9Manager::PresentSwapChain(IVDD3D9SwapChain *pSwapChain, const RECT *srcRect, HWND hwndDest, bool vsync, bool newframe, bool donotwait, float& syncDelta, VDD3DPresentHistory& history) {
  1355.     if (!mPresentParms.Windowed)
  1356.         return S_OK;
  1357.  
  1358.     if (!pSwapChain) {
  1359.         pSwapChain = mpImplicitSwapChain;
  1360.         if (!pSwapChain)
  1361.             return E_FAIL;
  1362.     }
  1363.  
  1364.     IDirect3DSwapChain9 *pD3DSwapChain = static_cast<VDD3D9SwapChain *>(pSwapChain)->GetD3DSwapChain();
  1365.     HRESULT hr;
  1366.  
  1367.     if (!vsync || !(mDevCaps.Caps & D3DCAPS_READ_SCANLINE)) {
  1368.         if (!newframe)
  1369.             return S_OK;
  1370.  
  1371.         syncDelta = 0.0f;
  1372.  
  1373.         for(;;) {
  1374.             hr = pD3DSwapChain->Present(srcRect, NULL, hwndDest, NULL, D3DPRESENT_DONOTWAIT);
  1375.  
  1376.             if (hr != D3DERR_WASSTILLDRAWING)
  1377.                 break;
  1378.  
  1379.             ::Sleep(1);
  1380.         }
  1381.  
  1382.         history.mbPresentPending = false;
  1383.         return hr;
  1384.     }
  1385.  
  1386.     // Okay, now we know we're doing vsync.
  1387.     if (newframe && !history.mbPresentPending) {
  1388.         RECT r;
  1389.         if (!GetWindowRect(hwndDest, &r))
  1390.             return E_FAIL;
  1391.  
  1392.         int top = 0;
  1393.         int bottom = GetSystemMetrics(SM_CYSCREEN);
  1394.  
  1395.         // GetMonitorInfo() requires Windows 98. We might never fail on this because
  1396.         // I think DirectX 9.0c requires 98+, but we have to dynamically link anyway
  1397.         // to avoid a startup link failure on 95.
  1398.         typedef BOOL (APIENTRY *tpGetMonitorInfo)(HMONITOR mon, LPMONITORINFO lpmi);
  1399.         static tpGetMonitorInfo spGetMonitorInfo = (tpGetMonitorInfo)GetProcAddress(GetModuleHandle("user32"), "GetMonitorInfo");
  1400.  
  1401.         if (spGetMonitorInfo) {
  1402.             HMONITOR hmon = mpD3D->GetAdapterMonitor(mAdapter);
  1403.             MONITORINFO monInfo = {sizeof(MONITORINFO)};
  1404.             if (spGetMonitorInfo(hmon, &monInfo)) {
  1405.                 top = monInfo.rcMonitor.top;
  1406.                 bottom = monInfo.rcMonitor.bottom;
  1407.             }
  1408.         }
  1409.  
  1410.         if (r.top < top)
  1411.             r.top = top;
  1412.         if (r.bottom > bottom)
  1413.             r.bottom = bottom;
  1414.  
  1415.         r.top -= top;
  1416.         r.bottom -= top;
  1417.  
  1418.         history.mScanTop = r.top;
  1419.         history.mScanBottom = r.bottom;
  1420.  
  1421.         newframe = false;
  1422.         history.mbPresentPending = true;
  1423.         history.mbPresentBlitStarted = false;
  1424.  
  1425.         history.mLastScanline = -1;
  1426.         history.mPresentStartTime = VDGetPreciseTick();
  1427.     }
  1428.  
  1429.     if (!history.mbPresentPending)
  1430.         return S_OK;
  1431.  
  1432.     // Poll raster status, and wait until we can safely blit. We assume that the
  1433.     // blit can outrace the beam. 
  1434.     ++history.mPollCount;
  1435.     for(;;) {
  1436.         // if we've already started the blit, skip beam-following
  1437.         if (history.mbPresentBlitStarted)
  1438.             break;
  1439.  
  1440.         D3DRASTER_STATUS rastStatus;
  1441.         hr = pD3DSwapChain->GetRasterStatus(&rastStatus);
  1442.         if (FAILED(hr))
  1443.             return hr;
  1444.  
  1445.         if (rastStatus.InVBlank)
  1446.             rastStatus.ScanLine = 0;
  1447.  
  1448.         sint32 y1 = (sint32)history.mLastScanline;
  1449.         if (y1 < 0) {
  1450.             y1 = rastStatus.ScanLine;
  1451.             history.mAverageStartScanline += ((float)y1 - history.mAverageStartScanline) * 0.01f;
  1452.         }
  1453.  
  1454.         sint32 y2 = (sint32)rastStatus.ScanLine;
  1455.  
  1456.         history.mbLastWasVBlank    = rastStatus.InVBlank ? true : false;
  1457.         history.mLastScanline    = rastStatus.ScanLine;
  1458.  
  1459.         sint32 yt = (sint32)history.mScanlineTarget;
  1460.  
  1461.         history.mLastBracketY1 = y1;
  1462.         history.mLastBracketY2 = y2;
  1463.  
  1464.         // check for yt in [y1, y2]... but we have to watch for a beam wrap (y1 > y2).
  1465.         if (y1 <= y2) {
  1466.             // non-wrap case
  1467.             if (y1 <= yt && yt <= y2)
  1468.                 break;
  1469.         } else {
  1470.             // wrap case
  1471.             if (y1 <= yt || yt <= y2)
  1472.                 break;
  1473.         }
  1474.  
  1475.         if (donotwait)
  1476.             return S_FALSE;
  1477.  
  1478.         ::Sleep(1);
  1479.     }
  1480.  
  1481.     history.mbPresentBlitStarted = true;
  1482.  
  1483.     if (donotwait) {
  1484.         hr = pD3DSwapChain->Present(srcRect, NULL, hwndDest, NULL, D3DPRESENT_DONOTWAIT);
  1485.  
  1486.         if (hr == D3DERR_WASSTILLDRAWING)
  1487.             return S_FALSE;
  1488.     } else
  1489.         hr = pD3DSwapChain->Present(srcRect, NULL, hwndDest, NULL, 0);
  1490.  
  1491.     history.mbPresentPending = false;
  1492.     if (FAILED(hr))
  1493.         return hr;
  1494.  
  1495.     history.mAverageEndScanline += ((float)history.mLastScanline - history.mAverageEndScanline) * 0.01f;
  1496.     history.mAveragePresentTime += ((VDGetPreciseTick() - history.mPresentStartTime)*VDGetPreciseSecondsPerTick() - history.mAveragePresentTime) * 0.01f;
  1497.  
  1498.     D3DRASTER_STATUS rastStatus2;
  1499.     hr = pD3DSwapChain->GetRasterStatus(&rastStatus2);
  1500.     syncDelta = 0.0f;
  1501.     if (SUCCEEDED(hr)) {
  1502.         if (rastStatus2.InVBlank)
  1503.             rastStatus2.ScanLine = 0;
  1504.  
  1505.         float yf = ((float)rastStatus2.ScanLine - (float)history.mScanTop) / ((float)history.mScanBottom - (float)history.mScanTop);
  1506.  
  1507.         yf -= 0.2f;
  1508.  
  1509.         if (yf < 0.0f)
  1510.             yf = 0.0f;
  1511.         if (yf > 1.0f)
  1512.             yf = 1.0f;
  1513.  
  1514.         if (yf > 0.5f)
  1515.             yf -= 1.0f;
  1516.  
  1517.         syncDelta = yf;
  1518.  
  1519.         history.mScanlineTarget -= yf * 15.0f;
  1520.         if (history.mScanlineTarget < 0.0f)
  1521.             history.mScanlineTarget += (float)mDisplayMode.Height;
  1522.         else if (history.mScanlineTarget >= (float)mDisplayMode.Height)
  1523.             history.mScanlineTarget -= (float)mDisplayMode.Height;
  1524.  
  1525.         float success = rastStatus2.InVBlank || (int)rastStatus2.ScanLine <= history.mScanTop || (int)rastStatus2.ScanLine >= history.mScanBottom ? 1.0f : 0.0f;
  1526.  
  1527.         int zone = 0;
  1528.         if (!history.mbLastWasVBlank)
  1529.             zone = ((int)history.mLastScanline * 16) / (int)mDisplayMode.Height;
  1530.  
  1531.         for(int i=0; i<17; ++i) {
  1532.             if (i != zone)
  1533.                 history.mAttemptProb[i] *= 0.99f;
  1534.         }
  1535.  
  1536.         history.mAttemptProb[zone] += (1.0f - history.mAttemptProb[zone]) * 0.01f;
  1537.         history.mSuccessProb[zone] += (success - history.mSuccessProb[zone]) * 0.01f;
  1538.  
  1539.         if (history.mLastScanline < history.mScanTop) {
  1540.             history.mVBlankSuccess += (success - history.mVBlankSuccess) * 0.01f;
  1541.         }
  1542.  
  1543.         if (!history.mbLastWasVBlank && !rastStatus2.InVBlank && (int)rastStatus2.ScanLine > history.mLastScanline) {
  1544.             float delta = (float)(int)(rastStatus2.ScanLine - history.mLastScanline);
  1545.  
  1546.             history.mPresentDelay += (delta - history.mPresentDelay) * 0.01f;
  1547.         }
  1548.     }
  1549.  
  1550.     return hr;
  1551. }
  1552.  
  1553. LRESULT CALLBACK VDD3D9Manager::StaticDeviceWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  1554.     switch(msg) {
  1555.         case WM_SETFOCUS:
  1556.             {
  1557.                 HWND hwndOldFocus = (HWND)wParam;
  1558.  
  1559.                 // Direct3D likes to send focus to the focus window when you go full screen. Well,
  1560.                 // we don't want that since we're using a hidden window, so if the focus came from
  1561.                 // another window of ours, we send the focus back.
  1562.                 if (hwndOldFocus) {
  1563.                     DWORD pid;
  1564.                     DWORD tid = GetWindowThreadProcessId(hwndOldFocus, &pid);
  1565.  
  1566.                     if (tid == GetCurrentThreadId()) {
  1567.                         SetFocus(hwndOldFocus);
  1568.                         return 0;
  1569.                     }
  1570.                 }
  1571.             }
  1572.             break;
  1573.     }
  1574.  
  1575.     return DefWindowProc(hwnd, msg, wParam, lParam);
  1576. }
  1577.