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 / displaydx9.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-10-24  |  92.2 KB  |  3,097 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/binary.h>
  34. #include <vd2/system/refcount.h>
  35. #include <vd2/system/math.h>
  36. #include <vd2/system/time.h>
  37. #include <vd2/system/vdstl.h>
  38. #include <vd2/system/w32assist.h>
  39. #include <vd2/Kasumi/pixmap.h>
  40. #include <vd2/Kasumi/pixmapops.h>
  41. #include <vd2/Kasumi/pixmaputils.h>
  42. #include <vd2/Kasumi/text.h>
  43. #include <vd2/Kasumi/region.h>
  44.  
  45. #include <vd2/Riza/direct3d.h>
  46. #include <vd2/Riza/displaydrvdx9.h>
  47. #include "displaydrv.h"
  48.  
  49. namespace {
  50.     #include "displaydx9_shader.inl"
  51. }
  52.  
  53. //#define VDDEBUG_DX9DISP VDDEBUG
  54. #define VDDEBUG_DX9DISP (void)sizeof
  55.  
  56. #define D3D_DO(x) VDVERIFY(SUCCEEDED(mpD3DDevice->x))
  57.  
  58. using namespace nsVDD3D9;
  59.  
  60. bool VDCreateD3D9TextureGeneratorFullSizeRTT(IVDD3D9TextureGenerator **ppGenerator);
  61. bool VDCreateD3D9TextureGeneratorFullSizeRTT16F(IVDD3D9TextureGenerator **ppGenerator);
  62.  
  63. ///////////////////////////////////////////////////////////////////////////
  64.  
  65. class VDD3D9TextureGeneratorDither : public vdrefcounted<IVDD3D9TextureGenerator> {
  66. public:
  67.     bool GenerateTexture(VDD3D9Manager *pManager, IVDD3D9Texture *pTexture) {
  68.         static const uint8 dither[16][16]={
  69.              35, 80,227,165, 64,199, 42,189,138, 74,238,111, 43,153, 13,211,
  70.             197,135, 20, 99,244,  4,162,105, 25,210, 38,134,225, 78,242, 87,
  71.              63,249,126,192, 50,174, 82,251,116,148, 97,176, 19,167, 52,163,
  72.             187, 30, 85,142,219, 71,194, 45,169, 11,241, 58,216,106,204,  5,
  73.              94,151,235,  9,112,155, 17,224, 91,206, 84,188,120, 36,132,233,
  74.             177, 48,124,201, 40,239,125, 66,180, 51,160,  7,152,255, 89, 56,
  75.              16,209, 72,161,121, 59,208,150, 28,248, 75,229,101, 26,140,220,
  76.             170,110,226, 22,252,139,  1,109,195,115,172, 39,200,114,191, 68,
  77.             136, 34, 96,183, 44,175, 95,234, 81, 15,143,217, 62,164,  2,237,
  78.              57,245,154, 61,203, 70,213, 37,137,243, 98, 23,179, 86,198,103,
  79.             184, 12,123,221,  6,129,156, 88,185, 53,127,228, 49,250, 31,130,
  80.              77,205, 83,145,107,247, 29,223, 10,212,159, 79,168, 73,146,232,
  81.             173, 41,240, 24,190, 54,178,102,149,118, 33,202,  8,215,119, 18,
  82.              92,158, 67,166, 76,207,133, 47,254, 65,230,100,131,157, 69,193,
  83.             253,  3,214,117,231, 14, 93,171, 21,182,144, 55,246, 27,222, 46,
  84.             141,181,104, 32,147,113,236, 60,218,122,  0,196, 90,186,128,108,
  85.         };
  86.  
  87.         IDirect3DDevice9 *dev = pManager->GetDevice();
  88.         vdrefptr<IDirect3DTexture9> tex;
  89.         HRESULT hr = dev->CreateTexture(16, 16, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ~tex, NULL);
  90.         if (FAILED(hr))
  91.             return false;
  92.  
  93.         D3DLOCKED_RECT lr;
  94.         hr = tex->LockRect(0, &lr, NULL, 0);
  95.         VDASSERT(SUCCEEDED(hr));
  96.         if (FAILED(hr)) {
  97.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to load horizontal even/odd texture.\n");
  98.             return false;
  99.         }
  100.  
  101.         char *dst = (char *)lr.pBits;
  102.         for(int y=0; y<16; ++y) {
  103.             const uint8 *srcrow = dither[y];
  104.             uint32 *dstrow = (uint32 *)dst;
  105.  
  106.             for(int x=0; x<16; ++x)
  107.                 dstrow[x] = 0x01010101 * srcrow[x];
  108.  
  109.             dst += lr.Pitch;
  110.         }
  111.  
  112.         VDVERIFY(SUCCEEDED(tex->UnlockRect(0)));
  113.  
  114.         pTexture->SetD3DTexture(tex);
  115.         return true;
  116.     }
  117. };
  118.  
  119. class VDD3D9TextureGeneratorHEvenOdd : public vdrefcounted<IVDD3D9TextureGenerator> {
  120. public:
  121.     bool GenerateTexture(VDD3D9Manager *pManager, IVDD3D9Texture *pTexture) {
  122.         IDirect3DDevice9 *dev = pManager->GetDevice();
  123.         vdrefptr<IDirect3DTexture9> tex;
  124.         HRESULT hr = dev->CreateTexture(16, 1, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ~tex, NULL);
  125.         if (FAILED(hr))
  126.             return false;
  127.  
  128.         D3DLOCKED_RECT lr;
  129.         hr = tex->LockRect(0, &lr, NULL, 0);
  130.         VDASSERT(SUCCEEDED(hr));
  131.         if (FAILED(hr)) {
  132.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to load horizontal even/odd texture.\n");
  133.             return false;
  134.         }
  135.  
  136.         for(int i=0; i<16; ++i)
  137.             ((uint32 *)lr.pBits)[i] = (uint32)-(sint32)(i&1);
  138.  
  139.         VDVERIFY(SUCCEEDED(tex->UnlockRect(0)));
  140.  
  141.         pTexture->SetD3DTexture(tex);
  142.         return true;
  143.     }
  144. };
  145.  
  146. class VDD3D9TextureGeneratorCubicFilter : public vdrefcounted<IVDD3D9TextureGenerator> {
  147. public:
  148.     VDD3D9TextureGeneratorCubicFilter(IVDVideoDisplayDX9Manager::CubicMode mode) : mCubicMode(mode) {}
  149.  
  150.     bool GenerateTexture(VDD3D9Manager *pManager, IVDD3D9Texture *pTexture) {
  151.         IDirect3DDevice9 *dev = pManager->GetDevice();
  152.         vdrefptr<IDirect3DTexture9> tex;
  153.         HRESULT hr = dev->CreateTexture(256, 4, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ~tex, NULL);
  154.         if (FAILED(hr))
  155.             return false;
  156.  
  157.         D3DLOCKED_RECT lr;
  158.         hr = tex->LockRect(0, &lr, NULL, 0);
  159.         VDASSERT(SUCCEEDED(hr));
  160.         if (FAILED(hr)) {
  161.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to load cubic filter texture.\n");
  162.             return false;
  163.         }
  164.  
  165.         MakeCubic4Texture((uint32 *)lr.pBits, lr.Pitch, -0.75, mCubicMode);
  166.  
  167.         VDVERIFY(SUCCEEDED(tex->UnlockRect(0)));
  168.  
  169.         pTexture->SetD3DTexture(tex);
  170.         return true;
  171.     }
  172.  
  173. protected:
  174.     IVDVideoDisplayDX9Manager::CubicMode mCubicMode;
  175.  
  176.     static void MakeCubic4Texture(uint32 *texture, ptrdiff_t pitch, double A, IVDVideoDisplayDX9Manager::CubicMode mode) {
  177.         int i;
  178.  
  179.         uint32 *p0 = texture;
  180.         uint32 *p1 = vdptroffset(texture, pitch);
  181.         uint32 *p2 = vdptroffset(texture, pitch*2);
  182.         uint32 *p3 = vdptroffset(texture, pitch*3);
  183.  
  184.         for(i=0; i<256; i++) {
  185.             double d = (double)(i&63) / 64.0;
  186.             int y1, y2, y3, y4, ydiff;
  187.  
  188.             // Coefficients for all four pixels *must* add up to 1.0 for
  189.             // consistent unity gain.
  190.             //
  191.             // Two good values for A are -1.0 (original VirtualDub bicubic filter)
  192.             // and -0.75 (closely matches Photoshop).
  193.  
  194.             double c1 =         +     A*d -       2.0*A*d*d +       A*d*d*d;
  195.             double c2 = + 1.0             -     (A+3.0)*d*d + (A+2.0)*d*d*d;
  196.             double c3 =         -     A*d + (2.0*A+3.0)*d*d - (A+2.0)*d*d*d;
  197.             double c4 =                   +           A*d*d -       A*d*d*d;
  198.  
  199.             const int maxval = 255;
  200.             double scale = maxval / (c1 + c2 + c3 + c4);
  201.  
  202.             y1 = (int)floor(0.5 + c1 * scale);
  203.             y2 = (int)floor(0.5 + c2 * scale);
  204.             y3 = (int)floor(0.5 + c3 * scale);
  205.             y4 = (int)floor(0.5 + c4 * scale);
  206.  
  207.             ydiff = maxval - y1 - y2 - y3 - y4;
  208.  
  209.             int ywhole = ydiff<0 ? (ydiff-2)/4 : (ydiff+2)/4;
  210.             ydiff -= ywhole*4;
  211.  
  212.             y1 += ywhole;
  213.             y2 += ywhole;
  214.             y3 += ywhole;
  215.             y4 += ywhole;
  216.  
  217.             if (ydiff < 0) {
  218.                 if (y1<y4)
  219.                     y1 += ydiff;
  220.                 else
  221.                     y4 += ydiff;
  222.             } else if (ydiff > 0) {
  223.                 if (y2 > y3)
  224.                     y2 += ydiff;
  225.                 else
  226.                     y3 += ydiff;
  227.             }
  228.  
  229.             switch(mode) {
  230.             case IVDVideoDisplayDX9Manager::kCubicUsePS1_4Path:
  231.                 p0[i] = (-y1 << 24) + (y2 << 16) + (y3 << 8) + (-y4);
  232.                 break;
  233.             case IVDVideoDisplayDX9Manager::kCubicUseFF3Path:
  234.                 p0[i] = -y1 * 0x020202 + (-y4 << 25);
  235.                 p1[i] = y2 * 0x010101 + (y3<<24);
  236.  
  237.                 if (y2 > y3)
  238.                     y2 += y3&1;
  239.                 else
  240.                     y3 += y2&1;
  241.  
  242.                 y2>>=1;
  243.                 y3>>=1;
  244.  
  245.                 p2[i] = -y1 * 0x010101 + (-y4 << 24);
  246.                 p3[i] = y2 * 0x010101 + (y3<<24);
  247.                 break;
  248.  
  249.             case IVDVideoDisplayDX9Manager::kCubicUsePS1_1Path:
  250.                 p0[i] = -y1 * 0x010101 + (-y4 << 24);
  251.                 p1[i] = y2 * 0x010101 + (y3<<24);
  252.  
  253.                 p2[i] = -y1 * 0x010101 + (-y4 << 24);
  254.                 p3[i] = y2 * 0x010101 + (y3<<24);
  255.                 break;
  256.  
  257.             case IVDVideoDisplayDX9Manager::kCubicUseFF2Path:
  258.                 p0[i] = -y1 * 0x010101;
  259.                 p1[i] = y2 * 0x010101;
  260.  
  261.                 p2[i] = y3 * 0x010101;
  262.                 p3[i] = -y4 * 0x010101;
  263.                 break;
  264.             }
  265.         }
  266.     }
  267. };
  268.  
  269. class VDD3D9TextureGeneratorCubicFilterFF2 : public VDD3D9TextureGeneratorCubicFilter {
  270. public:
  271.     VDD3D9TextureGeneratorCubicFilterFF2() : VDD3D9TextureGeneratorCubicFilter(IVDVideoDisplayDX9Manager::kCubicUseFF2Path) {}
  272. };
  273.  
  274. class VDD3D9TextureGeneratorCubicFilterFF3 : public VDD3D9TextureGeneratorCubicFilter {
  275. public:
  276.     VDD3D9TextureGeneratorCubicFilterFF3() : VDD3D9TextureGeneratorCubicFilter(IVDVideoDisplayDX9Manager::kCubicUseFF3Path) {}
  277. };
  278.  
  279. class VDD3D9TextureGeneratorCubicFilterPS1_1 : public VDD3D9TextureGeneratorCubicFilter {
  280. public:
  281.     VDD3D9TextureGeneratorCubicFilterPS1_1() : VDD3D9TextureGeneratorCubicFilter(IVDVideoDisplayDX9Manager::kCubicUsePS1_1Path) {}
  282. };
  283.  
  284. class VDD3D9TextureGeneratorCubicFilterPS1_4 : public VDD3D9TextureGeneratorCubicFilter {
  285. public:
  286.     VDD3D9TextureGeneratorCubicFilterPS1_4() : VDD3D9TextureGeneratorCubicFilter(IVDVideoDisplayDX9Manager::kCubicUsePS1_4Path) {}
  287. };
  288.  
  289. ///////////////////////////////////////////////////////////////////////////
  290.  
  291. class VDFontRendererD3D9 : public vdrefcounted<IVDFontRendererD3D9> {
  292. public:
  293.     VDFontRendererD3D9();
  294.  
  295.     bool Init(VDD3D9Manager *d3dmgr);
  296.     void Shutdown();
  297.  
  298.     bool Begin();
  299.     void DrawTextLine(int x, int y, uint32 textColor, uint32 outlineColor, const char *s);
  300.     void End();
  301.  
  302. protected:
  303.     VDD3D9Manager *mpD3DManager;
  304.     vdrefptr<IDirect3DTexture9> mpD3DFontTexture;
  305.  
  306.     struct GlyphLayoutInfo {
  307.         int        mGlyph;
  308.         float    mX;
  309.     };
  310.  
  311.     typedef vdfastvector<GlyphLayoutInfo> GlyphLayoutInfos;
  312.     GlyphLayoutInfos mGlyphLayoutInfos;
  313.  
  314.     struct GlyphInfo {
  315.         vdrect32f    mPos;
  316.         vdrect32f    mUV;
  317.         float        mAdvance;
  318.     };
  319.  
  320.     GlyphInfo mGlyphInfo[256];
  321. };
  322.  
  323. bool VDCreateFontRendererD3D9(IVDFontRendererD3D9 **pp) {
  324.     *pp = new_nothrow VDFontRendererD3D9();
  325.     if (*pp)
  326.         (*pp)->AddRef();
  327.     return *pp != NULL;
  328. }
  329.  
  330. VDFontRendererD3D9::VDFontRendererD3D9()
  331.     : mpD3DManager(NULL)
  332. {
  333. }
  334.  
  335. bool VDFontRendererD3D9::Init(VDD3D9Manager *d3dmgr) {
  336.     mpD3DManager = d3dmgr;
  337.  
  338.     vdfastvector<uint32> tempbits(256*256, 0);
  339.     VDPixmap temppx={0};
  340.     temppx.data = tempbits.data();
  341.     temppx.w = 256;
  342.     temppx.h = 256;
  343.     temppx.format = nsVDPixmap::kPixFormat_XRGB8888;
  344.     temppx.pitch = 256*sizeof(uint32);
  345.  
  346.     VDTextLayoutMetrics metrics;
  347.     VDPixmapPathRasterizer rast;
  348.  
  349.     VDPixmapRegion outlineRegion;
  350.     VDPixmapRegion charRegion;
  351.     VDPixmapRegion charOutlineRegion;
  352.     VDPixmapCreateRoundRegion(outlineRegion, 16.0f);
  353.  
  354.     static const float kFontSize = 16.0f;
  355.  
  356.     int x = 1;
  357.     int y = 1;
  358.     int lineHeight = 0;
  359.     GlyphInfo *pgi = mGlyphInfo;
  360.     for(int c=0; c<256; ++c) {
  361.         char s[2]={(char)c, 0};
  362.  
  363.         VDPixmapGetTextExtents(NULL, kFontSize, s, metrics);
  364.  
  365.         if (metrics.mExtents.valid()) {
  366.             int x1 = VDCeilToInt(metrics.mExtents.left * 8.0f - 0.5f);
  367.             int y1 = VDCeilToInt(metrics.mExtents.top * 8.0f - 0.5f);
  368.             int x2 = VDCeilToInt(metrics.mExtents.right * 8.0f - 0.5f);
  369.             int y2 = VDCeilToInt(metrics.mExtents.bottom * 8.0f - 0.5f);
  370.             int ix1 = x1 >> 3;
  371.             int iy1 = y1 >> 3;
  372.             int ix2 = (x2 + 7) >> 3;
  373.             int iy2 = (y2 + 7) >> 3;
  374.             int w = (ix2 - ix1) + 4;
  375.             int h = (iy2 - iy1) + 4;
  376.  
  377.             if (x + w > 255) {
  378.                 x = 1;
  379.                 y += lineHeight + 1;
  380.                 lineHeight = 0;
  381.             }
  382.  
  383.             if (lineHeight < h) {
  384.                 lineHeight = h;
  385.                 VDASSERT(lineHeight+y < 255);
  386.             }
  387.  
  388.             rast.Clear();
  389.             VDPixmapConvertTextToPath(rast, NULL, kFontSize * 64.0f, (float)(-ix1*64), (float)(-iy1*64), s);
  390.             rast.ScanConvert(charRegion);
  391.             VDPixmapConvolveRegion(charOutlineRegion, charRegion, outlineRegion);
  392.  
  393.             VDPixmapFillRegionAntialiased8x(temppx, charOutlineRegion, x*8+16, y*8+16, 0x000000FF);
  394.             VDPixmapFillRegionAntialiased8x(temppx, charRegion, x*8+16, y*8+16, 0xFFFFFFFF);
  395.  
  396.             pgi->mAdvance = metrics.mAdvance;
  397.             pgi->mPos.set((float)(ix1 - 2), (float)(iy1 - 2), (float)(ix2 + 2), (float)(iy2 + 2));
  398.             pgi->mUV.set((float)x, (float)y, (float)(x+w), (float)(y+h));
  399.             pgi->mUV.scale(1.0f / 256.0f, 1.0f / 256.0f);
  400.  
  401.             x += w+1;
  402.         } else {
  403.             pgi->mAdvance = metrics.mAdvance;
  404.             pgi->mPos.clear();
  405.             pgi->mUV.clear();
  406.         }
  407.         ++pgi;
  408.     }
  409.  
  410.     // create texture
  411.     IDirect3DDevice9 *dev = mpD3DManager->GetDevice();
  412.     HRESULT hr = dev->CreateTexture(256, 256, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ~mpD3DFontTexture, NULL);
  413.     if (FAILED(hr)) {
  414.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to create font cache texture.\n");
  415.         Shutdown();
  416.         return false;
  417.     }
  418.  
  419.     // copy into texture
  420.     D3DLOCKED_RECT lr;
  421.     hr = mpD3DFontTexture->LockRect(0, &lr, NULL, 0);
  422.     VDASSERT(SUCCEEDED(hr));
  423.     if (FAILED(hr)) {
  424.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to load font cache texture.\n");
  425.         Shutdown();
  426.         return false;
  427.     }
  428.     
  429.     uint32 *dst = (uint32 *)lr.pBits;
  430.     const uint32 *src = tempbits.data();
  431.     for(int y=0; y<256; ++y) {
  432.         for(int x=0; x<256; ++x) {
  433.             uint32 c = src[x];
  434.             dst[x] = ((c >> 8) & 0xff) * 0x010101 + (c << 24);
  435.         }
  436.  
  437.         src += 256;
  438.         vdptrstep(dst, lr.Pitch);
  439.     }
  440.  
  441.     VDVERIFY(SUCCEEDED(mpD3DFontTexture->UnlockRect(0)));
  442.     return true;
  443. }
  444.  
  445. void VDFontRendererD3D9::Shutdown() {
  446.     mpD3DFontTexture = NULL;
  447.     mpD3DManager = NULL;
  448. }
  449.  
  450. bool VDFontRendererD3D9::Begin() {
  451.     if (!mpD3DManager)
  452.         return false;
  453.  
  454.     IDirect3DDevice9 *dev = mpD3DManager->GetDevice();
  455.  
  456.     D3DVIEWPORT9 vp;
  457.     HRESULT hr = dev->GetViewport(&vp);
  458.     if (FAILED(hr))
  459.         return false;
  460.  
  461.     const D3DMATRIX ident={
  462.         1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
  463.     };
  464.  
  465.     dev->SetTransform(D3DTS_WORLD, &ident);
  466.     dev->SetTransform(D3DTS_VIEW, &ident);
  467.  
  468.     const D3DMATRIX proj = {
  469.         2.0f / (float)vp.Width, 0.0f, 0.0f, 0.0f,
  470.         0.0f, -2.0f / (float)vp.Height, 0.0f, 0.0f,
  471.         0.0f, 0.0f, 0.0f, 0.0f,
  472.         -1.0f - 1.0f / (float)vp.Width, 1.0f + 1.0f / (float)vp.Height, 0.0f, 1.0f
  473.     };
  474.  
  475.     dev->SetTransform(D3DTS_PROJECTION, &proj);
  476.  
  477.     dev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
  478.     dev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
  479.     dev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  480.     dev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  481.     dev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
  482.  
  483.     dev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  484.     dev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  485.  
  486.     // Rite of passage for any 3D programmer:
  487.     // "Why the *&#$ didn't it draw anything!?"
  488.     dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  489.     dev->SetRenderState(D3DRS_LIGHTING, FALSE);
  490.     dev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
  491.     dev->SetRenderState(D3DRS_ZENABLE, FALSE);
  492.     dev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
  493.     dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  494.     dev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
  495.     dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
  496.  
  497.     dev->SetVertexShader(NULL);
  498.     dev->SetVertexDeclaration(mpD3DManager->GetVertexDeclaration());
  499.     dev->SetPixelShader(NULL);
  500.     dev->SetStreamSource(0, mpD3DManager->GetVertexBuffer(), 0, sizeof(nsVDD3D9::Vertex));
  501.     dev->SetIndices(mpD3DManager->GetIndexBuffer());
  502.     dev->SetTexture(0, mpD3DFontTexture);
  503.  
  504.     return mpD3DManager->BeginScene();
  505. }
  506.  
  507. void VDFontRendererD3D9::DrawTextLine(int x, int y, uint32 textColor, uint32 outlineColor, const char *s) {
  508.     const uint32 kMaxQuads = nsVDD3D9::kVertexBufferSize / 4;
  509.     size_t len = strlen(s);
  510.  
  511.     mGlyphLayoutInfos.clear();
  512.     mGlyphLayoutInfos.reserve(len);
  513.  
  514.     float xpos = (float)x;
  515.     for(size_t i=0; i<len; ++i) {
  516.         char c = *s++;
  517.         const GlyphInfo& gi = mGlyphInfo[(int)c & 0xff];
  518.  
  519.         if (!gi.mPos.empty()) {
  520.             mGlyphLayoutInfos.push_back();
  521.             GlyphLayoutInfo& gli = mGlyphLayoutInfos.back();
  522.             gli.mGlyph = (int)c & 0xff;
  523.             gli.mX = xpos;
  524.         }
  525.  
  526.         xpos += gi.mAdvance;
  527.     }
  528.  
  529.     float ypos = (float)y;
  530.  
  531.     IDirect3DDevice9 *dev = mpD3DManager->GetDevice();
  532.     for(int i=0; i<2; ++i) {
  533.         uint32 vertexColor;
  534.  
  535.         switch(i) {
  536.         case 0:
  537.             vertexColor = outlineColor;
  538.             dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  539.             dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
  540.             dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
  541.             dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  542.             dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  543.             dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  544.             break;
  545.         case 1:
  546.             vertexColor = textColor;
  547.             dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  548.             dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
  549.             dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
  550.             dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  551.             dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  552.             dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
  553.             break;
  554.         }
  555.  
  556.         uint32 glyphCount = (uint32)mGlyphLayoutInfos.size();
  557.         uint32 glyphStart = 0;
  558.         const GlyphLayoutInfo *pgli = mGlyphLayoutInfos.data();
  559.         while(glyphStart < glyphCount) {
  560.             uint32 glyphsToRender = glyphCount - glyphStart;
  561.             if (glyphsToRender > kMaxQuads)
  562.                 glyphsToRender = kMaxQuads;
  563.  
  564.             nsVDD3D9::Vertex *vx = mpD3DManager->LockVertices(glyphsToRender * 4);
  565.             if (!vx)
  566.                 break;
  567.  
  568.             for(uint32 i=0; i<glyphsToRender; ++i) {
  569.                 const GlyphInfo& gi = mGlyphInfo[pgli->mGlyph];
  570.  
  571.                 new(vx  ) nsVDD3D9::Vertex(pgli->mX + gi.mPos.left,  ypos + gi.mPos.top,    vertexColor, gi.mUV.left,  gi.mUV.top   );
  572.                 new(vx+1) nsVDD3D9::Vertex(pgli->mX + gi.mPos.left,  ypos + gi.mPos.bottom, vertexColor, gi.mUV.left,  gi.mUV.bottom);
  573.                 new(vx+2) nsVDD3D9::Vertex(pgli->mX + gi.mPos.right, ypos + gi.mPos.bottom, vertexColor, gi.mUV.right, gi.mUV.bottom);
  574.                 new(vx+3) nsVDD3D9::Vertex(pgli->mX + gi.mPos.right, ypos + gi.mPos.top,    vertexColor, gi.mUV.right, gi.mUV.top   );
  575.                 vx += 4;
  576.                 ++pgli;
  577.             }
  578.  
  579.             mpD3DManager->UnlockVertices();
  580.  
  581.             uint16 *idx = mpD3DManager->LockIndices(glyphsToRender * 6);
  582.             if (!idx)
  583.                 break;
  584.  
  585.             uint32 vidx = 0;
  586.             for(uint32 i=0; i<glyphsToRender; ++i) {
  587.                 idx[0] = vidx;
  588.                 idx[1] = vidx+1;
  589.                 idx[2] = vidx+2;
  590.                 idx[3] = vidx;
  591.                 idx[4] = vidx+2;
  592.                 idx[5] = vidx+3;
  593.                 vidx += 4;
  594.                 idx += 6;
  595.             }
  596.  
  597.             mpD3DManager->UnlockIndices();
  598.  
  599.             mpD3DManager->DrawElements(D3DPT_TRIANGLELIST, 0, 4*glyphsToRender, 0, 2*glyphsToRender);
  600.  
  601.             glyphStart += glyphsToRender;
  602.         }
  603.     }
  604. }
  605.  
  606. void VDFontRendererD3D9::End() {
  607.     IDirect3DDevice9 *dev = mpD3DManager->GetDevice();
  608.  
  609.     dev->SetTexture(0, NULL);
  610. }
  611.  
  612. ///////////////////////////////////////////////////////////////////////////
  613.  
  614. #ifdef _MSC_VER
  615.     #pragma warning(push)
  616.     #pragma warning(disable: 4584)        // warning C4584: 'VDVideoDisplayDX9Manager' : base-class 'vdlist_node' is already a base-class of 'VDD3D9Client'
  617. #endif
  618.  
  619. struct VDVideoDisplayDX9ManagerNode : public vdlist_node {};
  620.  
  621. class VDVideoDisplayDX9Manager : public IVDVideoDisplayDX9Manager, public VDD3D9Client, public VDVideoDisplayDX9ManagerNode {
  622. public:
  623.     struct EffectContext {
  624.         IDirect3DTexture9 *mpSourceTexture1;
  625.         IDirect3DTexture9 *mpSourceTexture2;
  626.         IDirect3DTexture9 *mpSourceTexture3;
  627.         IDirect3DTexture9 *mpPaletteTexture;
  628.         IDirect3DTexture9 *mpInterpFilterH;
  629.         IDirect3DTexture9 *mpInterpFilterV;
  630.         uint32 mSourceW;
  631.         uint32 mSourceH;
  632.         uint32 mSourceTexW;
  633.         uint32 mSourceTexH;
  634.         uint32 mInterpHTexW;
  635.         uint32 mInterpHTexH;
  636.         uint32 mInterpVTexW;
  637.         uint32 mInterpVTexH;
  638.         float mDefaultUVScaleCorrectionX;
  639.         float mDefaultUVScaleCorrectionY;
  640.         float mFieldOffset;
  641.         bool mbHighPrecision;
  642.     };
  643.  
  644.     VDVideoDisplayDX9Manager(VDThreadID tid);
  645.     ~VDVideoDisplayDX9Manager();
  646.  
  647.     int AddRef();
  648.     int Release();
  649.  
  650.     bool Init();
  651.     void Shutdown();
  652.  
  653.     CubicMode InitBicubic();
  654.     void ShutdownBicubic();
  655.  
  656.     bool InitBicubicTempSurfaces(bool highPrecision);
  657.     void ShutdownBicubicTempSurfaces(bool highPrecision);
  658.  
  659.     bool Is16FEnabled() const { return mbIs16FEnabled; }
  660.  
  661.     VDThreadID GetThreadId() const { return mThreadId; }
  662.  
  663.     IVDD3D9Texture    *GetTempRTT(int i) const { return mpRTTs[i]; }
  664.     IVDD3D9Texture    *GetFilterTexture() const { return mpFilterTexture; }
  665.     IVDD3D9Texture    *GetHEvenOddTexture() const { return mpHEvenOddTexture; }
  666.  
  667.     void        DetermineBestTextureFormat(int srcFormat, int& dstFormat, D3DFORMAT& dstD3DFormat);
  668.  
  669.     bool ValidateBicubicShader(CubicMode mode);
  670.  
  671.     bool RunEffect(const EffectContext& ctx, const RECT& rClient, const TechniqueInfo& technique, IDirect3DSurface9 *pRTOverride);
  672.  
  673. public:
  674.     void OnPreDeviceReset() {}
  675.     void OnPostDeviceReset() {}
  676.  
  677. protected:
  678.     bool InitEffect();
  679.     void ShutdownEffect();
  680.  
  681.     VDD3D9Manager        *mpManager;
  682.     vdrefptr<IVDD3D9Texture>    mpFilterTexture;
  683.     vdrefptr<IVDD3D9Texture>    mpHEvenOddTexture;
  684.     vdrefptr<IVDD3D9Texture>    mpDitherTexture;
  685.     vdrefptr<IVDD3D9Texture>    mpRTTs[3];
  686.  
  687.     vdfastvector<IDirect3DVertexShader9 *>    mVertexShaders;
  688.     vdfastvector<IDirect3DPixelShader9 *>    mPixelShaders;
  689.  
  690.     CubicMode            mCubicMode;
  691.     int                    mCubicRefCount;
  692.     int                    mCubicTempSurfacesRefCount[2];
  693.     bool                mbIs16FEnabled;
  694.  
  695.     const VDThreadID    mThreadId;
  696.     int                    mRefCount;
  697. };
  698.  
  699. #ifdef _MSC_VER
  700.     #pragma warning(pop)
  701. #endif
  702.  
  703. ///////////////////////////////////////////////////////////////////////////
  704.  
  705. static VDCriticalSection g_csVDDisplayDX9Managers;
  706. static vdlist<VDVideoDisplayDX9ManagerNode> g_VDDisplayDX9Managers;
  707.  
  708. bool VDInitDisplayDX9(VDVideoDisplayDX9Manager **ppManager) {
  709.     VDVideoDisplayDX9Manager *pMgr = NULL;
  710.     bool firstClient = false;
  711.  
  712.     vdsynchronized(g_csVDDisplayDX9Managers) {
  713.         vdlist<VDVideoDisplayDX9ManagerNode>::iterator it(g_VDDisplayDX9Managers.begin()), itEnd(g_VDDisplayDX9Managers.end());
  714.  
  715.         VDThreadID tid = VDGetCurrentThreadID();
  716.  
  717.         for(; it != itEnd; ++it) {
  718.             VDVideoDisplayDX9Manager *mgr = static_cast<VDVideoDisplayDX9Manager *>(*it);
  719.  
  720.             if (mgr->GetThreadId() == tid) {
  721.                 pMgr = mgr;
  722.                 break;
  723.             }
  724.         }
  725.  
  726.         if (!pMgr) {
  727.             pMgr = new_nothrow VDVideoDisplayDX9Manager(tid);
  728.             if (!pMgr)
  729.                 return NULL;
  730.  
  731.             g_VDDisplayDX9Managers.push_back(pMgr);
  732.             firstClient = true;
  733.         }
  734.  
  735.         pMgr->AddRef();
  736.     }
  737.  
  738.     if (firstClient) {
  739.         if (!pMgr->Init()) {
  740.             vdsynchronized(g_csVDDisplayDX9Managers) {
  741.                 g_VDDisplayDX9Managers.erase(pMgr);
  742.             }
  743.             pMgr->Release();
  744.             return NULL;
  745.         }
  746.     }
  747.  
  748.     *ppManager = pMgr;
  749.     return true;
  750. }
  751.  
  752. VDVideoDisplayDX9Manager::VDVideoDisplayDX9Manager(VDThreadID tid)
  753.     : mpManager(NULL)
  754.     , mCubicRefCount(0)
  755.     , mThreadId(tid)
  756.     , mRefCount(0)
  757. {
  758.     mCubicTempSurfacesRefCount[0] = 0;
  759.     mCubicTempSurfacesRefCount[1] = 0;
  760. }
  761.  
  762. VDVideoDisplayDX9Manager::~VDVideoDisplayDX9Manager() {
  763.     VDASSERT(!mRefCount);
  764.     VDASSERT(!mCubicRefCount);
  765.     VDASSERT(!mCubicTempSurfacesRefCount[0]);
  766.     VDASSERT(!mCubicTempSurfacesRefCount[1]);
  767.  
  768.     vdsynchronized(g_csVDDisplayDX9Managers) {
  769.         g_VDDisplayDX9Managers.erase(this);
  770.     }
  771. }
  772.  
  773. int VDVideoDisplayDX9Manager::AddRef() {
  774.     return ++mRefCount;
  775. }
  776.  
  777. int VDVideoDisplayDX9Manager::Release() {
  778.     int rc = --mRefCount;
  779.     if (!rc) {
  780.         Shutdown();
  781.         delete this;
  782.     }
  783.     return rc;
  784. }
  785.  
  786. bool VDVideoDisplayDX9Manager::Init() {
  787.     VDASSERT(!mpManager);
  788.     mpManager = VDInitDirect3D9(this);
  789.     if (!mpManager)
  790.         return false;
  791.  
  792.     // Check for 16F capability.
  793.     //
  794.     // We need:
  795.     //    * Vertex and pixel shader 2.0.
  796.     //    * 16F texture support.
  797.     //    * 16F blending.
  798.  
  799.     const D3DCAPS9& caps = mpManager->GetCaps();
  800.  
  801.     mbIs16FEnabled = false;
  802.     if (caps.VertexShaderVersion >= D3DVS_VERSION(2, 0) &&
  803.         caps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
  804.     {
  805.         if (mpManager->CheckResourceFormat(0, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F) &&
  806.             mpManager->CheckResourceFormat(D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F))
  807.         {
  808.             mbIs16FEnabled = true;
  809.         }
  810.     }
  811.  
  812.     if (!mpManager->CreateSharedTexture<VDD3D9TextureGeneratorDither>("dither", ~mpDitherTexture)) {
  813.         Shutdown();
  814.         return false;
  815.     }
  816.  
  817.     if (!mpManager->CreateSharedTexture<VDD3D9TextureGeneratorHEvenOdd>("hevenodd", ~mpHEvenOddTexture)) {
  818.         Shutdown();
  819.         return false;
  820.     }
  821.  
  822.     if (!InitEffect()) {
  823.         Shutdown();
  824.         return false;
  825.     }
  826.  
  827.     return true;
  828. }
  829.  
  830. void VDVideoDisplayDX9Manager::Shutdown() {
  831.     VDASSERT(!mCubicRefCount);
  832.     VDASSERT(!mCubicTempSurfacesRefCount[0]);
  833.     VDASSERT(!mCubicTempSurfacesRefCount[1]);
  834.  
  835.     mpDitherTexture = NULL;
  836.     mpHEvenOddTexture = NULL;
  837.  
  838.     ShutdownEffect();
  839.  
  840.     if (mpManager) {
  841.         VDDeinitDirect3D9(mpManager, this);
  842.         mpManager = NULL;
  843.     }
  844. }
  845.  
  846. bool VDVideoDisplayDX9Manager::InitEffect() {
  847.     IDirect3DDevice9 *pD3DDevice = mpManager->GetDevice();
  848.     const D3DCAPS9& caps = mpManager->GetCaps();
  849.  
  850.     // initialize vertex shaders
  851.     if (g_effect.mVertexShaderCount && mVertexShaders.empty()) {
  852.         mVertexShaders.resize(g_effect.mVertexShaderCount, NULL);
  853.         for(uint32 i=0; i<g_effect.mVertexShaderCount; ++i) {
  854.             const uint32 *pVertexShaderData = g_shaderData + g_effect.mVertexShaderOffsets[i];
  855.  
  856.             if ((pVertexShaderData[0] & 0xffff) > (caps.VertexShaderVersion & 0xffff))
  857.                 continue;
  858.  
  859.             HRESULT hr = pD3DDevice->CreateVertexShader((const DWORD *)pVertexShaderData, &mVertexShaders[i]);
  860.             if (FAILED(hr)) {
  861.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Unable to create vertex shader #%d.\n", i+1);
  862.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Vertex shader version is: %x.\n", pVertexShaderData[0]);
  863.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Supported vertex shader version is: %x.\n", caps.VertexShaderVersion);
  864.                 return false;
  865.             }
  866.         }
  867.     }
  868.  
  869.     // initialize pixel shaders
  870.     if (g_effect.mPixelShaderCount && mPixelShaders.empty()) {
  871.         mPixelShaders.resize(g_effect.mPixelShaderCount, NULL);
  872.         for(uint32 i=0; i<g_effect.mPixelShaderCount; ++i) {
  873.             const uint32 *pPixelShaderData = g_shaderData + g_effect.mPixelShaderOffsets[i];
  874.  
  875.             if ((pPixelShaderData[0] & 0xffff) > (caps.PixelShaderVersion & 0xffff))
  876.                 continue;
  877.  
  878.             HRESULT hr = pD3DDevice->CreatePixelShader((const DWORD *)pPixelShaderData, &mPixelShaders[i]);
  879.             if (FAILED(hr)) {
  880.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Unable to create pixel shader #%d.\n", i+1);
  881.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Pixel shader version is: %x.\n", pPixelShaderData[0]);
  882.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Supported pixel shader version is: %x.\n", caps.PixelShaderVersion);
  883.                 return false;
  884.             }
  885.         }
  886.     }
  887.  
  888.     return true;
  889. }
  890.  
  891. void VDVideoDisplayDX9Manager::ShutdownEffect() {
  892.     while(!mPixelShaders.empty()) {
  893.         IDirect3DPixelShader9 *ps = mPixelShaders.back();
  894.         mPixelShaders.pop_back();
  895.  
  896.         if (ps)
  897.             ps->Release();
  898.     }
  899.  
  900.     while(!mVertexShaders.empty()) {
  901.         IDirect3DVertexShader9 *vs = mVertexShaders.back();
  902.         mVertexShaders.pop_back();
  903.  
  904.         if (vs)
  905.             vs->Release();
  906.     }
  907. }
  908.  
  909. VDVideoDisplayDX9Manager::CubicMode VDVideoDisplayDX9Manager::InitBicubic() {
  910.     VDASSERT(mRefCount > 0);
  911.     VDASSERT(mCubicRefCount >= 0);
  912.  
  913.     if (++mCubicRefCount > 1)
  914.         return mCubicMode;
  915.  
  916.     mCubicMode = (CubicMode)kMaxCubicMode;
  917.     while(mCubicMode > kCubicNotPossible) {
  918.         if (ValidateBicubicShader(mCubicMode))
  919.             break;
  920.         mCubicMode = (CubicMode)(mCubicMode - 1);
  921.     }
  922.  
  923.     if (mCubicMode == kCubicNotPossible) {
  924.         ShutdownBicubic();
  925.         return mCubicMode;
  926.     }
  927.  
  928.     bool success = false;
  929.  
  930.     switch(mCubicMode) {
  931.         case kCubicUseFF2Path:
  932.             success = mpManager->CreateSharedTexture<VDD3D9TextureGeneratorCubicFilterFF2>("cubicfilter", ~mpFilterTexture);
  933.             break;
  934.         case kCubicUseFF3Path:
  935.             success = mpManager->CreateSharedTexture<VDD3D9TextureGeneratorCubicFilterFF3>("cubicfilter", ~mpFilterTexture);
  936.             break;
  937.         case kCubicUsePS1_1Path:
  938.         case kCubicUsePS1_4Path:
  939.             success = true;
  940.             break;
  941.     }
  942.  
  943.     if (!success) {
  944.         ShutdownBicubic();
  945.         return kCubicNotPossible;
  946.     }
  947.  
  948.     return mCubicMode;
  949. }
  950.  
  951. void VDVideoDisplayDX9Manager::ShutdownBicubic() {
  952.     VDASSERT(mCubicRefCount > 0);
  953.     if (--mCubicRefCount)
  954.         return;
  955.  
  956.     mpFilterTexture = NULL;
  957. }
  958.  
  959. bool VDVideoDisplayDX9Manager::InitBicubicTempSurfaces(bool highPrecision) {
  960.     VDASSERT(mRefCount > 0);
  961.     VDASSERT(mCubicTempSurfacesRefCount[highPrecision] >= 0);
  962.  
  963.     if (++mCubicTempSurfacesRefCount[highPrecision] > 1)
  964.         return true;
  965.  
  966.     if (highPrecision) {
  967.         if (!mbIs16FEnabled) {
  968.             ShutdownBicubicTempSurfaces(highPrecision);
  969.             return false;
  970.         }
  971.  
  972.         if (!mpManager->CreateSharedTexture("rtt3", VDCreateD3D9TextureGeneratorFullSizeRTT16F, ~mpRTTs[2])) {
  973.             ShutdownBicubicTempSurfaces(highPrecision);
  974.             return false;
  975.         }
  976.     } else {
  977.         // create horizontal resampling texture
  978.         if (!mpManager->CreateSharedTexture("rtt1", VDCreateD3D9TextureGeneratorFullSizeRTT, ~mpRTTs[0])) {
  979.             ShutdownBicubicTempSurfaces(highPrecision);
  980.             return false;
  981.         }
  982.  
  983.         // create vertical resampling texture
  984.         if (mCubicMode < kCubicUsePS1_1Path) {
  985.             if (!mpManager->CreateSharedTexture("rtt2", VDCreateD3D9TextureGeneratorFullSizeRTT, ~mpRTTs[1])) {
  986.                 ShutdownBicubicTempSurfaces(highPrecision);
  987.                 return false;
  988.             }
  989.         }
  990.     }
  991.  
  992.     return true;
  993. }
  994.  
  995. void VDVideoDisplayDX9Manager::ShutdownBicubicTempSurfaces(bool highPrecision) {
  996.     VDASSERT(mCubicTempSurfacesRefCount[highPrecision] > 0);
  997.     if (--mCubicTempSurfacesRefCount[highPrecision])
  998.         return;
  999.  
  1000.     if (highPrecision) {
  1001.         mpRTTs[2] = NULL;
  1002.     } else {
  1003.         mpRTTs[1] = NULL;
  1004.         mpRTTs[0] = NULL;
  1005.     }
  1006. }
  1007.  
  1008. namespace {
  1009.     D3DFORMAT GetD3DTextureFormatForPixmapFormat(int format) {
  1010.         using namespace nsVDPixmap;
  1011.  
  1012.         switch(format) {
  1013.             case nsVDPixmap::kPixFormat_XRGB1555:
  1014.                 return D3DFMT_X1R5G5B5;
  1015.  
  1016.             case nsVDPixmap::kPixFormat_RGB565:
  1017.                 return D3DFMT_R5G6B5;
  1018.  
  1019.             case nsVDPixmap::kPixFormat_RGB888:
  1020.                 return D3DFMT_R8G8B8;                // No real hardware supports this format, in practice.
  1021.  
  1022.             case nsVDPixmap::kPixFormat_XRGB8888:
  1023.                 return D3DFMT_X8R8G8B8;
  1024.  
  1025.             case nsVDPixmap::kPixFormat_YUV422_UYVY:
  1026.                 return D3DFMT_UYVY;
  1027.  
  1028.             case nsVDPixmap::kPixFormat_YUV422_YUYV:
  1029.                 return D3DFMT_YUY2;
  1030.  
  1031.             default:
  1032.                 return D3DFMT_UNKNOWN;
  1033.         }
  1034.     }
  1035. }
  1036.  
  1037. void VDVideoDisplayDX9Manager::DetermineBestTextureFormat(int srcFormat, int& dstFormat, D3DFORMAT& dstD3DFormat) {
  1038.     using namespace nsVDPixmap;
  1039.  
  1040.     // Try direct format first. If that doesn't work, try a fallback (in practice, we
  1041.     // only have one).
  1042.  
  1043.     dstFormat = srcFormat;
  1044.     for(int i=0; i<2; ++i) {
  1045.         dstD3DFormat = GetD3DTextureFormatForPixmapFormat(dstFormat);
  1046.         if (dstD3DFormat && mpManager->IsTextureFormatAvailable(dstD3DFormat)) {
  1047.             dstFormat = srcFormat;
  1048.             return;
  1049.         }
  1050.  
  1051.         // fallback
  1052.         switch(dstFormat) {
  1053.             case kPixFormat_XRGB1555:
  1054.                 dstFormat = kPixFormat_RGB565;
  1055.                 break;
  1056.  
  1057.             case kPixFormat_RGB565:
  1058.                 dstFormat = kPixFormat_XRGB1555;
  1059.                 break;
  1060.  
  1061.             case kPixFormat_YUV422_UYVY:
  1062.                 dstFormat =    kPixFormat_YUV422_YUYV;
  1063.                 break;
  1064.  
  1065.             case kPixFormat_YUV422_YUYV:
  1066.                 dstFormat = kPixFormat_YUV422_UYVY;
  1067.                 break;
  1068.  
  1069.             default:
  1070.                 goto fail;
  1071.         }
  1072.     }
  1073. fail:
  1074.  
  1075.     // Just use X8R8G8B8. We always know this works (we reject the device if it doesn't).
  1076.     dstFormat = kPixFormat_XRGB8888;
  1077.     dstD3DFormat = D3DFMT_X8R8G8B8;
  1078. }
  1079.  
  1080. bool VDVideoDisplayDX9Manager::ValidateBicubicShader(CubicMode mode) {
  1081.     const TechniqueInfo *pTechInfo;
  1082.     switch(mode) {
  1083.         case kCubicUsePS1_4Path:
  1084.             pTechInfo = &g_technique_bicubic1_4;
  1085.             break;                                                                                                                        
  1086.         case kCubicUsePS1_1Path:                                                                                
  1087.             pTechInfo = &g_technique_bicubic1_1;
  1088.             break;                                                                                                                        
  1089.         case kCubicUseFF3Path:                                                                                
  1090.             pTechInfo = &g_technique_bicubicFF3;
  1091.             break;                                                                                                                        
  1092.         case kCubicUseFF2Path:                                                                                
  1093.             pTechInfo = &g_technique_bicubicFF2;
  1094.             break;
  1095.         default:
  1096.             return false;
  1097.     }
  1098.  
  1099.     // Validate caps bits.
  1100.     const D3DCAPS9& caps = mpManager->GetCaps();
  1101.     if ((caps.PrimitiveMiscCaps & pTechInfo->mPrimitiveMiscCaps) != pTechInfo->mPrimitiveMiscCaps)
  1102.         return false;
  1103.     if (caps.MaxSimultaneousTextures < pTechInfo->mMaxSimultaneousTextures)
  1104.         return false;
  1105.     if (caps.MaxTextureBlendStages < pTechInfo->mMaxSimultaneousTextures)
  1106.         return false;
  1107.     if ((caps.SrcBlendCaps & pTechInfo->mSrcBlendCaps) != pTechInfo->mSrcBlendCaps)
  1108.         return false;
  1109.     if ((caps.DestBlendCaps & pTechInfo->mDestBlendCaps) != pTechInfo->mDestBlendCaps)
  1110.         return false;
  1111.     if ((caps.TextureOpCaps & pTechInfo->mTextureOpCaps) != pTechInfo->mTextureOpCaps)
  1112.         return false;
  1113.     if (pTechInfo->mPSVersionRequired) {
  1114.         if (caps.PixelShaderVersion < pTechInfo->mPSVersionRequired)
  1115.             return false;
  1116.         if (caps.PixelShader1xMaxValue < pTechInfo->mPixelShader1xMaxValue * 0.95f)
  1117.             return false;
  1118.     }
  1119.  
  1120.     // Validate shaders.
  1121.     IDirect3DDevice9 *pDevice = mpManager->GetDevice();
  1122.     HRESULT hr = pDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2);
  1123.     if (FAILED(hr))
  1124.         return false;
  1125.  
  1126.     const PassInfo *pPasses = pTechInfo->mpPasses;
  1127.     for(uint32 stage = 0; stage < pTechInfo->mPassCount; ++stage) {
  1128.         const PassInfo& pi = *pPasses++;
  1129.  
  1130.         const uint32 stateStart = pi.mStateStart, stateEnd = pi.mStateEnd;
  1131.         for(uint32 stateIdx = stateStart; stateIdx != stateEnd; ++stateIdx) {
  1132.             uint32 token = g_states[stateIdx];
  1133.             uint32 tokenIndex = (token >> 12) & 0xFFF;
  1134.             uint32 tokenValue = token & 0xFFF;
  1135.  
  1136.             if (tokenValue == 0xFFF)
  1137.                 tokenValue = g_states[++stateIdx];
  1138.  
  1139.             hr = S_OK;
  1140.             switch(token >> 28) {
  1141.                 case 0:        // render state
  1142.                     hr = pDevice->SetRenderState((D3DRENDERSTATETYPE)tokenIndex, tokenValue);
  1143.                     break;
  1144.                 case 1:        // texture stage state
  1145.                     hr = pDevice->SetTextureStageState((token >> 24)&15, (D3DTEXTURESTAGESTATETYPE)tokenIndex, tokenValue);
  1146.                     break;
  1147.                 case 2:        // sampler state
  1148.                     hr = pDevice->SetSamplerState((token >> 24)&15, (D3DSAMPLERSTATETYPE)tokenIndex, tokenValue);
  1149.                     break;
  1150.                 case 3:        // texture
  1151.                 case 8:        // vertex bool constant
  1152.                 case 9:        // vertex int constant
  1153.                 case 10:    // vertex float constant
  1154.                 case 12:    // pixel bool constant
  1155.                 case 13:    // pixel int constant
  1156.                 case 14:    // pixel float constant
  1157.                     // ignore.
  1158.                     break;
  1159.             }
  1160.  
  1161.             if (FAILED(hr)) {
  1162.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to set state! hr=%08x\n", hr);
  1163.                 return false;
  1164.             }
  1165.         }
  1166.  
  1167.         HRESULT hr = pDevice->SetVertexShader(pi.mVertexShaderIndex >= 0 ? mVertexShaders[pi.mVertexShaderIndex] : NULL);
  1168.         if (FAILED(hr)) {
  1169.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Couldn't set vertex shader! hr=%08x\n", hr);
  1170.             return false;
  1171.         }
  1172.  
  1173.         hr = pDevice->SetPixelShader(pi.mPixelShaderIndex >= 0 ? mPixelShaders[pi.mPixelShaderIndex] : NULL);
  1174.         if (FAILED(hr)) {
  1175.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Couldn't set pixel shader! hr=%08x\n", hr);
  1176.             return false;
  1177.         }
  1178.  
  1179.         DWORD passes;
  1180.         hr = pDevice->ValidateDevice(&passes);
  1181.  
  1182.         if (FAILED(hr))
  1183.             return false;
  1184.     }
  1185.  
  1186.     return true;
  1187. }
  1188.  
  1189. bool VDVideoDisplayDX9Manager::RunEffect(const EffectContext& ctx, const RECT& rClient, const TechniqueInfo& technique, IDirect3DSurface9 *pRTOverride) {
  1190.     const int firstRTTIndex = ctx.mbHighPrecision ? 2 : 0;
  1191.  
  1192.     IDirect3DTexture9 *const textures[12]={
  1193.         NULL,
  1194.         ctx.mpSourceTexture1,
  1195.         ctx.mpSourceTexture2,
  1196.         ctx.mpSourceTexture3,
  1197.         ctx.mpPaletteTexture,
  1198.         mpRTTs[firstRTTIndex] ? mpRTTs[firstRTTIndex]->GetD3DTexture() : NULL,
  1199.         mpRTTs[1] ? mpRTTs[1]->GetD3DTexture() : NULL,
  1200.         mpFilterTexture ? mpFilterTexture->GetD3DTexture() : NULL,
  1201.         mpHEvenOddTexture ? mpHEvenOddTexture->GetD3DTexture() : NULL,
  1202.         mpDitherTexture ? mpDitherTexture->GetD3DTexture() : NULL,
  1203.         ctx.mpInterpFilterH,
  1204.         ctx.mpInterpFilterV
  1205.     };
  1206.  
  1207.     const D3DPRESENT_PARAMETERS& pparms = mpManager->GetPresentParms();
  1208.     int clippedWidth = std::min<int>(rClient.right, pparms.BackBufferWidth);
  1209.     int clippedHeight = std::min<int>(rClient.bottom, pparms.BackBufferHeight);
  1210.  
  1211.     if (clippedWidth <= 0 || clippedHeight <= 0)
  1212.         return true;
  1213.  
  1214.     struct StdParamData {
  1215.         float vpsize[4];            // (viewport size)            vpwidth, vpheight, 1/vpheight, 1/vpwidth
  1216.         float cvpsize[4];            // (clipped viewport size)    cvpwidth, cvpheight, 1/cvpheight, 1/cvpwidth
  1217.         float texsize[4];            // (texture size)            texwidth, texheight, 1/texheight, 1/texwidth
  1218.         float tex2size[4];            // (texture2 size)            tex2width, tex2height, 1/tex2height, 1/tex2width
  1219.         float srcsize[4];            // (source size)            srcwidth, srcheight, 1/srcheight, 1/srcwidth
  1220.         float tempsize[4];            // (temp rtt size)            tempwidth, tempheight, 1/tempheight, 1/tempwidth
  1221.         float temp2size[4];            // (temp2 rtt size)            tempwidth, tempheight, 1/tempheight, 1/tempwidth
  1222.         float vpcorrect[4];            // (viewport correction)    2/vpwidth, 2/vpheight, -1/vpheight, 1/vpwidth
  1223.         float vpcorrect2[4];        // (viewport correction)    2/vpwidth, -2/vpheight, 1+1/vpheight, -1-1/vpwidth
  1224.         float tvpcorrect[4];        // (temp vp correction)        2/tvpwidth, 2/tvpheight, -1/tvpheight, 1/tvpwidth
  1225.         float tvpcorrect2[4];        // (temp vp correction)        2/tvpwidth, -2/tvpheight, 1+1/tvpheight, -1-1/tvpwidth
  1226.         float t2vpcorrect[4];        // (temp2 vp correction)    2/tvpwidth, 2/tvpheight, -1/tvpheight, 1/tvpwidth
  1227.         float t2vpcorrect2[4];        // (temp2 vp correction)    2/tvpwidth, -2/tvpheight, 1+1/tvpheight, -1-1/tvpwidth
  1228.         float time[4];                // (time)
  1229.         float interphtexsize[4];    // (cubic htex interp info)
  1230.         float interpvtexsize[4];    // (cubic vtex interp info)
  1231.         float fieldinfo[4];            // (field information)        fieldoffset, -fieldoffset/4, und, und
  1232.     };
  1233.  
  1234.     static const struct StdParam {
  1235.         int offset;
  1236.     } kStdParamInfo[]={
  1237.         offsetof(StdParamData, vpsize),
  1238.         offsetof(StdParamData, cvpsize),
  1239.         offsetof(StdParamData, texsize),
  1240.         offsetof(StdParamData, tex2size),
  1241.         offsetof(StdParamData, srcsize),
  1242.         offsetof(StdParamData, tempsize),
  1243.         offsetof(StdParamData, temp2size),
  1244.         offsetof(StdParamData, vpcorrect),
  1245.         offsetof(StdParamData, vpcorrect2),
  1246.         offsetof(StdParamData, tvpcorrect),
  1247.         offsetof(StdParamData, tvpcorrect2),
  1248.         offsetof(StdParamData, t2vpcorrect),
  1249.         offsetof(StdParamData, t2vpcorrect2),
  1250.         offsetof(StdParamData, time),
  1251.         offsetof(StdParamData, interphtexsize),
  1252.         offsetof(StdParamData, interpvtexsize),
  1253.         offsetof(StdParamData, fieldinfo),
  1254.     };
  1255.  
  1256.     StdParamData data;
  1257.  
  1258.     data.vpsize[0] = (float)rClient.right;
  1259.     data.vpsize[1] = (float)rClient.bottom;
  1260.     data.vpsize[2] = 1.0f / (float)rClient.bottom;
  1261.     data.vpsize[3] = 1.0f / (float)rClient.right;
  1262.     data.cvpsize[0] = (float)clippedWidth;
  1263.     data.cvpsize[0] = (float)clippedHeight;
  1264.     data.cvpsize[0] = 1.0f / (float)clippedHeight;
  1265.     data.cvpsize[0] = 1.0f / (float)clippedWidth;
  1266.     data.texsize[0] = (float)(int)ctx.mSourceTexW;
  1267.     data.texsize[1] = (float)(int)ctx.mSourceTexH;
  1268.     data.texsize[2] = 1.0f / (float)(int)ctx.mSourceTexH;
  1269.     data.texsize[3] = 1.0f / (float)(int)ctx.mSourceTexW;
  1270.     data.tex2size[0] = 1.f;
  1271.     data.tex2size[1] = 1.f;
  1272.     data.tex2size[2] = 1.f;
  1273.     data.tex2size[3] = 1.f;
  1274.     data.srcsize[0] = (float)(int)ctx.mSourceW;
  1275.     data.srcsize[1] = (float)(int)ctx.mSourceH;
  1276.     data.srcsize[2] = 1.0f / (float)(int)ctx.mSourceH;
  1277.     data.srcsize[3] = 1.0f / (float)(int)ctx.mSourceW;
  1278.     data.tempsize[0] = 1.f;
  1279.     data.tempsize[1] = 1.f;
  1280.     data.tempsize[2] = 1.f;
  1281.     data.tempsize[3] = 1.f;
  1282.     data.temp2size[0] = 1.f;
  1283.     data.temp2size[1] = 1.f;
  1284.     data.temp2size[2] = 1.f;
  1285.     data.temp2size[3] = 1.f;
  1286.     data.vpcorrect[0] = 2.0f / (float)clippedWidth;
  1287.     data.vpcorrect[1] = 2.0f / (float)clippedHeight;
  1288.     data.vpcorrect[2] = -1.0f / (float)clippedHeight;
  1289.     data.vpcorrect[3] = 1.0f / (float)clippedWidth;
  1290.     data.vpcorrect2[0] = 2.0f / (float)clippedWidth;
  1291.     data.vpcorrect2[1] = -2.0f / (float)clippedHeight;
  1292.     data.vpcorrect2[2] = 1.0f + 1.0f / (float)clippedHeight;
  1293.     data.vpcorrect2[3] = -1.0f - 1.0f / (float)clippedWidth;
  1294.     data.tvpcorrect[0] = 2.0f;
  1295.     data.tvpcorrect[1] = 2.0f;
  1296.     data.tvpcorrect[2] = -1.0f;
  1297.     data.tvpcorrect[3] = 1.0f;
  1298.     data.tvpcorrect2[0] = 2.0f;
  1299.     data.tvpcorrect2[1] = -2.0f;
  1300.     data.tvpcorrect2[2] = 0.f;
  1301.     data.tvpcorrect2[3] = 2.0f;
  1302.     data.t2vpcorrect[0] = 2.0f;
  1303.     data.t2vpcorrect[1] = 2.0f;
  1304.     data.t2vpcorrect[2] = -1.0f;
  1305.     data.t2vpcorrect[3] = 1.0f;
  1306.     data.t2vpcorrect2[0] = 2.0f;
  1307.     data.t2vpcorrect2[1] = -2.0f;
  1308.     data.t2vpcorrect2[2] = 0.f;
  1309.     data.t2vpcorrect2[3] = 2.0f;
  1310.     data.interphtexsize[0] = (float)ctx.mInterpHTexW;
  1311.     data.interphtexsize[1] = (float)ctx.mInterpHTexH;
  1312.     data.interphtexsize[2] = ctx.mInterpHTexH ? 1.0f / (float)ctx.mInterpHTexH : 0.0f;
  1313.     data.interphtexsize[3] = ctx.mInterpHTexW ? 1.0f / (float)ctx.mInterpHTexW : 0.0f;
  1314.     data.interpvtexsize[0] = (float)ctx.mInterpVTexW;
  1315.     data.interpvtexsize[1] = (float)ctx.mInterpVTexH;
  1316.     data.interpvtexsize[2] = ctx.mInterpVTexH ? 1.0f / (float)ctx.mInterpVTexH : 0.0f;
  1317.     data.interpvtexsize[3] = ctx.mInterpVTexW ? 1.0f / (float)ctx.mInterpVTexW : 0.0f;
  1318.     data.fieldinfo[0] = ctx.mFieldOffset;
  1319.     data.fieldinfo[1] = ctx.mFieldOffset * -0.25f;
  1320.     data.fieldinfo[2] = 0.0f;
  1321.     data.fieldinfo[3] = 0.0f;
  1322.  
  1323.     uint32 t = VDGetAccurateTick();
  1324.     data.time[0] = (t % 1000) / 1000.0f;
  1325.     data.time[1] = (t % 5000) / 5000.0f;
  1326.     data.time[2] = (t % 10000) / 10000.0f;
  1327.     data.time[3] = (t % 30000) / 30000.0f;
  1328.  
  1329.     if (ctx.mpSourceTexture2) {
  1330.         D3DSURFACE_DESC desc;
  1331.  
  1332.         HRESULT hr = ctx.mpSourceTexture2->GetLevelDesc(0, &desc);
  1333.         if (FAILED(hr))
  1334.             return false;
  1335.  
  1336.         float w = (float)desc.Width;
  1337.         float h = (float)desc.Height;
  1338.  
  1339.         data.tex2size[0] = w;
  1340.         data.tex2size[1] = h;
  1341.         data.tex2size[2] = 1.0f / h;
  1342.         data.tex2size[3] = 1.0f / w;
  1343.     }
  1344.  
  1345.     if (mpRTTs[firstRTTIndex]) {
  1346.         data.tempsize[0] = (float)mpRTTs[firstRTTIndex]->GetWidth();
  1347.         data.tempsize[1] = (float)mpRTTs[firstRTTIndex]->GetHeight();
  1348.         data.tempsize[2] = 1.0f / data.tempsize[1];
  1349.         data.tempsize[3] = 1.0f / data.tempsize[0];
  1350.         data.tvpcorrect[0] = 2.0f * data.tempsize[3];
  1351.         data.tvpcorrect[1] = 2.0f * data.tempsize[2];
  1352.         data.tvpcorrect[2] = -data.tempsize[2];
  1353.         data.tvpcorrect[3] = data.tempsize[3];
  1354.         data.tvpcorrect2[0] = 2.0f * data.tempsize[3];
  1355.         data.tvpcorrect2[1] = -2.0f * data.tempsize[2];
  1356.         data.tvpcorrect2[2] = 1.0f + data.tempsize[2];
  1357.         data.tvpcorrect2[3] = -1.0f - data.tempsize[3];
  1358.     }
  1359.  
  1360.     if (mpRTTs[1]) {
  1361.         data.temp2size[0] = (float)mpRTTs[1]->GetWidth();
  1362.         data.temp2size[1] = (float)mpRTTs[1]->GetHeight();
  1363.         data.temp2size[2] = 1.0f / data.temp2size[1];
  1364.         data.temp2size[3] = 1.0f / data.temp2size[0];
  1365.         data.t2vpcorrect[0] = 2.0f * data.tempsize[3];
  1366.         data.t2vpcorrect[1] = 2.0f * data.tempsize[2];
  1367.         data.t2vpcorrect[2] = -data.tempsize[2];
  1368.         data.t2vpcorrect[3] = data.tempsize[3];
  1369.         data.t2vpcorrect2[0] = 2.0f * data.tempsize[3];
  1370.         data.t2vpcorrect2[1] = -2.0f * data.tempsize[2];
  1371.         data.t2vpcorrect2[2] = 1.0f + data.tempsize[2];
  1372.         data.t2vpcorrect2[3] = -1.0f - data.tempsize[3];
  1373.     }
  1374.  
  1375.     enum { kStdParamCount = sizeof kStdParamInfo / sizeof kStdParamInfo[0] };
  1376.  
  1377.     uint32 nPasses = technique.mPassCount;
  1378.     const PassInfo *pPasses = technique.mpPasses;
  1379.     IDirect3DDevice9 *dev = mpManager->GetDevice();
  1380.     while(nPasses--) {
  1381.         const PassInfo& pi = *pPasses++;
  1382.  
  1383.         // bind vertex and pixel shaders
  1384.         HRESULT hr = dev->SetVertexShader(pi.mVertexShaderIndex >= 0 ? mVertexShaders[pi.mVertexShaderIndex] : NULL);
  1385.         if (FAILED(hr)) {
  1386.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Couldn't set vertex shader! hr=%08x\n", hr);
  1387.             return false;
  1388.         }
  1389.  
  1390.         hr = dev->SetPixelShader(pi.mPixelShaderIndex >= 0 ? mPixelShaders[pi.mPixelShaderIndex] : NULL);
  1391.         if (FAILED(hr)) {
  1392.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Couldn't set pixel shader! hr=%08x\n", hr);
  1393.             return false;
  1394.         }
  1395.  
  1396.         // set states
  1397.         const uint32 stateStart = pi.mStateStart, stateEnd = pi.mStateEnd;
  1398.         for(uint32 stateIdx = stateStart; stateIdx != stateEnd; ++stateIdx) {
  1399.             uint32 token = g_states[stateIdx];
  1400.             uint32 tokenIndex = (token >> 12) & 0xFFF;
  1401.             uint32 tokenValue = token & 0xFFF;
  1402.  
  1403.             if (tokenValue == 0xFFF)
  1404.                 tokenValue = g_states[++stateIdx];
  1405.  
  1406.             HRESULT hr;
  1407.             switch(token >> 28) {
  1408.                 case 0:        // render state
  1409.                     hr = dev->SetRenderState((D3DRENDERSTATETYPE)tokenIndex, tokenValue);
  1410.                     break;
  1411.                 case 1:        // texture stage state
  1412.                     switch((D3DTEXTURESTAGESTATETYPE)tokenIndex) {
  1413.                     case D3DTSS_BUMPENVMAT00:
  1414.                     case D3DTSS_BUMPENVMAT01:
  1415.                     case D3DTSS_BUMPENVMAT10:
  1416.                     case D3DTSS_BUMPENVMAT11:
  1417.                         {
  1418.                             union {
  1419.                                 uint32 i;
  1420.                                 float f;
  1421.                             } converter = {tokenValue};
  1422.  
  1423.                             if (pi.mBumpEnvScale) {
  1424.                                 const float *param = (const float *)&data + 4*(pi.mBumpEnvScale - 1);
  1425.  
  1426.                                 switch((D3DTEXTURESTAGESTATETYPE)tokenIndex) {
  1427.                                 case D3DTSS_BUMPENVMAT00:
  1428.                                 case D3DTSS_BUMPENVMAT10:
  1429.                                     converter.f *= param[3];
  1430.                                     break;
  1431.                                 case D3DTSS_BUMPENVMAT01:
  1432.                                 case D3DTSS_BUMPENVMAT11:
  1433.                                 default:
  1434.                                     converter.f *= param[2];
  1435.                                     break;
  1436.                                 }
  1437.                             }
  1438.                         
  1439.                             hr = dev->SetTextureStageState((token >> 24)&15, (D3DTEXTURESTAGESTATETYPE)tokenIndex, converter.i);
  1440.                         }
  1441.                         break;
  1442.                     default:
  1443.                         hr = dev->SetTextureStageState((token >> 24)&15, (D3DTEXTURESTAGESTATETYPE)tokenIndex, tokenValue);
  1444.                         break;
  1445.                     }
  1446.                     break;
  1447.                 case 2:        // sampler state
  1448.                     hr = dev->SetSamplerState((token >> 24)&15, (D3DSAMPLERSTATETYPE)tokenIndex, tokenValue);
  1449.                     break;
  1450.                 case 3:        // texture
  1451.                     VDASSERT(tokenValue < sizeof(textures)/sizeof(textures[0]));
  1452.                     hr = dev->SetTexture(tokenIndex, textures[tokenValue]);
  1453.                     break;
  1454.                 case 8:        // vertex bool constant
  1455.                     hr = dev->SetVertexShaderConstantB(tokenIndex, (const BOOL *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1456.                     break;
  1457.                 case 9:        // vertex int constant
  1458.                     hr = dev->SetVertexShaderConstantI(tokenIndex, (const INT *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1459.                     break;
  1460.                 case 10:    // vertex float constant
  1461.                     hr = dev->SetVertexShaderConstantF(tokenIndex, (const float *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1462.                     break;
  1463.                 case 12:    // pixel bool constant
  1464.                     hr = dev->SetPixelShaderConstantB(tokenIndex, (const BOOL *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1465.                     break;
  1466.                 case 13:    // pixel int constant
  1467.                     hr = dev->SetPixelShaderConstantI(tokenIndex, (const INT *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1468.                     break;
  1469.                 case 14:    // pixel float constant
  1470.                     hr = dev->SetPixelShaderConstantF(tokenIndex, (const float *)((char *)&data + kStdParamInfo[tokenValue].offset), 1);
  1471.                     break;
  1472.             }
  1473.  
  1474.             if (FAILED(hr)) {
  1475.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to set state! hr=%08x\n", hr);
  1476.                 return false;
  1477.             }
  1478.         }
  1479.  
  1480.         // change render target
  1481.         if (pi.mRenderTarget >= 0) {
  1482.             if (!mpManager->EndScene())
  1483.                 return false;
  1484.  
  1485.             HRESULT hr = E_FAIL;
  1486.             switch(pi.mRenderTarget) {
  1487.                 case 0:
  1488.                     hr = dev->SetRenderTarget(0, pRTOverride ? pRTOverride : mpManager->GetRenderTarget());
  1489.                     break;
  1490.                 case 1:
  1491.                     if (mpRTTs[firstRTTIndex]) {
  1492.                         IDirect3DSurface9 *pSurf;
  1493.                         hr = mpRTTs[firstRTTIndex]->GetD3DTexture()->GetSurfaceLevel(0, &pSurf);
  1494.                         if (SUCCEEDED(hr)) {
  1495.                             hr = dev->SetRenderTarget(0, pSurf);
  1496.                             pSurf->Release();
  1497.                         }
  1498.                     }
  1499.                     break;
  1500.                 case 2:
  1501.                     if (mpRTTs[1]) {
  1502.                         IDirect3DSurface9 *pSurf;
  1503.                         hr = mpRTTs[1]->GetD3DTexture()->GetSurfaceLevel(0, &pSurf);
  1504.                         if (SUCCEEDED(hr)) {
  1505.                             hr = dev->SetRenderTarget(0, pSurf);
  1506.                             pSurf->Release();
  1507.                         }
  1508.                     }
  1509.                     break;
  1510.             }
  1511.  
  1512.             if (FAILED(hr)) {
  1513.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to set render target! hr=%08x\n", hr);
  1514.                 return false;
  1515.             }
  1516.         }
  1517.  
  1518.         // change viewport
  1519.         D3DVIEWPORT9 vp;
  1520.         if (pi.mViewportW | pi.mViewportH) {
  1521.             HRESULT hr;
  1522.  
  1523.             IDirect3DSurface9 *rt;
  1524.             hr = dev->GetRenderTarget(0, &rt);
  1525.             if (SUCCEEDED(hr)) {
  1526.                 D3DSURFACE_DESC desc;
  1527.                 hr = rt->GetDesc(&desc);
  1528.                 if (SUCCEEDED(hr)) {
  1529.                     const DWORD hsizes[4]={ desc.Width, ctx.mSourceW, clippedWidth, rClient.right };
  1530.                     const DWORD vsizes[4]={ desc.Height, ctx.mSourceH, clippedHeight, rClient.bottom };
  1531.  
  1532.                     vp.X = 0;
  1533.                     vp.Y = 0;
  1534.                     vp.Width = hsizes[pi.mViewportW];
  1535.                     vp.Height = vsizes[pi.mViewportH];
  1536.                     vp.MinZ = 0;
  1537.                     vp.MaxZ = 1;
  1538.  
  1539.                     hr = dev->SetViewport(&vp);
  1540.                 }
  1541.                 rt->Release();
  1542.             }
  1543.  
  1544.             if (FAILED(hr)) {
  1545.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to set viewport! hr=%08x\n", hr);
  1546.                 return false;
  1547.             }
  1548.         } else {
  1549.             HRESULT hr = dev->GetViewport(&vp);
  1550.             if (FAILED(hr)) {
  1551.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to retrieve viewport! hr=%08x\n", hr);
  1552.                 return false;
  1553.             }
  1554.         }
  1555.  
  1556.         // clear target
  1557.         if (pi.mbRTDoClear) {
  1558.             hr = dev->Clear(0, NULL, D3DCLEAR_TARGET, pi.mRTClearColor, 0, 0);
  1559.             if (FAILED(hr)) {
  1560.                 VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to clear viewport! hr=%08x\n", hr);
  1561.                 return false;
  1562.             }
  1563.         }
  1564.  
  1565.         // render!
  1566.         bool validDraw = true;
  1567.  
  1568.         if (Vertex *pvx = mpManager->LockVertices(4)) {
  1569.             const float ustep = 1.0f / (float)(int)ctx.mSourceTexW * ctx.mDefaultUVScaleCorrectionX;
  1570.             const float vstep = 1.0f / (float)(int)ctx.mSourceTexH * ctx.mDefaultUVScaleCorrectionY;
  1571.             const float u0 = 0.0f;
  1572.             const float v0 = pi.mbClipPosition ? ctx.mFieldOffset * vstep * -0.25f : 0.0f;
  1573.             const float u1 = u0 + (int)ctx.mSourceW * ustep;
  1574.             const float v1 = v0 + (int)ctx.mSourceH * vstep;
  1575.  
  1576.             const float invVpW = 1.f / (float)vp.Width;
  1577.             const float invVpH = 1.f / (float)vp.Height;
  1578.  
  1579.             const float x0 = -1.f - invVpW;
  1580.             const float y0 = 1.f + invVpH;
  1581.             const float x1 = pi.mbClipPosition ? x0 + rClient.right * 2.0f * invVpW : 1.f - invVpW;
  1582.             const float y1 = pi.mbClipPosition ? y0 - rClient.bottom * 2.0f * invVpH : -1.f + invVpH;
  1583.  
  1584.             __try {
  1585.                 pvx[0].SetFF2(x0, y0, 0xFFFFFFFF, u0, v0, 0, 0);
  1586.                 pvx[1].SetFF2(x1, y0, 0xFFFFFFFF, u1, v0, 1, 0);
  1587.                 pvx[2].SetFF2(x0, y1, 0xFFFFFFFF, u0, v1, 0, 1);
  1588.                 pvx[3].SetFF2(x1, y1, 0xFFFFFFFF, u1, v1, 1, 1);
  1589.             } __except(1) {
  1590.                 validDraw = false;
  1591.             }
  1592.  
  1593.             mpManager->UnlockVertices();
  1594.         }
  1595.  
  1596.         if (!validDraw) {
  1597.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Invalid vertex buffer lock detected -- bailing.\n");
  1598.             return false;
  1599.         }
  1600.  
  1601.         if (!mpManager->BeginScene())
  1602.             return false;
  1603.  
  1604.         hr = mpManager->DrawArrays(D3DPT_TRIANGLESTRIP, 0, 2);
  1605.         if (FAILED(hr)) {
  1606.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to draw primitive! hr=%08x\n", hr);
  1607.             return false;
  1608.         }
  1609.     }
  1610.  
  1611.     // NVPerfHUD 3.1 draws a bit funny if we leave this set to REVSUBTRACT, even
  1612.     // with alpha blending off....
  1613.     dev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
  1614.  
  1615.     return true;
  1616. }
  1617.  
  1618. ///////////////////////////////////////////////////////////////////////////
  1619.  
  1620. class VDVideoUploadContextD3D9 : public vdrefcounted<IVDVideoUploadContextD3D9>, public VDD3D9Client {
  1621. public:
  1622.     VDVideoUploadContextD3D9();
  1623.     ~VDVideoUploadContextD3D9();
  1624.  
  1625.     IDirect3DTexture9 *GetD3DTexture(int i = 0) { return mpD3DConversionTextures[0] ? mpD3DConversionTextures[i] : mpD3DImageTextures[i]; }
  1626.  
  1627.     bool Init(const VDPixmap& source, bool allowConversion, bool highPrecision, int buffers);
  1628.     void Shutdown();
  1629.  
  1630.     bool Update(const VDPixmap& source, int fieldMask);
  1631.  
  1632. protected:
  1633.     void OnPreDeviceReset();
  1634.     void OnPostDeviceReset();
  1635.     bool ReinitVRAMTextures();
  1636.  
  1637.     VDD3D9Manager    *mpManager;
  1638.     vdrefptr<VDVideoDisplayDX9Manager> mpVideoManager;
  1639.  
  1640.     enum UploadMode {
  1641.         kUploadModeNormal,
  1642.         kUploadModeDirect8,
  1643.         kUploadModeDirect16,
  1644.         kUploadModeDirectV210,
  1645.         kUploadModeDirectNV12
  1646.     } mUploadMode;
  1647.  
  1648.     int mBufferCount;
  1649.     int    mConversionTexW;
  1650.     int    mConversionTexH;
  1651.     bool mbHighPrecision;
  1652.  
  1653.     VDPixmap            mTexFmt;
  1654.  
  1655.     IDirect3DTexture9    *mpD3DImageTextures[3];
  1656.     IDirect3DTexture9    *mpD3DPaletteTexture;
  1657.     IDirect3DTexture9    *mpD3DImageTexture2a;
  1658.     IDirect3DTexture9    *mpD3DImageTexture2b;
  1659.     IDirect3DTexture9    *mpD3DConversionTextures[3];
  1660. };
  1661.  
  1662. bool VDCreateVideoUploadContextD3D9(IVDVideoUploadContextD3D9 **ppContext) {
  1663.     return VDRefCountObjectFactory<VDVideoUploadContextD3D9, IVDVideoUploadContextD3D9>(ppContext);
  1664. }
  1665.  
  1666. VDVideoUploadContextD3D9::VDVideoUploadContextD3D9()
  1667.     : mpManager(NULL)
  1668.     , mpD3DPaletteTexture(NULL)
  1669.     , mpD3DImageTexture2a(NULL)
  1670.     , mpD3DImageTexture2b(NULL)
  1671.     , mbHighPrecision(false)
  1672. {
  1673.     for(int i=0; i<3; ++i) {
  1674.         mpD3DImageTextures[i] = NULL;
  1675.         mpD3DConversionTextures[i] = NULL;
  1676.     }
  1677. }
  1678.  
  1679. VDVideoUploadContextD3D9::~VDVideoUploadContextD3D9() {
  1680.     Shutdown();
  1681. }
  1682.  
  1683. bool VDVideoUploadContextD3D9::Init(const VDPixmap& source, bool allowConversion, bool highPrecision, int buffers) {
  1684.     mBufferCount = buffers;
  1685.     mbHighPrecision = highPrecision;
  1686.  
  1687.     VDASSERT(!mpManager);
  1688.     mpManager = VDInitDirect3D9(this);
  1689.     if (!mpManager)
  1690.         return false;
  1691.  
  1692.     if (!VDInitDisplayDX9(~mpVideoManager)) {
  1693.         Shutdown();
  1694.         return false;
  1695.     }
  1696.  
  1697.     // check capabilities
  1698.     const D3DCAPS9& caps = mpManager->GetCaps();
  1699.  
  1700.     if (caps.MaxTextureWidth < (uint32)source.w || caps.MaxTextureHeight < (uint32)source.h) {
  1701.         VDDEBUG_DX9DISP("VideoDisplay/DX9: source image is larger than maximum texture size\n");
  1702.         Shutdown();
  1703.         return false;
  1704.     }
  1705.  
  1706.     // create source texture
  1707.     int texw = source.w;
  1708.     int texh = source.h;
  1709.  
  1710.     mpManager->AdjustTextureSize(texw, texh);
  1711.  
  1712.     memset(&mTexFmt, 0, sizeof mTexFmt);
  1713.     mTexFmt.format        = nsVDPixmap::kPixFormat_XRGB8888;
  1714.  
  1715.     HRESULT hr;
  1716.     D3DFORMAT d3dfmt;
  1717.     IDirect3DDevice9 *dev = mpManager->GetDevice();
  1718.  
  1719.     if ((    source.format == nsVDPixmap::kPixFormat_YUV410_Planar ||
  1720.             source.format == nsVDPixmap::kPixFormat_YUV420_Planar ||
  1721.             source.format == nsVDPixmap::kPixFormat_YUV422_Planar ||
  1722.             source.format == nsVDPixmap::kPixFormat_YUV444_Planar ||
  1723.             source.format == nsVDPixmap::kPixFormat_Pal8)
  1724.         && mpManager->IsTextureFormatAvailable(D3DFMT_L8) && caps.PixelShaderVersion >= D3DPS_VERSION(1, 1))
  1725.     {
  1726.         mUploadMode = kUploadModeDirect8;
  1727.         d3dfmt = D3DFMT_L8;
  1728.  
  1729.         uint32 subw = texw;
  1730.         uint32 subh = texh;
  1731.  
  1732.         switch(source.format) {
  1733.             case nsVDPixmap::kPixFormat_Pal8:
  1734.             case nsVDPixmap::kPixFormat_YUV444_Planar:
  1735.                 break;
  1736.             case nsVDPixmap::kPixFormat_YUV422_Planar:
  1737.                 subw >>= 1;
  1738.                 break;
  1739.             case nsVDPixmap::kPixFormat_YUV420_Planar:
  1740.                 subw >>= 1;
  1741.                 subh >>= 1;
  1742.                 break;
  1743.             case nsVDPixmap::kPixFormat_YUV410_Planar:
  1744.                 subw >>= 2;
  1745.                 subh >>= 2;
  1746.                 break;
  1747.         }
  1748.  
  1749.         if (subw < 1)
  1750.             subw = 1;
  1751.         if (subh < 1)
  1752.             subh = 1;
  1753.  
  1754.         if (source.format == nsVDPixmap::kPixFormat_Pal8) {
  1755.             hr = dev->CreateTexture(256, 1, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &mpD3DPaletteTexture, NULL);
  1756.             if (FAILED(hr)) {
  1757.                 Shutdown();
  1758.                 return false;
  1759.             }
  1760.         }
  1761.  
  1762.         hr = dev->CreateTexture(subw, subh, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &mpD3DImageTexture2a, NULL);
  1763.         if (FAILED(hr)) {
  1764.             Shutdown();
  1765.             return false;
  1766.         }
  1767.  
  1768.         hr = dev->CreateTexture(subw, subh, 1, 0, D3DFMT_L8, D3DPOOL_MANAGED, &mpD3DImageTexture2b, NULL);
  1769.         if (FAILED(hr)) {
  1770.             Shutdown();
  1771.             return false;
  1772.         }
  1773.     } else if (
  1774.             source.format == nsVDPixmap::kPixFormat_YUV420_NV12 &&
  1775.             mpManager->IsTextureFormatAvailable(D3DFMT_L8) &&
  1776.             mpManager->IsTextureFormatAvailable(D3DFMT_A8L8) &&
  1777.             caps.PixelShaderVersion >= D3DPS_VERSION(1, 1)) {
  1778.         mUploadMode = kUploadModeDirectNV12;
  1779.         d3dfmt = D3DFMT_L8;
  1780.  
  1781.         uint32 subw = (texw + 1) >> 1;
  1782.         uint32 subh = (texh + 1) >> 1;
  1783.  
  1784.         if (subw < 1)
  1785.             subw = 1;
  1786.         if (subh < 1)
  1787.             subh = 1;
  1788.  
  1789.         hr = dev->CreateTexture(subw, subh, 1, 0, D3DFMT_A8L8, D3DPOOL_MANAGED, &mpD3DImageTexture2a, NULL);
  1790.         if (FAILED(hr)) {
  1791.             Shutdown();
  1792.             return false;
  1793.         }
  1794.     } else if (source.format == nsVDPixmap::kPixFormat_YUV422_V210 && mpManager->IsTextureFormatAvailable(D3DFMT_A2B10G10R10) && caps.PixelShaderVersion >= D3DPS_VERSION(2, 0)) {
  1795.         mUploadMode = kUploadModeDirectV210;
  1796.         d3dfmt = D3DFMT_A2B10G10R10;
  1797.     } else {
  1798.         mpVideoManager->DetermineBestTextureFormat(source.format, mTexFmt.format, d3dfmt);
  1799.  
  1800.         mUploadMode = kUploadModeNormal;
  1801.  
  1802.         if (source.format != mTexFmt.format) {
  1803.             if ((source.format == nsVDPixmap::kPixFormat_YUV422_UYVY || source.format == nsVDPixmap::kPixFormat_YUV422_YUYV || source.format == nsVDPixmap::kPixFormat_YUV422_UYVY_709)
  1804.                 && caps.PixelShaderVersion >= D3DPS_VERSION(1,1))
  1805.             {
  1806.                 if (mpManager->IsTextureFormatAvailable(D3DFMT_A8R8G8B8)) {
  1807.                     mUploadMode = kUploadModeDirect16;
  1808.                     d3dfmt = D3DFMT_A8R8G8B8;
  1809.                 }
  1810.             } else if (!allowConversion) {
  1811.                 Shutdown();
  1812.                 return false;
  1813.             }
  1814.         }
  1815.     }
  1816.  
  1817.     mConversionTexW = texw;
  1818.     mConversionTexH = texh;
  1819.     if (!ReinitVRAMTextures()) {
  1820.         Shutdown();
  1821.         return false;
  1822.     }
  1823.  
  1824.     if (mUploadMode == kUploadModeDirectV210) {
  1825.         texw = ((source.w + 5) / 6) * 4;
  1826.         texh = source.h;
  1827.         mpManager->AdjustTextureSize(texw, texh);
  1828.     } else if (mUploadMode == kUploadModeDirect16) {
  1829.         texw = (source.w + 1) >> 1;
  1830.         texh = source.h;
  1831.         mpManager->AdjustTextureSize(texw, texh);
  1832.     }
  1833.  
  1834.     mTexFmt.w            = texw;
  1835.     mTexFmt.h            = texh;
  1836.  
  1837.     hr = dev->CreateTexture(texw, texh, 1, 0, d3dfmt, D3DPOOL_MANAGED, &mpD3DImageTextures[0], NULL);
  1838.     if (FAILED(hr)) {
  1839.         Shutdown();
  1840.         return false;
  1841.     }
  1842.  
  1843.     if (!mpD3DConversionTextures[0]) {
  1844.         for(int i=1; i<buffers; ++i) {
  1845.             hr = dev->CreateTexture(texw, texh, 1, 0, d3dfmt, D3DPOOL_MANAGED, &mpD3DImageTextures[i], NULL);
  1846.             if (FAILED(hr)) {
  1847.                 Shutdown();
  1848.                 return false;
  1849.             }
  1850.         }
  1851.     }
  1852.  
  1853.     // clear source textures
  1854.     for(int i=0; i<buffers; ++i) {
  1855.         D3DLOCKED_RECT lr;
  1856.         if (mpD3DImageTextures[i] && SUCCEEDED(mpD3DImageTextures[i]->LockRect(0, &lr, NULL, 0))) {
  1857.             uint32 fillValue = 0;
  1858.  
  1859.             switch(source.format) {
  1860.                 case nsVDPixmap::kPixFormat_YUV422_UYVY:
  1861.                     VDMemset32Rect(lr.pBits, lr.Pitch, 0x80108010, (texw + 1) >> 1, texh);
  1862.                     break;
  1863.                 case nsVDPixmap::kPixFormat_YUV422_YUYV:
  1864.                     VDMemset32Rect(lr.pBits, lr.Pitch, 0x10801080, (texw + 1) >> 1, texh);
  1865.                     break;
  1866.                 case nsVDPixmap::kPixFormat_YUV444_Planar:
  1867.                 case nsVDPixmap::kPixFormat_YUV422_Planar:
  1868.                 case nsVDPixmap::kPixFormat_YUV420_Planar:
  1869.                 case nsVDPixmap::kPixFormat_YUV411_Planar:
  1870.                 case nsVDPixmap::kPixFormat_YUV410_Planar:
  1871.                 case nsVDPixmap::kPixFormat_YUV420_NV12:
  1872.                     VDMemset8Rect(lr.pBits, lr.Pitch, 0x10, texw, texh);
  1873.                     break;
  1874.                 case nsVDPixmap::kPixFormat_YUV422_V210:
  1875.                     VDMemset32Rect(lr.pBits, lr.Pitch, 0x20080200, ((texw + 5) / 6) * 4, texh);
  1876.                     break;
  1877.                 case nsVDPixmap::kPixFormat_XRGB1555:
  1878.                 case nsVDPixmap::kPixFormat_RGB565:
  1879.                     VDMemset16Rect(lr.pBits, lr.Pitch, 0, texw, texh);
  1880.                     break;
  1881.                 case nsVDPixmap::kPixFormat_Pal8:
  1882.                     VDMemset8Rect(lr.pBits, lr.Pitch, 0, texw, texh);
  1883.                     break;
  1884.                 default:
  1885.                     VDMemset32Rect(lr.pBits, lr.Pitch, 0, texw, texh);
  1886.                     break;
  1887.             }
  1888.  
  1889.             mpD3DImageTextures[i]->UnlockRect(0);
  1890.         }
  1891.     }
  1892.  
  1893.     VDDEBUG_DX9DISP("VideoDisplay/DX9: Init successful for %dx%d source image (%s -> %s)\n", source.w, source.h, VDPixmapGetInfo(source.format).name, VDPixmapGetInfo(mTexFmt.format).name);
  1894.     return true;
  1895. }
  1896.  
  1897. void VDVideoUploadContextD3D9::Shutdown() {
  1898.     if (mpD3DPaletteTexture) {
  1899.         mpD3DPaletteTexture->Release();
  1900.         mpD3DPaletteTexture = NULL;
  1901.     }
  1902.  
  1903.     for(int i=0; i<3; ++i) {
  1904.         if (mpD3DConversionTextures[i]) {
  1905.             mpD3DConversionTextures[i]->Release();
  1906.             mpD3DConversionTextures[i] = NULL;
  1907.         }
  1908.     }
  1909.     if (mpD3DImageTexture2b) {
  1910.         mpD3DImageTexture2b->Release();
  1911.         mpD3DImageTexture2b = NULL;
  1912.     }
  1913.     if (mpD3DImageTexture2a) {
  1914.         mpD3DImageTexture2a->Release();
  1915.         mpD3DImageTexture2a = NULL;
  1916.     }
  1917.  
  1918.     for(int i=0; i<3; ++i) {
  1919.         if (mpD3DImageTextures[i]) {
  1920.             mpD3DImageTextures[i]->Release();
  1921.             mpD3DImageTextures[i] = NULL;
  1922.         }
  1923.     }
  1924.  
  1925.     mpVideoManager = NULL;
  1926.     if (mpManager) {
  1927.         VDDeinitDirect3D9(mpManager, this);
  1928.         mpManager = NULL;
  1929.     }
  1930. }
  1931.  
  1932. bool VDVideoUploadContextD3D9::Update(const VDPixmap& source, int fieldMask) {
  1933.     if (mpD3DConversionTextures[1]) {
  1934.         for(int i=mBufferCount - 2; i>=0; --i)
  1935.             std::swap(mpD3DConversionTextures[i], mpD3DConversionTextures[i+1]);
  1936.     }
  1937.  
  1938.     if (mpD3DImageTextures[1]) {
  1939.         for(int i=mBufferCount - 2; i>=0; --i)
  1940.             std::swap(mpD3DImageTextures[i], mpD3DImageTextures[i+1]);
  1941.     }
  1942.  
  1943.     D3DLOCKED_RECT lr;
  1944.     HRESULT hr;
  1945.  
  1946.     if (mpD3DPaletteTexture) {
  1947.         hr = mpD3DPaletteTexture->LockRect(0, &lr, NULL, 0);
  1948.         if (FAILED(hr))
  1949.             return false;
  1950.  
  1951.         if (source.palette) {
  1952.             memcpy(lr.pBits, source.palette, 256*4);
  1953.         } else {
  1954.             uint32 *dst = (uint32 *)lr.pBits;
  1955.             uint32 v = 0;
  1956.             for(uint32 i=0; i<256; ++i) {
  1957.                 *dst++ = v;
  1958.                 v += 0x010101;
  1959.             }
  1960.         }
  1961.  
  1962.         VDVERIFY(SUCCEEDED(mpD3DPaletteTexture->UnlockRect(0)));
  1963.     }
  1964.     
  1965.     hr = mpD3DImageTextures[0]->LockRect(0, &lr, NULL, 0);
  1966.     if (FAILED(hr))
  1967.         return false;
  1968.  
  1969.     mTexFmt.data        = lr.pBits;
  1970.     mTexFmt.pitch        = lr.Pitch;
  1971.  
  1972.     VDPixmap dst(mTexFmt);
  1973.     VDPixmap src(source);
  1974.  
  1975.     if (fieldMask == 1) {
  1976.         dst.pitch *= 2;
  1977.         dst.h = (dst.h + 1) >> 1;
  1978.         src.pitch *= 2;
  1979.         src.h = (src.h + 1) >> 1;
  1980.     } else if (fieldMask == 2) {
  1981.         dst.data = vdptroffset(dst.data, dst.pitch);
  1982.         dst.pitch *= 2;
  1983.         dst.h >>= 1;
  1984.         src.data = vdptroffset(src.data, src.pitch);
  1985.         src.pitch *= 2;
  1986.         src.h >>= 1;
  1987.     }
  1988.  
  1989.     if (mUploadMode == kUploadModeDirectV210) {
  1990.         VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, ((src.w + 5) / 6) * 16, src.h);
  1991.     } else if (mUploadMode == kUploadModeDirect16) {
  1992.         VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, src.w * 2, src.h);
  1993.     } else if (mUploadMode == kUploadModeDirect8 || mUploadMode == kUploadModeDirectNV12) {
  1994.         VDMemcpyRect(dst.data, dst.pitch, src.data, src.pitch, src.w, src.h);
  1995.     } else {
  1996.         VDPixmapBlt(dst, src);
  1997.     }
  1998.  
  1999.     VDVERIFY(SUCCEEDED(mpD3DImageTextures[0]->UnlockRect(0)));
  2000.  
  2001.     if (mUploadMode == kUploadModeDirectNV12) {
  2002.         uint32 subw = (source.w + 1) >> 1;
  2003.         uint32 subh = (source.h + 1) >> 1;
  2004.  
  2005.         if (subw < 1)
  2006.             subw = 1;
  2007.         if (subh < 1)
  2008.             subh = 1;
  2009.  
  2010.         // upload chroma plane
  2011.         hr = mpD3DImageTexture2a->LockRect(0, &lr, NULL, 0);
  2012.         if (FAILED(hr))
  2013.             return false;
  2014.  
  2015.         VDMemcpyRect(lr.pBits, lr.Pitch, source.data2, source.pitch2, subw*2, subh);
  2016.  
  2017.         VDVERIFY(SUCCEEDED(mpD3DImageTexture2a->UnlockRect(0)));
  2018.  
  2019.     } else if (mUploadMode == kUploadModeDirect8) {
  2020.         uint32 subw = source.w;
  2021.         uint32 subh = source.h;
  2022.  
  2023.         switch(source.format) {
  2024.             case nsVDPixmap::kPixFormat_YUV410_Planar:
  2025.                 subw >>= 2;
  2026.                 subh >>= 2;
  2027.                 break;
  2028.             case nsVDPixmap::kPixFormat_YUV420_Planar:
  2029.                 subw >>= 1;
  2030.                 subh >>= 1;
  2031.                 break;
  2032.             case nsVDPixmap::kPixFormat_YUV422_Planar:
  2033.                 subw >>= 1;
  2034.                 break;
  2035.             case nsVDPixmap::kPixFormat_YUV444_Planar:
  2036.                 break;
  2037.         }
  2038.  
  2039.         if (subw < 1)
  2040.             subw = 1;
  2041.         if (subh < 1)
  2042.             subh = 1;
  2043.  
  2044.         if (source.format != nsVDPixmap::kPixFormat_Pal8) {
  2045.             // upload Cb plane
  2046.             hr = mpD3DImageTexture2a->LockRect(0, &lr, NULL, 0);
  2047.             if (FAILED(hr))
  2048.                 return false;
  2049.  
  2050.             VDMemcpyRect(lr.pBits, lr.Pitch, source.data2, source.pitch2, subw, subh);
  2051.  
  2052.             VDVERIFY(SUCCEEDED(mpD3DImageTexture2a->UnlockRect(0)));
  2053.  
  2054.             // upload Cr plane
  2055.             hr = mpD3DImageTexture2b->LockRect(0, &lr, NULL, 0);
  2056.             if (FAILED(hr))
  2057.                 return false;
  2058.  
  2059.             VDMemcpyRect(lr.pBits, lr.Pitch, source.data3, source.pitch3, subw, subh);
  2060.  
  2061.             VDVERIFY(SUCCEEDED(mpD3DImageTexture2b->UnlockRect(0)));
  2062.         }
  2063.     }
  2064.  
  2065.     if (mUploadMode != kUploadModeNormal) {
  2066.         IDirect3DDevice9 *dev = mpManager->GetDevice();
  2067.         vdrefptr<IDirect3DSurface9> rtsurface;
  2068.  
  2069.         hr = mpD3DConversionTextures[0]->GetSurfaceLevel(0, ~rtsurface);
  2070.         if (FAILED(hr))
  2071.             return false;
  2072.  
  2073.         hr = dev->SetStreamSource(0, mpManager->GetVertexBuffer(), 0, sizeof(Vertex));
  2074.         if (FAILED(hr))
  2075.             return false;
  2076.  
  2077.         hr = dev->SetIndices(mpManager->GetIndexBuffer());
  2078.         if (FAILED(hr))
  2079.             return false;
  2080.  
  2081.         hr = dev->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2);
  2082.         if (FAILED(hr))
  2083.             return false;
  2084.  
  2085.         hr = dev->SetRenderTarget(0, rtsurface);
  2086.         if (FAILED(hr))
  2087.             return false;
  2088.  
  2089.         static const uint32 kRenderStates[][2]={
  2090.             {    D3DRS_LIGHTING,            FALSE                },
  2091.             {    D3DRS_CULLMODE,            D3DCULL_NONE        },
  2092.             {    D3DRS_ZENABLE,            FALSE                },
  2093.             {    D3DRS_ALPHATESTENABLE,    FALSE                },
  2094.             {    D3DRS_ALPHABLENDENABLE,    FALSE                },
  2095.             {    D3DRS_STENCILENABLE,    FALSE                },
  2096.         };
  2097.  
  2098.         for(int i=0; i<sizeof(kRenderStates)/sizeof(kRenderStates[0]); ++i) {
  2099.             const uint32 (&rs)[2] = kRenderStates[i];
  2100.  
  2101.             hr = dev->SetRenderState((D3DRENDERSTATETYPE)rs[0], rs[1]);
  2102.             if (FAILED(hr))
  2103.                 return false;
  2104.         }
  2105.  
  2106.         bool success = false;
  2107.         if (mpManager->BeginScene()) {
  2108.             success = true;
  2109.  
  2110.             D3DVIEWPORT9 vp = { 0, 0, source.w, source.h, 0, 1 };
  2111.             hr = dev->SetViewport(&vp);
  2112.             if (FAILED(hr))
  2113.                 success = false;
  2114.  
  2115.             RECT r = { 0, 0, source.w, source.h };
  2116.             if (success) {
  2117.                 VDVideoDisplayDX9Manager::EffectContext ctx;
  2118.  
  2119.                 ctx.mpSourceTexture1 = mpD3DImageTextures[0];
  2120.                 ctx.mpSourceTexture2 = mpD3DImageTexture2a;
  2121.                 ctx.mpSourceTexture3 = mpD3DImageTexture2b;
  2122.                 ctx.mpPaletteTexture = mpD3DPaletteTexture;
  2123.                 ctx.mpInterpFilterH = NULL;
  2124.                 ctx.mpInterpFilterV = NULL;
  2125.                 ctx.mSourceW = source.w;
  2126.                 ctx.mSourceH = source.h;
  2127.                 ctx.mSourceTexW = mTexFmt.w;
  2128.                 ctx.mSourceTexH = mTexFmt.h;
  2129.                 ctx.mInterpHTexW = 0;
  2130.                 ctx.mInterpHTexH = 0;
  2131.                 ctx.mInterpVTexW = 0;
  2132.                 ctx.mInterpVTexH = 0;
  2133.                 ctx.mDefaultUVScaleCorrectionX = 1.0f;
  2134.                 ctx.mDefaultUVScaleCorrectionY = 1.0f;
  2135.                 ctx.mbHighPrecision = mbHighPrecision;
  2136.  
  2137.                 if (source.format == nsVDPixmap::kPixFormat_YUV422_V210) {
  2138.                     if (!mpVideoManager->RunEffect(ctx, r, g_technique_v210_to_rgb_2_0, rtsurface))
  2139.                         success = false;
  2140.                 } else if (mbHighPrecision) {
  2141.                     switch(source.format) {
  2142.                         case nsVDPixmap::kPixFormat_YUV422_UYVY:
  2143.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2144.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_uyvy_to_rgb_2_0, rtsurface))
  2145.                                 success = false;
  2146.                             break;
  2147.  
  2148.                         case nsVDPixmap::kPixFormat_YUV422_UYVY_709:
  2149.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2150.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_hdyc_to_rgb_2_0, rtsurface))
  2151.                                 success = false;
  2152.                             break;
  2153.  
  2154.                         case nsVDPixmap::kPixFormat_YUV422_YUYV:
  2155.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2156.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yuy2_to_rgb_2_0, rtsurface))
  2157.                                 success = false;
  2158.                             break;
  2159.  
  2160.                         case nsVDPixmap::kPixFormat_YUV444_Planar:
  2161.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv24_to_rgb_2_0, rtsurface))
  2162.                                 success = false;
  2163.                             break;
  2164.  
  2165.                         case nsVDPixmap::kPixFormat_YUV422_Planar:
  2166.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv16_to_rgb_2_0, rtsurface))
  2167.                                 success = false;
  2168.                             break;
  2169.  
  2170.                         case nsVDPixmap::kPixFormat_YUV420_Planar:
  2171.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv12_to_rgb_2_0, rtsurface))
  2172.                                 success = false;
  2173.                             break;
  2174.  
  2175.                         case nsVDPixmap::kPixFormat_YUV410_Planar:
  2176.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yvu9_to_rgb_2_0, rtsurface))
  2177.                                 success = false;
  2178.                             break;
  2179.  
  2180.                         case nsVDPixmap::kPixFormat_Pal8:
  2181.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_pal8_to_rgb_1_1, rtsurface))
  2182.                                 success = false;
  2183.                             break;
  2184.  
  2185.                         case nsVDPixmap::kPixFormat_YUV420_NV12:
  2186.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_nv12_to_rgb_2_0, rtsurface))
  2187.                                 success = false;
  2188.                             break;
  2189.                     }
  2190.                 } else {
  2191.                     switch(source.format) {
  2192.                         case nsVDPixmap::kPixFormat_YUV422_UYVY:
  2193.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2194.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_uyvy_to_rgb_1_1, rtsurface))
  2195.                                 success = false;
  2196.                             break;
  2197.  
  2198.                         case nsVDPixmap::kPixFormat_YUV422_UYVY_709:
  2199.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2200.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_hdyc_to_rgb_1_1, rtsurface))
  2201.                                 success = false;
  2202.                             break;
  2203.  
  2204.                         case nsVDPixmap::kPixFormat_YUV422_YUYV:
  2205.                             ctx.mDefaultUVScaleCorrectionX = 0.5f;
  2206.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yuy2_to_rgb_1_1, rtsurface))
  2207.                                 success = false;
  2208.                             break;
  2209.  
  2210.                         case nsVDPixmap::kPixFormat_YUV444_Planar:
  2211.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv24_to_rgb_1_1, rtsurface))
  2212.                                 success = false;
  2213.                             break;
  2214.  
  2215.                         case nsVDPixmap::kPixFormat_YUV422_Planar:
  2216.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv16_to_rgb_1_1, rtsurface))
  2217.                                 success = false;
  2218.                             break;
  2219.  
  2220.                         case nsVDPixmap::kPixFormat_YUV420_Planar:
  2221.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yv12_to_rgb_1_1, rtsurface))
  2222.                                 success = false;
  2223.                             break;
  2224.  
  2225.                         case nsVDPixmap::kPixFormat_YUV410_Planar:
  2226.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_yvu9_to_rgb_1_1, rtsurface))
  2227.                                 success = false;
  2228.                             break;
  2229.  
  2230.                         case nsVDPixmap::kPixFormat_Pal8:
  2231.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_pal8_to_rgb_1_1, rtsurface))
  2232.                                 success = false;
  2233.                             break;
  2234.  
  2235.                         case nsVDPixmap::kPixFormat_YUV420_NV12:
  2236.                             if (!mpVideoManager->RunEffect(ctx, r, g_technique_nv12_to_rgb_1_1, rtsurface))
  2237.                                 success = false;
  2238.                             break;
  2239.                     }
  2240.                 }
  2241.             }
  2242.  
  2243.             if (!mpManager->EndScene())
  2244.                 success = false;
  2245.         }
  2246.  
  2247.         dev->SetRenderTarget(0, mpManager->GetRenderTarget());
  2248.  
  2249.         return success;
  2250.     }
  2251.  
  2252.     return true;
  2253. }
  2254.  
  2255. void VDVideoUploadContextD3D9::OnPreDeviceReset() {
  2256.     for(int i=0; i<3; ++i) {
  2257.         if (mpD3DConversionTextures[i]) {
  2258.             mpD3DConversionTextures[i]->Release();
  2259.             mpD3DConversionTextures[i] = NULL;
  2260.         }
  2261.     }
  2262. }
  2263.  
  2264. void VDVideoUploadContextD3D9::OnPostDeviceReset() {
  2265.     ReinitVRAMTextures();
  2266. }
  2267.  
  2268. bool VDVideoUploadContextD3D9::ReinitVRAMTextures() {
  2269.     if (mUploadMode != kUploadModeNormal) {
  2270.         IDirect3DDevice9 *dev = mpManager->GetDevice();
  2271.  
  2272.         for(int i=0; i<mBufferCount; ++i) {
  2273.             if (mpD3DConversionTextures[i]) {
  2274.                 mpD3DConversionTextures[i]->Release();
  2275.                 mpD3DConversionTextures[i] = NULL;
  2276.             }
  2277.  
  2278.             HRESULT hr = dev->CreateTexture(mConversionTexW, mConversionTexH, 1, D3DUSAGE_RENDERTARGET, mbHighPrecision ? D3DFMT_A16B16G16R16F : D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &mpD3DConversionTextures[i], NULL);
  2279.             if (FAILED(hr))
  2280.                 return false;
  2281.  
  2282.             mpManager->ClearRenderTarget(mpD3DConversionTextures[i]);
  2283.         }
  2284.     }
  2285.  
  2286.     return true;
  2287. }
  2288.  
  2289. ///////////////////////////////////////////////////////////////////////////
  2290.  
  2291. class VDVideoDisplayMinidriverDX9 : public VDVideoDisplayMinidriver, protected VDD3D9Client {
  2292. public:
  2293.     VDVideoDisplayMinidriverDX9(bool clipToMonitor);
  2294.     ~VDVideoDisplayMinidriverDX9();
  2295.  
  2296. protected:
  2297.     bool Init(HWND hwnd, const VDVideoDisplaySourceInfo& info);
  2298.     void Shutdown();
  2299.  
  2300.     bool ModifySource(const VDVideoDisplaySourceInfo& info);
  2301.  
  2302.     bool IsValid();
  2303.     bool IsFramePending() { return mbSwapChainPresentPending; }
  2304.     void SetFilterMode(FilterMode mode);
  2305.     void SetFullScreen(bool fs);
  2306.  
  2307.     bool Tick(int id);
  2308.     void Poll();
  2309.     bool Resize();
  2310.     bool Update(UpdateMode);
  2311.     void Refresh(UpdateMode);
  2312.     bool Paint(HDC hdc, const RECT& rClient, UpdateMode mode);
  2313.  
  2314.     void SetLogicalPalette(const uint8 *pLogicalPalette);
  2315.     float GetSyncDelta() const { return mSyncDelta; }
  2316.  
  2317. protected:
  2318.     void OnPreDeviceReset();
  2319.     void OnPostDeviceReset() {}
  2320.  
  2321.     void InitBicubic();
  2322.     void ShutdownBicubic();
  2323.     bool InitBicubicPS2Filters(int w, int h);
  2324.     void ShutdownBicubicPS2Filters();
  2325.  
  2326.     bool UpdateBackbuffer(const RECT& rClient, UpdateMode updateMode);
  2327.     bool UpdateScreen(const RECT& rClient, UpdateMode updateMode, bool polling);
  2328.  
  2329.     HWND                mhwnd;
  2330.     RECT                mrClient;
  2331.     VDD3D9Manager        *mpManager;
  2332.     vdrefptr<VDVideoDisplayDX9Manager>    mpVideoManager;
  2333.     IDirect3DDevice9    *mpD3DDevice;            // weak ref
  2334.     vdrefptr<IDirect3DTexture9>    mpD3DInterpFilterTextureH;
  2335.     vdrefptr<IDirect3DTexture9>    mpD3DInterpFilterTextureV;
  2336.     int                    mInterpFilterHSize;
  2337.     int                    mInterpFilterHTexSize;
  2338.     int                    mInterpFilterVSize;
  2339.     int                    mInterpFilterVTexSize;
  2340.  
  2341.     vdrefptr<VDVideoUploadContextD3D9>    mpUploadContext;
  2342.     vdrefptr<IVDFontRendererD3D9>    mpFontRenderer;
  2343.  
  2344.     vdrefptr<IVDD3D9SwapChain>    mpSwapChain;
  2345.     int                    mSwapChainW;
  2346.     int                    mSwapChainH;
  2347.     bool                mbSwapChainImageValid;
  2348.     bool                mbSwapChainPresentPending;
  2349.     bool                mbSwapChainPresentPolling;
  2350.     bool                mbFirstPresent;
  2351.     bool                mbFullScreen;
  2352.     bool                mbFullScreenSet;
  2353.     const bool            mbClipToMonitor;
  2354.  
  2355.     VDVideoDisplayDX9Manager::CubicMode    mCubicMode;
  2356.     bool                mbCubicInitialized;
  2357.     bool                mbCubicAttempted;
  2358.     bool                mbCubicUsingHighPrecision;
  2359.     bool                mbCubicTempSurfacesInitialized;
  2360.     FilterMode            mPreferredFilter;
  2361.     float                mSyncDelta;
  2362.     VDD3DPresentHistory    mPresentHistory;
  2363.  
  2364.     VDPixmap                    mTexFmt;
  2365.  
  2366.     VDVideoDisplaySourceInfo    mSource;
  2367.  
  2368.     VDStringA        mFormatString;
  2369.     VDStringA        mDebugString;
  2370. };
  2371.  
  2372. IVDVideoDisplayMinidriver *VDCreateVideoDisplayMinidriverDX9(bool clipToMonitor) {
  2373.     return new VDVideoDisplayMinidriverDX9(clipToMonitor);
  2374. }
  2375.  
  2376. VDVideoDisplayMinidriverDX9::VDVideoDisplayMinidriverDX9(bool clipToMonitor)
  2377.     : mpManager(NULL)
  2378.     , mpD3DDevice(NULL)
  2379.     , mInterpFilterHSize(0)
  2380.     , mInterpFilterHTexSize(0)
  2381.     , mInterpFilterVSize(0)
  2382.     , mInterpFilterVTexSize(0)
  2383.     , mpVideoManager(NULL)
  2384.     , mSwapChainW(0)
  2385.     , mSwapChainH(0)
  2386.     , mbSwapChainImageValid(false)
  2387.     , mbSwapChainPresentPending(false)
  2388.     , mbSwapChainPresentPolling(false)
  2389.     , mbFirstPresent(true)
  2390.     , mbFullScreen(false)
  2391.     , mbFullScreenSet(false)
  2392.     , mbClipToMonitor(clipToMonitor)
  2393.     , mbCubicInitialized(false)
  2394.     , mbCubicAttempted(false)
  2395.     , mbCubicUsingHighPrecision(false)
  2396.     , mbCubicTempSurfacesInitialized(false)
  2397.     , mPreferredFilter(kFilterAnySuitable)
  2398.     , mSyncDelta(0.0f)
  2399. {
  2400.     mrClient.top = mrClient.left = mrClient.right = mrClient.bottom = 0;
  2401. }
  2402.  
  2403. VDVideoDisplayMinidriverDX9::~VDVideoDisplayMinidriverDX9() {
  2404. }
  2405.  
  2406. bool VDVideoDisplayMinidriverDX9::Init(HWND hwnd, const VDVideoDisplaySourceInfo& info) {
  2407.     VDASSERT(!mpManager);
  2408.     mhwnd = hwnd;
  2409.     mSource = info;
  2410.     GetClientRect(hwnd, &mrClient);
  2411.  
  2412.     // attempt to initialize D3D9
  2413.     mbFullScreenSet = false;
  2414.     mpManager = VDInitDirect3D9(this);
  2415.     if (!mpManager) {
  2416.         Shutdown();
  2417.         return false;
  2418.     }
  2419.  
  2420.     if (!VDInitDisplayDX9(~mpVideoManager)) {
  2421.         Shutdown();
  2422.         return false;
  2423.     }
  2424.  
  2425.     if (mbFullScreen && !mbFullScreenSet) {
  2426.         mbFullScreenSet = true;
  2427.         mpManager->AdjustFullScreen(true);
  2428.     }
  2429.  
  2430.     mpD3DDevice = mpManager->GetDevice();
  2431.  
  2432.     // init font renderer
  2433.     if (mbDisplayDebugInfo) {
  2434.         if (!VDCreateFontRendererD3D9(~mpFontRenderer)) {
  2435.             Shutdown();
  2436.             return false;
  2437.         }
  2438.  
  2439.         mpFontRenderer->Init(mpManager);        // we explicitly allow this to fail
  2440.     }
  2441.  
  2442.     mpUploadContext = new_nothrow VDVideoUploadContextD3D9;
  2443.     if (!mpUploadContext || !mpUploadContext->Init(info.pixmap, info.bAllowConversion, mbHighPrecision && mpVideoManager->Is16FEnabled(), 1)) {
  2444.         Shutdown();
  2445.         return false;
  2446.     }
  2447.  
  2448.     mSyncDelta = 0.0f;
  2449.     mbFirstPresent = true;
  2450.  
  2451.     return true;
  2452. }
  2453.  
  2454. void VDVideoDisplayMinidriverDX9::OnPreDeviceReset() {
  2455.     ShutdownBicubic();
  2456.     ShutdownBicubicPS2Filters();
  2457.     mpSwapChain = NULL;
  2458.     mSwapChainW = 0;
  2459.     mSwapChainH = 0;
  2460. }
  2461.  
  2462. void VDVideoDisplayMinidriverDX9::InitBicubic() {
  2463.     if (mbCubicInitialized || mbCubicAttempted)
  2464.         return;
  2465.  
  2466.     mbCubicAttempted = true;
  2467.  
  2468.     mCubicMode = mpVideoManager->InitBicubic();
  2469.  
  2470.     if (mCubicMode == VDVideoDisplayDX9Manager::kCubicNotPossible)
  2471.         return;
  2472.  
  2473.     VDASSERT(!mbCubicTempSurfacesInitialized);
  2474.     mbCubicUsingHighPrecision = mbHighPrecision;
  2475.     mbCubicTempSurfacesInitialized = mpVideoManager->InitBicubicTempSurfaces(mbCubicUsingHighPrecision);
  2476.     if (!mbCubicTempSurfacesInitialized) {
  2477.         mpVideoManager->ShutdownBicubic();
  2478.         mCubicMode = VDVideoDisplayDX9Manager::kCubicNotPossible;
  2479.         return;
  2480.     }
  2481.  
  2482.     VDDEBUG_DX9DISP("VideoDisplay/DX9: Bicubic initialization complete.\n");
  2483.     if (mCubicMode == VDVideoDisplayDX9Manager::kCubicUsePS1_4Path)
  2484.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Using pixel shader 1.4, 5 texture (RADEON 8xxx+ / GeForceFX+) pixel path.\n");
  2485.     else if (mCubicMode == VDVideoDisplayDX9Manager::kCubicUsePS1_1Path)
  2486.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Using pixel shader 1.1, 4 texture (GeForce3/4) pixel path.\n");
  2487.     else if (mCubicMode == VDVideoDisplayDX9Manager::kCubicUseFF3Path)
  2488.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Using fixed function, 3 texture (RADEON 7xxx) pixel path.\n");
  2489.     else
  2490.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Using fixed function, 2 texture (GeForce2) pixel path.\n");
  2491.  
  2492.     mbCubicInitialized = true;
  2493. }
  2494.  
  2495. void VDVideoDisplayMinidriverDX9::ShutdownBicubic() {
  2496.     if (mbCubicInitialized) {
  2497.         mbCubicInitialized = mbCubicAttempted = false;
  2498.  
  2499.         if (mbCubicTempSurfacesInitialized) {
  2500.             mbCubicTempSurfacesInitialized = false;
  2501.  
  2502.             mpVideoManager->ShutdownBicubicTempSurfaces(mbCubicUsingHighPrecision);
  2503.         }
  2504.  
  2505.         mpVideoManager->ShutdownBicubic();
  2506.     }
  2507. }
  2508.  
  2509. ///////////////////////////////////////////////////////////////////////////
  2510.  
  2511. namespace {
  2512.     int GeneratePS2CubicTexture(VDD3D9Manager *pManager, int w, int srcw, vdrefptr<IDirect3DTexture9>& pTexture, int existingTexW, bool mode1_4) {
  2513.         IDirect3DDevice9 *dev = pManager->GetDevice();
  2514.  
  2515.         // Round up to next multiple of 128 pixels to reduce reallocation.
  2516.         int texw = (w + 127) & ~127;
  2517.         int texh = 1;
  2518.         pManager->AdjustTextureSize(texw, texh);
  2519.  
  2520.         // If we can't fit the texture, bail.
  2521.         if (texw < w)
  2522.             return -1;
  2523.  
  2524.         // Check if we need to reallocate the texture.
  2525.         if (!pTexture || existingTexW != texw) {
  2526.             HRESULT hr = dev->CreateTexture(texw, texh, 1, 0, mode1_4  ? D3DFMT_A8R8G8B8 : D3DFMT_X8L8V8U8, D3DPOOL_MANAGED, ~pTexture, NULL);
  2527.             if (FAILED(hr))
  2528.                 return -1;
  2529.         }
  2530.  
  2531.         // Fill the texture.
  2532.         D3DLOCKED_RECT lr;
  2533.         HRESULT hr = pTexture->LockRect(0, &lr, NULL, 0);
  2534.         VDASSERT(SUCCEEDED(hr));
  2535.         if (FAILED(hr)) {
  2536.             VDDEBUG_DX9DISP("VideoDisplay/DX9: Failed to load bicubic texture.\n");
  2537.             return -1;
  2538.         }
  2539.  
  2540.         double dudx = (double)srcw / (double)w;
  2541.         double u = dudx * 0.5;
  2542.         double u0 = 0.5;
  2543.         double ud0 = 1.5;
  2544.         double ud1 = (double)srcw - 1.5;
  2545.         double u1 = (double)srcw - 0.5;
  2546.         uint32 *p0 = (uint32 *)lr.pBits;
  2547.  
  2548.         if (mode1_4) {
  2549.             for(int x = 0; x < texw; ++x) {
  2550.                 double ut = u;
  2551.                 if (ut < u0)
  2552.                     ut = u0;
  2553.                 else if (ut > u1)
  2554.                     ut = u1;
  2555.                 int ix = VDFloorToInt(ut - 0.5);
  2556.                 double d = ut - ((double)ix + 0.5);
  2557.  
  2558.                 static const double m = -0.75;
  2559.                 double c0 = (( (m    )*d - 2.0*m    )*d +   m)*d;
  2560.                 double c1 = (( (m+2.0)*d -     m-3.0)*d      )*d + 1.0;
  2561.                 double c2 = ((-(m+2.0)*d + 2.0*m+3.0)*d -   m)*d;
  2562.                 double c3 = ((-(m    )*d +     m    )*d      )*d;
  2563.  
  2564.                 double c03        = c0+c3;
  2565.                 double k1 = d < 0.5 ? d < 1e-5 ? -m : c2 / d : d > 1-1e-5 ? -m : c1 / (1-d);
  2566.                 double kx = d < 0.5 ? c1 - k1*(1-d) : c2 - k1*d;
  2567.  
  2568.                 if (ut < ud0 || ut > ud1) {
  2569.                     c0 = 0;
  2570.                     k1 = 1.0;
  2571.                     kx = 0.0;
  2572.                     c3 = 0;
  2573.                 }
  2574.  
  2575.                 double blue        = -c0*4;
  2576.                 double green    = k1 - 1.0 + 128.0f/255.0f;
  2577.                 double red        = kx * 2;
  2578.                 double alpha    = -c3*4;
  2579.  
  2580.                 uint8 ib = VDClampedRoundFixedToUint8Fast((float)blue);
  2581.                 uint8 ig = VDClampedRoundFixedToUint8Fast((float)green);
  2582.                 uint8 ir = VDClampedRoundFixedToUint8Fast((float)red);
  2583.                 uint8 ia = VDClampedRoundFixedToUint8Fast((float)alpha);
  2584.  
  2585.                 p0[x] = (uint32)ib + ((uint32)ig << 8) + ((uint32)ir << 16) + ((uint32)ia << 24);
  2586.  
  2587.                 u += dudx;
  2588.             }
  2589.         } else {
  2590.             for(int x = 0; x < texw; ++x) {
  2591.                 int ix = VDFloorToInt(u - 0.5);
  2592.                 double d = u - ((double)ix + 0.5);
  2593.  
  2594.                 static const double m = -0.75;
  2595.                 double c0 = (( (m    )*d - 2.0*m    )*d +   m)*d;
  2596.                 double c1 = (( (m+2.0)*d -     m-3.0)*d      )*d + 1.0;
  2597.                 double c2 = ((-(m+2.0)*d + 2.0*m+3.0)*d -   m)*d;
  2598.                 double c3 = ((-(m    )*d +     m    )*d      )*d;
  2599.  
  2600.                 double k0 = d*(1-d)*m;
  2601.                 double k2 = d*(1-d)*m;
  2602.  
  2603.                 double c1bi = d*k0;
  2604.                 double c2bi = (1-d)*k2;
  2605.                 double c1ex = c1-c1bi;
  2606.                 double c2ex = c2-c2bi;
  2607.  
  2608.                 double o1 = c2ex/(c1ex+c2ex)-d;
  2609.  
  2610.                 double blue        = d;                            // bilinear offset - p0 and p3
  2611.                 double green    = o1*4;                            // bilinear offset - p1 and p2
  2612.                 double red        = (d*(1-d))*4;                    // shift factor between the two
  2613.                 double alpha    = d;                            // lerp constant between p0 and p3
  2614.  
  2615.                 uint8 ib = VDClampedRoundFixedToUint8Fast((float)blue * 127.0f/255.0f + 128.0f/255.0f) ^ 0x80;
  2616.                 uint8 ig = VDClampedRoundFixedToUint8Fast((float)green * 127.0f/255.0f + 128.0f/255.0f) ^ 0x80;
  2617.                 uint8 ir = VDClampedRoundFixedToUint8Fast((float)red);
  2618.                 uint8 ia = VDClampedRoundFixedToUint8Fast((float)alpha);
  2619.  
  2620. #if 0
  2621.                 double fb = (sint8)ib / 127.0f;
  2622.                 double fg = (sint8)ig / 127.0f;
  2623.                 double fr = (double)ir / 255.0f;
  2624.                 double fa = (double)ia / 255.0f;
  2625.  
  2626.                 double g0 = fr*0.25f*0.75f;
  2627.                 double g1 = 2*(0.5f + fr*0.25f*0.75f);
  2628.                 double d1 = 0.25f * fg + d;
  2629.                 double g2 = fr*0.25f*0.75f;
  2630.  
  2631.                 double cr0 = -g0*(1-d);
  2632.                 double cr1 = -g0*d + g1*(1-d1);
  2633.                 double cr2 = g1*d1 + -g2*(1-d);
  2634.                 double cr3 = -g2*d;
  2635.  
  2636.                 if (fabsf(cr0-c0) > 0.01f)
  2637.                     __debugbreak();
  2638.                 if (fabsf(cr1-c1) > 0.01f)
  2639.                     __debugbreak();
  2640.                 if (fabsf(cr2-c2) > 0.01f)
  2641.                     __debugbreak();
  2642.                 if (fabsf(cr3-c3) > 0.01f)
  2643.                     __debugbreak();
  2644. #endif
  2645.  
  2646.     //            p0[x] = (uint32)ib + ((uint32)ig << 8);
  2647.                 p0[x] = (uint32)ib + ((uint32)ig << 8) + ((uint32)ir << 16) + ((uint32)ia << 24);
  2648.  
  2649.                 u += dudx;
  2650.             }
  2651.         }
  2652.  
  2653.         VDVERIFY(SUCCEEDED(pTexture->UnlockRect(0)));
  2654.         return texw;
  2655.     }
  2656. }
  2657.  
  2658. bool VDVideoDisplayMinidriverDX9::InitBicubicPS2Filters(int w, int h) {
  2659.     // requires PS2.0 path
  2660.     if (mCubicMode != VDVideoDisplayDX9Manager::kCubicUsePS1_1Path && mCubicMode != VDVideoDisplayDX9Manager::kCubicUsePS1_4Path)
  2661.         return false;
  2662.  
  2663.     bool mode1_4 = (mCubicMode == VDVideoDisplayDX9Manager::kCubicUsePS1_4Path);
  2664.  
  2665.     // update horiz filter
  2666.     if (!mpD3DInterpFilterTextureH || mInterpFilterHSize != w) {
  2667.         int newtexw = GeneratePS2CubicTexture(mpManager, w, mSource.pixmap.w, mpD3DInterpFilterTextureH, mInterpFilterHSize, mode1_4);
  2668.         if (newtexw < 0)
  2669.             return false;
  2670.  
  2671.         mInterpFilterHSize = w;
  2672.         mInterpFilterHTexSize = newtexw;
  2673.     }
  2674.  
  2675.     // update vert filter
  2676.     if (!mpD3DInterpFilterTextureV || mInterpFilterVSize != h) {
  2677.         int newtexw = GeneratePS2CubicTexture(mpManager, h, mSource.pixmap.h, mpD3DInterpFilterTextureV, mInterpFilterVSize, mode1_4);
  2678.         if (newtexw < 0)
  2679.             return false;
  2680.  
  2681.         mInterpFilterVSize = h;
  2682.         mInterpFilterVTexSize = newtexw;
  2683.     }
  2684.     return true;
  2685. }
  2686.  
  2687. void VDVideoDisplayMinidriverDX9::ShutdownBicubicPS2Filters() {
  2688.     mpD3DInterpFilterTextureH = NULL;
  2689.     mpD3DInterpFilterTextureV = NULL;
  2690.     mInterpFilterHSize = 0;
  2691.     mInterpFilterHTexSize = 0;
  2692.     mInterpFilterVSize = 0;
  2693.     mInterpFilterVTexSize = 0;
  2694. }
  2695.  
  2696. void VDVideoDisplayMinidriverDX9::Shutdown() {
  2697.     mpUploadContext = NULL;
  2698.  
  2699.     if (mpFontRenderer) {
  2700.         mpFontRenderer->Shutdown();
  2701.         mpFontRenderer = NULL;
  2702.     }
  2703.  
  2704.     ShutdownBicubic();
  2705.     ShutdownBicubicPS2Filters();
  2706.  
  2707.     mpSwapChain = NULL;
  2708.     mSwapChainW = 0;
  2709.     mSwapChainH = 0;
  2710.  
  2711.     mpVideoManager = NULL;
  2712.  
  2713.     if (mpManager) {
  2714.         if (mbFullScreenSet) {
  2715.             mbFullScreenSet = false;
  2716.             mpManager->AdjustFullScreen(false);
  2717.         }
  2718.  
  2719.         VDDeinitDirect3D9(mpManager, this);
  2720.         mpManager = NULL;
  2721.     }
  2722.  
  2723.     mbCubicAttempted = false;
  2724. }
  2725.  
  2726. bool VDVideoDisplayMinidriverDX9::ModifySource(const VDVideoDisplaySourceInfo& info) {
  2727.     if (mSource.pixmap.w == info.pixmap.w && mSource.pixmap.h == info.pixmap.h && mSource.pixmap.format == info.pixmap.format && mSource.pixmap.pitch == info.pixmap.pitch) {
  2728.         mSource = info;
  2729.         return true;
  2730.     }
  2731.     return false;
  2732. }
  2733.  
  2734. bool VDVideoDisplayMinidriverDX9::IsValid() {
  2735.     return mpD3DDevice != 0;
  2736. }
  2737.  
  2738. void VDVideoDisplayMinidriverDX9::SetFilterMode(FilterMode mode) {
  2739.     mPreferredFilter = mode;
  2740.  
  2741.     if (mode != kFilterBicubic && mode != kFilterAnySuitable) {
  2742.         ShutdownBicubicPS2Filters();
  2743.  
  2744.         if (mbCubicInitialized)
  2745.             ShutdownBicubic();
  2746.     }
  2747. }
  2748.  
  2749. void VDVideoDisplayMinidriverDX9::SetFullScreen(bool fs) {
  2750.     if (mbFullScreen != fs) {
  2751.         mbFullScreen = fs;
  2752.  
  2753.         if (mpManager) {
  2754.             if (mbFullScreenSet != fs) {
  2755.                 mbFullScreenSet = fs;
  2756.                 mpManager->AdjustFullScreen(fs);
  2757.             }
  2758.         }
  2759.     }
  2760. }
  2761.  
  2762. bool VDVideoDisplayMinidriverDX9::Tick(int id) {
  2763.     return true;
  2764. }
  2765.  
  2766. void VDVideoDisplayMinidriverDX9::Poll() {
  2767.     if (mbSwapChainPresentPending)
  2768.         UpdateScreen(mrClient, kModeVSync, true);
  2769. }
  2770.  
  2771. bool VDVideoDisplayMinidriverDX9::Resize() {
  2772.     mbSwapChainImageValid = false;
  2773.     GetClientRect(mhwnd, &mrClient);
  2774.     return true;
  2775. }
  2776.  
  2777. bool VDVideoDisplayMinidriverDX9::Update(UpdateMode mode) {
  2778.     int fieldMask = 3;
  2779.  
  2780.     switch(mode & kModeFieldMask) {
  2781.         case kModeEvenField:
  2782.             fieldMask = 1;
  2783.             break;
  2784.  
  2785.         case kModeOddField:
  2786.             fieldMask = 2;
  2787.             break;
  2788.  
  2789.         case kModeAllFields:
  2790.             break;
  2791.     }
  2792.  
  2793.     if (!mpUploadContext->Update(mSource.pixmap, fieldMask))
  2794.         return false;
  2795.  
  2796.     mbSwapChainImageValid = false;
  2797.  
  2798.     return true;
  2799. }
  2800.  
  2801. void VDVideoDisplayMinidriverDX9::Refresh(UpdateMode mode) {
  2802.     if (mrClient.right > 0 && mrClient.bottom > 0) {
  2803.         Paint(NULL, mrClient, mode);
  2804.     }
  2805. }
  2806.  
  2807. bool VDVideoDisplayMinidriverDX9::Paint(HDC, const RECT& rClient, UpdateMode updateMode) {
  2808.     return (mbSwapChainImageValid || UpdateBackbuffer(rClient, updateMode)) && UpdateScreen(rClient, updateMode, 0 != (updateMode & kModeVSync));
  2809. }
  2810.  
  2811. void VDVideoDisplayMinidriverDX9::SetLogicalPalette(const uint8 *pLogicalPalette) {
  2812. }
  2813.  
  2814. bool VDVideoDisplayMinidriverDX9::UpdateBackbuffer(const RECT& rClient0, UpdateMode updateMode) {
  2815.     int rtw = mpManager->GetMainRTWidth();
  2816.     int rth = mpManager->GetMainRTHeight();
  2817.     RECT rClient = rClient0;
  2818.     if (mbFullScreen) {
  2819.         rClient.right = rtw;
  2820.         rClient.bottom = rth;
  2821.     }
  2822.  
  2823.     RECT rClippedClient={0,0,std::min<int>(rClient.right, rtw), std::min<int>(rClient.bottom, rth)};
  2824.  
  2825.     // Make sure the device is sane.
  2826.     if (!mpManager->CheckDevice())
  2827.         return false;
  2828.  
  2829.     // Check if we need to create or resize the swap chain.
  2830.     if (mSwapChainW >= rClippedClient.right + 128 || mSwapChainH >= rClippedClient.bottom + 128) {
  2831.         mpSwapChain = NULL;
  2832.         mSwapChainW = 0;
  2833.         mSwapChainH = 0;
  2834.     }
  2835.  
  2836.     if (!mbFullScreen && (!mpSwapChain || mSwapChainW < rClippedClient.right || mSwapChainH < rClippedClient.bottom)) {
  2837.         int scw = std::min<int>((rClippedClient.right + 127) & ~127, rtw);
  2838.         int sch = std::min<int>((rClippedClient.bottom + 127) & ~127, rth);
  2839.  
  2840.  
  2841.         if (!mpManager->CreateSwapChain(scw, sch, mbClipToMonitor, ~mpSwapChain))
  2842.             return false;
  2843.  
  2844.         mSwapChainW = scw;
  2845.         mSwapChainH = sch;
  2846.     }
  2847.  
  2848.     // Do we need to switch bicubic modes?
  2849.     FilterMode mode = mPreferredFilter;
  2850.  
  2851.     if (mode == kFilterAnySuitable)
  2852.         mode = kFilterBicubic;
  2853.  
  2854.     // bicubic modes cannot clip
  2855.     if (rClient.right != rClippedClient.right || rClient.bottom != rClippedClient.bottom)
  2856.         mode = kFilterBilinear;
  2857.  
  2858.     if (mode != kFilterBicubic && mbCubicInitialized)
  2859.         ShutdownBicubic();
  2860.     else if (mode == kFilterBicubic && !mbCubicInitialized && !mbCubicAttempted)
  2861.         InitBicubic();
  2862.  
  2863.  
  2864.     const D3DMATRIX ident={
  2865.         1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1
  2866.     };
  2867.  
  2868.     D3D_DO(SetTransform(D3DTS_WORLD, &ident));
  2869.     D3D_DO(SetTransform(D3DTS_VIEW, &ident));
  2870.     D3D_DO(SetTransform(D3DTS_PROJECTION, &ident));
  2871.  
  2872.     D3D_DO(SetStreamSource(0, mpManager->GetVertexBuffer(), 0, sizeof(Vertex)));
  2873.     D3D_DO(SetIndices(mpManager->GetIndexBuffer()));
  2874.     D3D_DO(SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2));
  2875.     D3D_DO(SetRenderState(D3DRS_LIGHTING, FALSE));
  2876.     D3D_DO(SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE));
  2877.     D3D_DO(SetRenderState(D3DRS_ZENABLE, FALSE));
  2878.     D3D_DO(SetRenderState(D3DRS_ALPHATESTENABLE, FALSE));
  2879.     D3D_DO(SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE));
  2880.     D3D_DO(SetRenderState(D3DRS_STENCILENABLE, FALSE));
  2881.     D3D_DO(SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0));
  2882.     D3D_DO(SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1));
  2883.     D3D_DO(SetTextureStageState(2, D3DTSS_TEXCOORDINDEX, 2));
  2884.  
  2885.     const D3DPRESENT_PARAMETERS& pparms = mpManager->GetPresentParms();
  2886.  
  2887.     VDVideoDisplayDX9Manager::EffectContext ctx;
  2888.  
  2889.     ctx.mpSourceTexture1 = mpUploadContext->GetD3DTexture();
  2890.     ctx.mpSourceTexture2 = NULL;
  2891.     ctx.mpSourceTexture3 = NULL;
  2892.     ctx.mpInterpFilterH = NULL;
  2893.     ctx.mpInterpFilterV = NULL;
  2894.     ctx.mSourceW = mSource.pixmap.w;
  2895.     ctx.mSourceH = mSource.pixmap.h;
  2896.  
  2897.     D3DSURFACE_DESC desc;
  2898.  
  2899.     HRESULT hr = ctx.mpSourceTexture1->GetLevelDesc(0, &desc);
  2900.     if (FAILED(hr))
  2901.         return false;
  2902.  
  2903.     ctx.mSourceTexW = desc.Width;
  2904.     ctx.mSourceTexH = desc.Height;
  2905.     ctx.mInterpHTexW = 1;
  2906.     ctx.mInterpHTexH = 1;
  2907.     ctx.mInterpVTexW = 1;
  2908.     ctx.mInterpVTexH = 1;
  2909.     ctx.mFieldOffset = 0.0f;
  2910.     ctx.mDefaultUVScaleCorrectionX = 1.0f;
  2911.     ctx.mDefaultUVScaleCorrectionY = 1.0f;
  2912.     ctx.mbHighPrecision = mbHighPrecision;
  2913.  
  2914.     if (updateMode & kModeBobEven)
  2915.         ctx.mFieldOffset = -1.0f;
  2916.     else if (updateMode & kModeBobOdd)
  2917.         ctx.mFieldOffset = +1.0f;
  2918.  
  2919.     vdrefptr<IDirect3DSurface9> pRTMain;
  2920.  
  2921.     mpManager->SetSwapChainActive(NULL);
  2922.  
  2923.     if (mpSwapChain) {
  2924.         IDirect3DSwapChain9 *sc = mpSwapChain->GetD3DSwapChain();
  2925.         hr = sc->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, ~pRTMain);
  2926.         if (FAILED(hr))
  2927.             return false;
  2928.     } else {
  2929.         mpManager->SetSwapChainActive(NULL);
  2930.         mpD3DDevice->GetRenderTarget(0, ~pRTMain);
  2931.     }
  2932.  
  2933.     mbSwapChainImageValid = false;
  2934.  
  2935.     bool bSuccess = false;
  2936.  
  2937.     if (mColorOverride) {
  2938.         mpManager->SetSwapChainActive(mpSwapChain);
  2939.  
  2940.         D3DRECT rClear;
  2941.         rClear.x1 = rClient.left;
  2942.         rClear.y1 = rClient.top;
  2943.         rClear.x2 = rClient.right;
  2944.         rClear.y2 = rClient.bottom;
  2945.         HRESULT hr = mpD3DDevice->Clear(1, &rClear, D3DCLEAR_TARGET, mColorOverride, 0.0f, 0);
  2946.  
  2947.         bSuccess = SUCCEEDED(hr);
  2948.     } else if (mbCubicInitialized &&
  2949.         (uint32)rClient.right <= pparms.BackBufferWidth &&
  2950.         (uint32)rClient.bottom <= pparms.BackBufferHeight &&
  2951.         (uint32)mSource.pixmap.w <= pparms.BackBufferWidth &&
  2952.         (uint32)mSource.pixmap.h <= pparms.BackBufferHeight
  2953.         )
  2954.     {
  2955.         int cubicMode = mCubicMode;
  2956.  
  2957.         if (cubicMode == VDVideoDisplayDX9Manager::kCubicUsePS1_1Path || cubicMode == VDVideoDisplayDX9Manager::kCubicUsePS1_4Path) {
  2958.             if (!InitBicubicPS2Filters(rClient.right, rClient.bottom))
  2959.                 cubicMode = VDVideoDisplayDX9Manager::kCubicUseFF3Path;
  2960.             else {
  2961.                 ctx.mpInterpFilterH = mpD3DInterpFilterTextureH;
  2962.                 ctx.mpInterpFilterV = mpD3DInterpFilterTextureV;
  2963.                 ctx.mInterpHTexW = mInterpFilterHTexSize;
  2964.                 ctx.mInterpHTexH = 1;
  2965.                 ctx.mInterpVTexW = mInterpFilterVTexSize;
  2966.                 ctx.mInterpVTexH = 1;
  2967.             }
  2968.         }
  2969.  
  2970.         if (mbHighPrecision && mpVideoManager->Is16FEnabled()) {
  2971.             bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bicubic_2_0, pRTMain);
  2972.         } else {
  2973.             switch(cubicMode) {
  2974.             case VDVideoDisplayDX9Manager::kCubicUsePS1_4Path:
  2975.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bicubic1_4, pRTMain);
  2976.                 break;
  2977.             case VDVideoDisplayDX9Manager::kCubicUsePS1_1Path:
  2978.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bicubic1_1, pRTMain);
  2979.                 break;
  2980.             case VDVideoDisplayDX9Manager::kCubicUseFF3Path:
  2981.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bicubicFF3, pRTMain);
  2982.                 break;
  2983.             case VDVideoDisplayDX9Manager::kCubicUseFF2Path:
  2984.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bicubicFF2, pRTMain);
  2985.                 break;
  2986.             }
  2987.         }
  2988.     } else {
  2989.         if (mbHighPrecision && mpVideoManager->Is16FEnabled()) {
  2990.             if (mPreferredFilter == kFilterPoint)
  2991.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_point_2_0, pRTMain);
  2992.             else
  2993.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bilinear_2_0, pRTMain);
  2994.         } else {
  2995.             if (mPreferredFilter == kFilterPoint)
  2996.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_point, pRTMain);
  2997.             else
  2998.                 bSuccess = mpVideoManager->RunEffect(ctx, rClient, g_technique_bilinear, pRTMain);
  2999.         }
  3000.     }
  3001.  
  3002.     pRTMain = NULL;
  3003.  
  3004.     if (mbDisplayDebugInfo && mpFontRenderer) {
  3005.         if (mpManager->BeginScene() && mpFontRenderer->Begin()) {
  3006.             const char *modestr = "point";
  3007.  
  3008.             switch(mode) {
  3009.                 case kFilterBilinear:
  3010.                     modestr = "bilinear";
  3011.                     break;
  3012.                 case kFilterBicubic:
  3013.                     modestr = "bicubic";
  3014.                     break;
  3015.             }
  3016.  
  3017.             GetFormatString(mSource, mFormatString);
  3018.             mDebugString.sprintf("Direct3D9 minidriver - %s (%s%s)  Average present time: %6.2fms", mFormatString.c_str(), modestr, mbHighPrecision && mpVideoManager->Is16FEnabled() ? "-16F" : "", mPresentHistory.mAveragePresentTime * 1000.0);
  3019.             mpFontRenderer->DrawTextLine(10, rClient.bottom - 40, 0xFFFFFF00, 0, mDebugString.c_str());
  3020.  
  3021.             mDebugString.sprintf("Target scanline: %7.2f  Average bracket [%7.2f,%7.2f]  Last bracket [%4d,%4d]  Poll count %5d"
  3022.                     , mPresentHistory.mScanlineTarget
  3023.                     , mPresentHistory.mAverageStartScanline
  3024.                     , mPresentHistory.mAverageEndScanline
  3025.                     , mPresentHistory.mLastBracketY1
  3026.                     , mPresentHistory.mLastBracketY2
  3027.                     , mPresentHistory.mPollCount);
  3028.             mPresentHistory.mPollCount = 0;
  3029.             mpFontRenderer->DrawTextLine(10, rClient.bottom - 20, 0xFFFFFF00, 0, mDebugString.c_str());
  3030.  
  3031.             mpFontRenderer->End();
  3032.         }
  3033.     }
  3034.  
  3035.     if (bSuccess && !mpManager->EndScene())
  3036.         bSuccess = false;
  3037.  
  3038.     mpManager->Flush();
  3039.     mpManager->SetSwapChainActive(NULL);
  3040.  
  3041.     hr = E_FAIL;
  3042.  
  3043.     if (!bSuccess) {
  3044.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Render failed -- applying boot to the head.\n");
  3045.  
  3046.         // TODO: Need to free all DEFAULT textures before proceeding
  3047.  
  3048.         if (!mpManager->Reset())
  3049.             return false;
  3050.  
  3051.     } else {
  3052.         mbSwapChainImageValid = true;
  3053.         mbSwapChainPresentPending = true;
  3054.         mbSwapChainPresentPolling = false;
  3055.     }
  3056.  
  3057.     return bSuccess;
  3058. }
  3059.  
  3060. bool VDVideoDisplayMinidriverDX9::UpdateScreen(const RECT& rClient, UpdateMode updateMode, bool polling) {
  3061.     if (!mbSwapChainImageValid)
  3062.         return false;
  3063.  
  3064.     HRESULT hr;
  3065.     if (mbFullScreen)
  3066.         hr = mpManager->PresentFullScreen(!polling);
  3067.     else {
  3068.         hr = mpManager->PresentSwapChain(mpSwapChain, &rClient, mhwnd, (updateMode & kModeVSync) != 0, !polling || !mbSwapChainPresentPolling, polling, mSyncDelta, mPresentHistory);
  3069.         mbSwapChainPresentPolling = false;
  3070.     }
  3071.  
  3072.     if (hr == S_FALSE)
  3073.         return true;
  3074.  
  3075.     // Workaround for Windows Vista DWM composition chain not updating.
  3076.     if (!mbFullScreen && mbFirstPresent) {
  3077.         SetWindowPos(mhwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
  3078.         mbFirstPresent = false;
  3079.     }
  3080.  
  3081.     mbSwapChainPresentPending = false;
  3082.     mbSwapChainPresentPolling = false;
  3083.     VDASSERT(!mPresentHistory.mbPresentPending);
  3084.  
  3085.     if (FAILED(hr)) {
  3086.         VDDEBUG_DX9DISP("VideoDisplay/DX9: Render failed -- applying boot to the head.\n");
  3087.  
  3088.         // TODO: Need to free all DEFAULT textures before proceeding
  3089.  
  3090.         if (!mpManager->Reset())
  3091.             return false;
  3092.     } else
  3093.         mSource.mpCB->RequestNextFrame();
  3094.  
  3095.     return true;
  3096. }
  3097.