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 / displaygl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  34.5 KB  |  1,188 lines

  1. #include <windows.h>
  2. #include <vd2/system/profile.h>
  3. #include <vd2/system/vdstl.h>
  4. #include <vd2/system/vdalloc.h>
  5. #include <vd2/system/math.h>
  6. #include <vd2/system/w32assist.h>
  7. #include <vd2/Kasumi/pixmap.h>
  8. #include <vd2/Riza/opengl.h>
  9. #include "displaydrv.h"
  10.  
  11. #define VDDEBUG_DISP (void)sizeof printf
  12. //#define VDDEBUG_DISP VDDEBUG
  13.  
  14. ///////////////////////////////////////////////////////////////////////////
  15.  
  16. namespace {
  17.     const char kFPCubic1[]=
  18.         "!!ARBfp1.0\n"
  19. #if 1
  20.         "TEMP pix0;\n"
  21.         "TEMP pix1;\n"
  22.         "TEMP pix2;\n"
  23.         "TEMP filt;\n"
  24.         "TEMP tcen;\n"
  25.         "TEMP r0;\n"
  26.         "PARAM uvscale = program.local[0];\n"
  27.         "PARAM scale = {-0.1875, 0.375, 0, 0};\n"
  28.         "TEX filt, fragment.texcoord[3], texture[3], 2D;\n"
  29.         "MAD tcen, filt.g, uvscale, fragment.texcoord[1];\n"
  30.         "TEX pix0, fragment.texcoord[0], texture[0], 2D;\n"
  31.         "TEX pix1, tcen, texture[1], 2D;\n"
  32.         "TEX pix2, fragment.texcoord[2], texture[2], 2D;\n"
  33.  
  34.         // (pix0+pix2)*filt.b*0.75/4 + pix1*(filt.b*0.75/2 + 1)
  35.         "MUL r0, pix0, scale.r;\n"
  36.         "MAD r0, pix2, scale.r, r0;\n"
  37.         "MAD r0, pix1, scale.g, r0;\n"
  38.         "MAD result.color.rgb, r0, filt.r, pix1;\n"
  39.         "MOV result.color.a, pix1.a;\n"
  40. #else
  41.         "PARAM one = {1,1,1,1};\n"
  42.         "TEMP foo;\n"
  43.         "TEX foo, fragment.texcoord[3], texture[3], 1D;\n"
  44.         "ADD result.color, one, -foo;\n"
  45. #endif
  46.         "END\n";
  47. }
  48.  
  49. ///////////////////////////////////////////////////////////////////////////
  50.  
  51. class VDVideoTextureTilePatternOpenGL {
  52. public:
  53.     struct TileInfo {
  54.         float    mInvU;
  55.         float    mInvV;
  56.         int        mSrcW;
  57.         int        mSrcH;
  58.     };
  59.  
  60.     VDVideoTextureTilePatternOpenGL() : mTexture(0), mbPhase(false) {}
  61.     void Init(VDOpenGLBinding *pgl, int w, int h, bool bPackedPixelsSupported, bool bEdgeClampSupported);
  62.     void Shutdown(VDOpenGLBinding *pgl);
  63.  
  64.     void ReinitFiltering(VDOpenGLBinding *pgl, IVDVideoDisplayMinidriver::FilterMode mode);
  65.  
  66.     bool IsInited() const { return mTexture != 0; }
  67.  
  68.     void Flip();
  69.     GLuint GetTexture() const { return mTexture; }
  70.     const TileInfo& GetTileInfo() const { return mTileInfo; }
  71.  
  72. protected:
  73.     int            mTextureTilesW;
  74.     int            mTextureTilesH;
  75.     int            mTextureSize;
  76.     double        mTextureSizeInv;
  77.     int            mTextureLastW;
  78.     int            mTextureLastH;
  79.     double        mTextureLastWInvPow2;
  80.     double        mTextureLastHInvPow2;
  81.     GLuint        mTexture;
  82.     TileInfo    mTileInfo;
  83.  
  84.     bool        mbPackedPixelsSupported;
  85.     bool        mbEdgeClampSupported;
  86.     bool        mbPhase;
  87. };
  88.  
  89. void VDVideoTextureTilePatternOpenGL::Init(VDOpenGLBinding *pgl, int w, int h, bool bPackedPixelsSupported, bool bEdgeClampSupported) {
  90.     mbPackedPixelsSupported        = bPackedPixelsSupported;
  91.     mbEdgeClampSupported        = bEdgeClampSupported;
  92.  
  93.     GLint maxsize;
  94.     pgl->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
  95.  
  96.     mTextureSize    = maxsize;
  97.     mTextureSizeInv    = 1.0 / maxsize;
  98.     mTextureTilesW    = 1;
  99.     mTextureTilesH    = 1;
  100.  
  101.     int ntiles = 1;
  102.     int xlast = w;
  103.     int ylast = h;
  104.     int xlasttex = 1;
  105.     int ylasttex = 1;
  106.  
  107.     while(xlasttex < xlast)
  108.         xlasttex += xlasttex;
  109.     while(ylasttex < ylast)
  110.         ylasttex += ylasttex;
  111.  
  112.     int largestW = xlasttex;
  113.     int largestH = ylasttex;
  114.  
  115.     mTextureLastW = xlast;
  116.     mTextureLastH = ylast;
  117.     mTextureLastWInvPow2    = 1.0 / xlasttex;
  118.     mTextureLastHInvPow2    = 1.0 / ylasttex;
  119.  
  120.     pgl->glGenTextures(1, &mTexture);
  121.  
  122.     vdautoblockptr zerobuffer(malloc(4 * largestW * largestH));
  123.     memset(zerobuffer, 0, 4 * largestW * largestH);
  124.  
  125.     pgl->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  126.     pgl->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  127.  
  128.  
  129.     int tile = 0;
  130.     int y = 0;
  131.     int x = 0;
  132.     int texw = xlasttex;
  133.     int texh = ylasttex;
  134.  
  135.     pgl->glBindTexture(GL_TEXTURE_2D, mTexture);
  136.  
  137.     if (mbEdgeClampSupported) {
  138.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE_EXT);
  139.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE_EXT);
  140.     } else {
  141.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  142.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  143.  
  144.         static const float black[4]={0.f,0.f,0.f,0.f};
  145.         pgl->glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, black);
  146.     }
  147.  
  148.     pgl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texw, texh, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
  149.  
  150.     mTileInfo.mInvU        = 1.0f / texw;
  151.     mTileInfo.mInvV        = 1.0f / texh;
  152.     mTileInfo.mSrcW        = xlast;
  153.     mTileInfo.mSrcH        = ylast;
  154.  
  155.     Flip();
  156. }
  157.  
  158. void VDVideoTextureTilePatternOpenGL::Shutdown(VDOpenGLBinding *pgl) {
  159.     if (mTexture) {
  160.         pgl->glDeleteTextures(1, &mTexture);
  161.         mTexture = 0;
  162.     }
  163. }
  164.  
  165. void VDVideoTextureTilePatternOpenGL::ReinitFiltering(VDOpenGLBinding *pgl, IVDVideoDisplayMinidriver::FilterMode mode) {
  166.     pgl->glBindTexture(GL_TEXTURE_2D, mTexture);
  167.  
  168.     if (mode == IVDVideoDisplayMinidriver::kFilterPoint)
  169.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  170.     else
  171.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  172.  
  173.     if (mode == IVDVideoDisplayMinidriver::kFilterPoint)
  174.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  175.     else
  176.         pgl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  177. }
  178.  
  179. void VDVideoTextureTilePatternOpenGL::Flip() {
  180.     mbPhase = !mbPhase;
  181. }
  182.  
  183. ///////////////////////////////////////////////////////////////////////////
  184.  
  185. class VDVideoDisplayMinidriverOpenGL : public VDVideoDisplayMinidriver {
  186. public:
  187.     VDVideoDisplayMinidriverOpenGL();
  188.     ~VDVideoDisplayMinidriverOpenGL();
  189.  
  190.     bool Init(HWND hwnd, const VDVideoDisplaySourceInfo& info);
  191.     void Shutdown();
  192.  
  193.     bool ModifySource(const VDVideoDisplaySourceInfo& info);
  194.  
  195.     bool IsValid() { return mbValid; }
  196.     void SetFilterMode(FilterMode mode);
  197.  
  198.     bool Resize();
  199.     bool Update(UpdateMode);
  200.     void Refresh(UpdateMode);
  201.     bool Paint(HDC hdc, const RECT& rClient, UpdateMode mode) { return true; }
  202.  
  203. protected:
  204.     void Upload(const VDPixmap& source, VDVideoTextureTilePatternOpenGL& texPattern);
  205.  
  206.     static ATOM VDVideoDisplayMinidriverOpenGL::Register();
  207.     static LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  208.     LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
  209.  
  210.     bool OnOpenGLInit();
  211.     void OnDestroy();
  212.     void OnPaint();
  213.     bool InitBicubic();
  214.     void ShutdownBicubic();
  215.     void UpdateCubicTextures(uint32 w, uint32 h);
  216.     void UpdateCubicTexture(uint32 dw, uint32 sw);
  217.  
  218.     enum {
  219.         kTimerId_Refresh = 100
  220.     };
  221.     
  222.     HWND        mhwnd;
  223.     HWND        mhwndOGL;
  224.     bool        mbValid;
  225.     bool        mbVsync;
  226.     bool        mbFirstPresent;
  227.     bool        mbVerticalFlip;
  228.     UpdateMode    mRefreshMode;
  229.     int            mRefreshIdleCount;
  230.     bool        mbRefreshIdleTimerActive;
  231.     bool        mbRefreshQueued;
  232.     bool        mbCubicPossible;
  233.  
  234.     GLuint        mFPCubic;
  235.     GLuint        mCubicFramebuffer;
  236.     GLuint        mCubicFilterTempTex;
  237.     GLuint        mCubicFilterTempTexWidth;
  238.     GLuint        mCubicFilterTempTexHeight;
  239.     GLuint        mCubicFilterH;
  240.     uint32        mCubicFilterHSize;
  241.     uint32        mCubicFilterHTexSize;
  242.     GLuint        mCubicFilterV;
  243.     uint32        mCubicFilterVSize;
  244.     uint32        mCubicFilterVTexSize;
  245.  
  246.     GLuint        mFontBase;
  247.  
  248.     FilterMode    mPreferredFilter;
  249.     VDVideoTextureTilePatternOpenGL        mTexPattern[2];
  250.     VDVideoDisplaySourceInfo            mSource;
  251.  
  252.     VDRTProfileChannel    mProfChan;
  253.     VDOpenGLBinding    mGL;
  254. };
  255.  
  256. #define MYWM_OGLINIT        (WM_USER + 0x180)
  257.  
  258. IVDVideoDisplayMinidriver *VDCreateVideoDisplayMinidriverOpenGL() {
  259.     return new VDVideoDisplayMinidriverOpenGL;
  260. }
  261.  
  262. VDVideoDisplayMinidriverOpenGL::VDVideoDisplayMinidriverOpenGL()
  263.     : mhwndOGL(0)
  264.     , mbValid(false)
  265.     , mbVsync(false)
  266.     , mbFirstPresent(false)
  267.     , mbVerticalFlip(false)
  268.     , mRefreshMode(kModeNone)
  269.     , mRefreshIdleCount(0)
  270.     , mbRefreshIdleTimerActive(false)
  271.     , mbRefreshQueued(false)
  272.     , mFPCubic(0)
  273.     , mCubicFramebuffer(0)
  274.     , mCubicFilterTempTex(0)
  275.     , mCubicFilterTempTexWidth(0)
  276.     , mCubicFilterTempTexHeight(0)
  277.     , mCubicFilterH(0)
  278.     , mCubicFilterHSize(0)
  279.     , mCubicFilterHTexSize(0)
  280.     , mCubicFilterV(0)
  281.     , mCubicFilterVTexSize(0)
  282.     , mFontBase(0)
  283.     , mPreferredFilter(kFilterAnySuitable)
  284.     , mProfChan("GLDisplay")
  285. {
  286.     memset(&mSource, 0, sizeof mSource);
  287. }
  288.  
  289. VDVideoDisplayMinidriverOpenGL::~VDVideoDisplayMinidriverOpenGL() {
  290. }
  291.  
  292. bool VDVideoDisplayMinidriverOpenGL::Init(HWND hwnd, const VDVideoDisplaySourceInfo& info) {
  293.     mSource = info;
  294.     mhwnd = hwnd;
  295.  
  296.     // Format check....
  297.     switch(info.pixmap.format) {
  298.         case nsVDPixmap::kPixFormat_XRGB1555:
  299.         case nsVDPixmap::kPixFormat_RGB565:
  300.         case nsVDPixmap::kPixFormat_RGB888:
  301.         case nsVDPixmap::kPixFormat_XRGB8888:
  302.             break;
  303.  
  304.         default:
  305.             return false;
  306.     }
  307.  
  308.     // OpenGL doesn't allow upside-down texture uploads, so we simply
  309.     // upload the surface inverted and then reinvert on display.
  310.     mbVerticalFlip = false;
  311.     if (mSource.pixmap.pitch < 0) {
  312.         mSource.pixmap.data = (char *)mSource.pixmap.data + mSource.pixmap.pitch*(mSource.pixmap.h - 1);
  313.         mSource.pixmap.pitch = -mSource.pixmap.pitch;
  314.         mbVerticalFlip = true;
  315.     }
  316.  
  317.     RECT r;
  318.     GetClientRect(mhwnd, &r);
  319.  
  320.     static ATOM wndClass = Register();
  321.  
  322.     if (!mGL.Init())
  323.         return false;
  324.  
  325.     // We have to create a separate window because the NVIDIA driver subclasses the
  326.     // window and doesn't unsubclass it even after the OpenGL context is deleted.
  327.     // If we use the main window instead then the app will bomb the moment we unload
  328.     // OpenGL.
  329.  
  330.     mhwndOGL = CreateWindowEx(WS_EX_TRANSPARENT, (LPCSTR)wndClass, "", WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, r.right, r.bottom, mhwnd, NULL, VDGetLocalModuleHandleW32(), this);
  331.     if (!mhwndOGL)
  332.         return false;
  333.  
  334.     if (!SendMessage(mhwndOGL, MYWM_OGLINIT, 0, 0)) {
  335.         DestroyWindow(mhwndOGL);
  336.         mhwndOGL = 0;
  337.         return false;
  338.     }
  339.  
  340.     mbValid = false;
  341.     mbFirstPresent = true;
  342.     return true;
  343. }
  344.  
  345. void VDVideoDisplayMinidriverOpenGL::Shutdown() {
  346.     ShutdownBicubic();
  347.  
  348.     if (mhwndOGL) {
  349.         DestroyWindow(mhwndOGL);
  350.         mhwndOGL = NULL;
  351.     }
  352.  
  353.     mGL.Shutdown();
  354.     mbValid = false;
  355.  
  356.     mRefreshIdleCount = 0;
  357.     mbRefreshIdleTimerActive = false;
  358.     mbRefreshQueued = false;
  359. }
  360.  
  361. bool VDVideoDisplayMinidriverOpenGL::ModifySource(const VDVideoDisplaySourceInfo& info) {
  362.     if (!mGL.IsInited())
  363.         return false;
  364.  
  365.     if (info.pixmap.w == mSource.pixmap.w && info.pixmap.h == mSource.pixmap.h && info.pixmap.format == mSource.pixmap.format && info.bInterlaced == mSource.bInterlaced) {
  366.         mSource = info;
  367.         // OpenGL doesn't allow upside-down texture uploads, so we simply
  368.         // upload the surface inverted and then reinvert on display.
  369.         mbVerticalFlip = false;
  370.         if (mSource.pixmap.pitch < 0) {
  371.             mSource.pixmap.data = (char *)mSource.pixmap.data + mSource.pixmap.pitch*(mSource.pixmap.h - 1);
  372.             mSource.pixmap.pitch = -mSource.pixmap.pitch;
  373.             mbVerticalFlip = true;
  374.         }
  375.         return true;
  376.     }
  377.  
  378.     return false;
  379. }
  380.  
  381. void VDVideoDisplayMinidriverOpenGL::SetFilterMode(FilterMode mode) {
  382.     if (mPreferredFilter == mode)
  383.         return;
  384.  
  385.     mPreferredFilter = mode;
  386.  
  387.     if (mhwndOGL) {
  388.         if (HDC hdc = GetDC(mhwndOGL)) {
  389.             if (mGL.Begin(hdc)) {
  390.                 mTexPattern[0].ReinitFiltering(&mGL, mode);
  391.                 mTexPattern[1].ReinitFiltering(&mGL, mode);
  392.                 mGL.wglMakeCurrent(NULL, NULL);
  393.             }
  394.         }
  395.     }
  396. }
  397.  
  398. bool VDVideoDisplayMinidriverOpenGL::Resize() {
  399.     if (mhwndOGL) {
  400.         RECT r;
  401.  
  402.         GetClientRect(mhwnd, &r);
  403.         SetWindowPos(mhwndOGL, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS);
  404.     }
  405.  
  406.     return true;
  407. }
  408.  
  409. bool VDVideoDisplayMinidriverOpenGL::Update(UpdateMode mode) {
  410.     if (!mGL.IsInited())
  411.         return false;
  412.  
  413.     if (!mSource.pixmap.data)
  414.         return false;
  415.  
  416.     if (HDC hdc = GetDC(mhwndOGL)) {
  417.         if (mGL.Begin(hdc)) {
  418.             VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  419.  
  420.             if (mSource.bInterlaced) {
  421.                 uint32 fieldmode = (mode & kModeFieldMask);
  422.  
  423.                 if (fieldmode == kModeAllFields || fieldmode == kModeEvenField) {
  424.                     VDPixmap evenFieldSrc(mSource.pixmap);
  425.  
  426.                     evenFieldSrc.h = (evenFieldSrc.h+1) >> 1;
  427.                     evenFieldSrc.pitch += evenFieldSrc.pitch;
  428.  
  429.                     Upload(evenFieldSrc, mTexPattern[0]);
  430.                 }
  431.                 if (fieldmode == kModeAllFields || fieldmode == kModeOddField) {
  432.                     VDPixmap oddFieldSrc(mSource.pixmap);
  433.  
  434.                     oddFieldSrc.data = (char *)oddFieldSrc.data + oddFieldSrc.pitch;
  435.                     oddFieldSrc.h = (oddFieldSrc.h+1) >> 1;
  436.                     oddFieldSrc.pitch += oddFieldSrc.pitch;
  437.  
  438.                     Upload(oddFieldSrc, mTexPattern[1]);
  439.                 }
  440.             } else {
  441.                 Upload(mSource.pixmap, mTexPattern[0]);
  442.             }
  443.  
  444.             VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  445.  
  446.             mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  447.             mGL.End();
  448.         }
  449.  
  450.         mbValid = true;
  451.  
  452.         ReleaseDC(mhwndOGL, hdc);
  453.     }
  454.  
  455.     return true;
  456. }
  457.  
  458. void VDVideoDisplayMinidriverOpenGL::Refresh(UpdateMode updateMode) {
  459.     if (mbValid) {
  460.         InvalidateRect(mhwndOGL, NULL, FALSE);
  461.         mRefreshMode = updateMode;
  462.         mbRefreshQueued = true;
  463.         mRefreshIdleCount = 0;
  464.         if (!mbRefreshIdleTimerActive) {
  465.             mbRefreshIdleTimerActive = true;
  466.  
  467.             VDVERIFY(SetTimer(mhwndOGL, kTimerId_Refresh, 1000, NULL));
  468.         }
  469.  
  470.         PostMessage(mhwndOGL, WM_TIMER, kTimerId_Refresh, 0);
  471.     }
  472. }
  473.  
  474. void VDVideoDisplayMinidriverOpenGL::Upload(const VDPixmap& source, VDVideoTextureTilePatternOpenGL& texPattern) {
  475.     mProfChan.Begin(0xe0e0e0, "Upload");
  476.  
  477.     mGL.glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  478.     switch(source.format) {
  479.     case nsVDPixmap::kPixFormat_XRGB1555:
  480.     case nsVDPixmap::kPixFormat_RGB565:
  481.         mGL.glPixelStorei(GL_UNPACK_ROW_LENGTH, source.pitch >> 1);
  482.         break;
  483.     case nsVDPixmap::kPixFormat_RGB888:
  484.         mGL.glPixelStorei(GL_UNPACK_ROW_LENGTH, source.pitch / 3);
  485.         break;
  486.     case nsVDPixmap::kPixFormat_XRGB8888:
  487.         mGL.glPixelStorei(GL_UNPACK_ROW_LENGTH, source.pitch >> 2);
  488.         break;
  489.     }
  490.  
  491.     texPattern.Flip();
  492.  
  493.     const VDVideoTextureTilePatternOpenGL::TileInfo& tile = texPattern.GetTileInfo();
  494.  
  495.     mGL.glBindTexture(GL_TEXTURE_2D, texPattern.GetTexture());
  496.  
  497.     switch(source.format) {
  498.     case nsVDPixmap::kPixFormat_XRGB1555:
  499.         mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tile.mSrcW, tile.mSrcH, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, (const char *)source.data);
  500.         break;
  501.     case nsVDPixmap::kPixFormat_RGB565:
  502.         mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tile.mSrcW, tile.mSrcH, GL_BGR_EXT, GL_UNSIGNED_SHORT_5_6_5_REV, (const char *)source.data);
  503.         break;
  504.     case nsVDPixmap::kPixFormat_RGB888:
  505.         mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tile.mSrcW, tile.mSrcH, GL_BGR_EXT, GL_UNSIGNED_BYTE, (const char *)source.data);
  506.         break;
  507.     case nsVDPixmap::kPixFormat_XRGB8888:
  508.         mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tile.mSrcW, tile.mSrcH, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (const char *)source.data);
  509.         break;
  510.     }
  511.  
  512.     mProfChan.End();
  513. }
  514.  
  515. ///////////////////////////////////////////////////////////////////////////
  516.  
  517. ATOM VDVideoDisplayMinidriverOpenGL::Register() {
  518.     WNDCLASS wc;
  519.  
  520.     wc.style            = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
  521.     wc.lpfnWndProc        = StaticWndProc;
  522.     wc.cbClsExtra        = 0;
  523.     wc.cbWndExtra        = sizeof(VDVideoDisplayMinidriverOpenGL *);
  524.     wc.hInstance        = VDGetLocalModuleHandleW32();
  525.     wc.hIcon            = 0;
  526.     wc.hCursor            = 0;
  527.     wc.hbrBackground    = 0;
  528.     wc.lpszMenuName        = 0;
  529.     wc.lpszClassName    = "phaeronOpenGLVideoDisplay";
  530.  
  531.     return RegisterClass(&wc);
  532. }
  533.  
  534. LRESULT CALLBACK VDVideoDisplayMinidriverOpenGL::StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  535.     VDVideoDisplayMinidriverOpenGL *pThis = (VDVideoDisplayMinidriverOpenGL *)GetWindowLongPtr(hwnd, 0);
  536.  
  537.     switch(msg) {
  538.     case WM_NCCREATE:
  539.         pThis = (VDVideoDisplayMinidriverOpenGL *)((LPCREATESTRUCT)lParam)->lpCreateParams;
  540.         SetWindowLongPtr(hwnd, 0, (DWORD_PTR)pThis);
  541.         pThis->mhwndOGL = hwnd;
  542.         break;
  543.     }
  544.  
  545.     return pThis ? pThis->WndProc(msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam);
  546. }
  547.  
  548. LRESULT VDVideoDisplayMinidriverOpenGL::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) {
  549.     switch(msg) {
  550.     case MYWM_OGLINIT:
  551.         return OnOpenGLInit();
  552.     case WM_DESTROY:
  553.         OnDestroy();
  554.         break;
  555.     case WM_PAINT:
  556.         OnPaint();
  557.         return 0;
  558.     case WM_NCHITTEST:
  559.         return HTTRANSPARENT;
  560.     case WM_TIMER:
  561.         if (wParam == kTimerId_Refresh) {
  562.             if (mbRefreshQueued) {
  563.                 mRefreshIdleCount = 0;
  564.                 mbRefreshQueued = false;
  565.                 UpdateWindow(mhwndOGL);
  566.             } else if (++mRefreshIdleCount >= 5) {
  567.                 mRefreshIdleCount = 0;
  568.                 mbRefreshIdleTimerActive = false;
  569.                 VDVERIFY(KillTimer(mhwndOGL, kTimerId_Refresh));
  570.             }
  571.         }
  572.         break;
  573.     }
  574.  
  575.     return DefWindowProc(mhwndOGL, msg, wParam, lParam);
  576. }
  577.  
  578. bool VDVideoDisplayMinidriverOpenGL::OnOpenGLInit() {
  579.     if (HDC hdc = GetDC(mhwndOGL)) {
  580.         if (mGL.Attach(hdc, 8, 0, 0, 0, true)) {
  581.             if (mGL.Begin(hdc)) {
  582.                 VDDEBUG_DISP("VideoDisplay: OpenGL version string: [%s]\n", mGL.glGetString(GL_VERSION));
  583.  
  584.                 const GLubyte *pExtensions = mGL.glGetString(GL_EXTENSIONS);
  585.  
  586.                 vdfastvector<char> extstr(strlen((const char *)pExtensions)+1);
  587.                 std::copy(pExtensions, pExtensions + extstr.size(), extstr.data());
  588.  
  589.                 char *s = extstr.data();
  590.  
  591.                 bool bPackedPixelsSupported = false;
  592.                 bool bEdgeClampSupported = false;
  593.  
  594.                 while(const char *tok = strtok(s, " ")) {
  595.                     if (!strcmp(tok, "GL_EXT_packed_pixels"))
  596.                         bPackedPixelsSupported = true;
  597.                     else if (!strcmp(tok, "GL_EXT_texture_edge_clamp"))
  598.                         bEdgeClampSupported = true;
  599.                     s = NULL;
  600.                 }
  601.  
  602.                 if (mSource.bInterlaced) {
  603.                     mTexPattern[0].Init(&mGL, mSource.pixmap.w, (mSource.pixmap.h+1)>>1, bPackedPixelsSupported, bEdgeClampSupported);
  604.                     mTexPattern[1].Init(&mGL, mSource.pixmap.w, mSource.pixmap.h>>1, bPackedPixelsSupported, bEdgeClampSupported);
  605.                     mTexPattern[1].ReinitFiltering(&mGL, mPreferredFilter);
  606.                 } else
  607.                     mTexPattern[0].Init(&mGL, mSource.pixmap.w, mSource.pixmap.h, bPackedPixelsSupported, bEdgeClampSupported);
  608.                 mTexPattern[0].ReinitFiltering(&mGL, mPreferredFilter);
  609.  
  610.                 VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  611.  
  612.                 mbCubicPossible = InitBicubic();
  613.                 if (!mbCubicPossible)
  614.                     ShutdownBicubic();
  615.  
  616.                 mbVsync = false;
  617.                 if (mGL.EXT_swap_control)
  618.                     mGL.wglSwapIntervalEXT(0);
  619.  
  620.                 mFontBase = mGL.glGenLists(96);
  621.  
  622.                 SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
  623.                 mGL.wglUseFontBitmapsA(hdc, 32, 96, mFontBase);
  624.  
  625.                 VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  626.  
  627.                 mGL.End();
  628.                 ReleaseDC(mhwndOGL, hdc);
  629.  
  630.                 VDDEBUG_DISP("VideoDisplay: Using OpenGL for %dx%d display.\n", mSource.pixmap.w, mSource.pixmap.h);
  631.                 return true;
  632.             }
  633.             mGL.Detach();
  634.         }
  635.  
  636.         ReleaseDC(mhwndOGL, hdc);
  637.     }
  638.  
  639.     return false;
  640. }
  641.  
  642. void VDVideoDisplayMinidriverOpenGL::OnDestroy() {
  643.     if (mGL.IsInited()) {
  644.         if (HDC hdc = GetDC(mhwndOGL)) {
  645.             if (mGL.Begin(hdc)) {
  646.                 mTexPattern[0].Shutdown(&mGL);
  647.                 mTexPattern[1].Shutdown(&mGL);
  648.  
  649.                 if (mFontBase) {
  650.                     mGL.glDeleteLists(96, mFontBase);
  651.                     mFontBase = 0;
  652.                 }
  653.  
  654.                 if (mGL.ARB_fragment_program) {
  655.                     if (mFPCubic) {
  656.                         mGL.glDeleteProgramsARB(1, &mFPCubic);
  657.                         mFPCubic = 0;
  658.                     }
  659.                 }
  660.  
  661.                 mGL.End();
  662.             }
  663.         }
  664.  
  665.         mGL.Detach();
  666.     }
  667. }
  668.  
  669. void VDVideoDisplayMinidriverOpenGL::OnPaint() {
  670.     PAINTSTRUCT ps;
  671.     HDC hdc = BeginPaint(mhwndOGL, &ps);
  672.  
  673.     if (!hdc)
  674.         return;
  675.  
  676.     float bobOffset;
  677.  
  678.     if (mRefreshMode & kModeBobEven)
  679.         bobOffset = +1.0f;
  680.     else if (mRefreshMode & kModeBobOdd)
  681.         bobOffset = -1.0f;
  682.     else
  683.         bobOffset = 0.0f;
  684.  
  685.     RECT r;
  686.     GetClientRect(mhwndOGL, &r);
  687.  
  688.     FilterMode mode = mPreferredFilter;
  689.  
  690.     if (mode == kFilterAnySuitable)
  691.         mode = kFilterBicubic;
  692.  
  693.     if (mode == kFilterBicubic && !mbCubicPossible)
  694.         mode = kFilterBilinear;
  695.  
  696.     if (mGL.Begin(hdc)) {
  697.         bool vsync = (mRefreshMode & kModeVSync) != 0;
  698.         if (mbVsync != vsync) {
  699.             mbVsync = vsync;
  700.  
  701.             if (mGL.EXT_swap_control)
  702.                 mGL.wglSwapIntervalEXT(vsync ? 1 : 0);
  703.         }
  704.  
  705.         if (mode == kFilterBicubic)
  706.             UpdateCubicTextures(r.right, r.bottom);
  707.  
  708.         mGL.glViewport(0, 0, r.right, r.bottom);
  709.  
  710.         if (mColorOverride) {
  711.             mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  712.             mGL.glClearColor(
  713.                 (float)(mColorOverride & 0x00ff0000) / (float)0x00ff0000,
  714.                 (float)(mColorOverride & 0x0000ff00) / (float)0x0000ff00,
  715.                 (float)(mColorOverride & 0x000000ff) / (float)0x000000ff,
  716.                 0.0f);
  717.             mGL.glClear(GL_COLOR_BUFFER_BIT);
  718.         } else {
  719.             mGL.glMatrixMode(GL_PROJECTION);
  720.             mGL.glLoadIdentity();
  721.             mGL.glMatrixMode(GL_MODELVIEW);
  722.             mGL.glLoadIdentity();
  723.  
  724.             mGL.glDisable(GL_ALPHA_TEST);
  725.             mGL.glDisable(GL_DEPTH_TEST);
  726.             mGL.glDisable(GL_STENCIL_TEST);
  727.             mGL.glDisable(GL_BLEND);
  728.             mGL.glDisable(GL_CULL_FACE);
  729.             mGL.glEnable(GL_DITHER);
  730.             mGL.glEnable(GL_TEXTURE_2D);
  731.  
  732.             if (mSource.bInterlaced) {
  733.                 const int dstH = r.bottom;
  734.  
  735.                 mGL.glOrtho(0, r.right, mbVerticalFlip ? 0 : dstH, mbVerticalFlip ? dstH : 0, -1, 1);
  736.  
  737.                 for(int field=0; field<2; ++field) {
  738.                     const VDVideoTextureTilePatternOpenGL::TileInfo& tile = mTexPattern[field].GetTileInfo();
  739.  
  740.                     int        w = tile.mSrcW;
  741.                     int        h = tile.mSrcH;
  742.                     double    iw = tile.mInvU;
  743.                     double    ih = tile.mInvV;
  744.  
  745.                     double    px1 = 0.0;
  746.                     double    py1 = 0.0;
  747.                     double    px2 = w;
  748.                     double    py2 = h;
  749.  
  750.                     double    u1 = iw * px1;
  751.                     double    u2 = iw * px2;
  752.  
  753.                     ih *= mSource.pixmap.h / (double)dstH * 0.5;
  754.  
  755.                     mGL.glBindTexture(GL_TEXTURE_2D, mTexPattern[field].GetTexture());
  756.  
  757.                     int ytop    = VDRoundToInt(ceil((py1*2 + field - 0.5) * (dstH / (double)mSource.pixmap.h) - 0.5));
  758.                     int ybottom    = VDRoundToInt(ceil((py2*2 + field - 0.5) * (dstH / (double)mSource.pixmap.h) - 0.5));
  759.  
  760.                     if ((ytop^field) & 1)
  761.                         ++ytop;
  762.  
  763.                     mGL.glBegin(GL_QUADS);
  764.                     mGL.glColor4d(1.0f, 1.0f, 1.0f, 1.0f);
  765.  
  766.                     for(int ydst = ytop; ydst < ybottom; ydst += 2) {
  767.                         mGL.glTexCoord2d(u1, (ydst  -field+0.5)*ih);        mGL.glVertex2d(px1, ydst);
  768.                         mGL.glTexCoord2d(u1, (ydst+1-field+0.5)*ih);        mGL.glVertex2d(px1, ydst+1);
  769.                         mGL.glTexCoord2d(u2, (ydst+1-field+0.5)*ih);        mGL.glVertex2d(px2, ydst+1);
  770.                         mGL.glTexCoord2d(u2, (ydst  -field+0.5)*ih);        mGL.glVertex2d(px2, ydst);
  771.                     }
  772.  
  773.                     mGL.glEnd();
  774.                 }
  775.             } else {
  776.                 const VDVideoTextureTilePatternOpenGL::TileInfo& tile = mTexPattern[0].GetTileInfo();
  777.  
  778.                 int        w = tile.mSrcW;
  779.                 int        h = tile.mSrcH;
  780.                 float    iw = tile.mInvU;
  781.                 float    ih = tile.mInvV;
  782.  
  783.                 GLuint texHandle = mTexPattern[0].GetTexture();
  784.                 mGL.glBindTexture(GL_TEXTURE_2D, texHandle);
  785.  
  786.                 if (mode == kFilterBicubic) {
  787.                     float    px1 = 0;
  788.                     float    py1 = 0;
  789.                     float    px2 = (float)r.right;
  790.                     float    py2 = (float)h;
  791.                     float    u1 = 0;
  792.                     float    v1 = 0.25f * ih * bobOffset;
  793.                     float    u2 = iw * w;
  794.                     float    v2 = ih * h;
  795.                     float    f1 = 0.0f;
  796.                     float    f2 = r.right / (float)mCubicFilterHTexSize;
  797.                     float    px3 = 0;
  798.                     float    py3 = 0;
  799.                     float    px4 = (float)r.right;
  800.                     float    py4 = (float)r.bottom;
  801.                     float    iw2 = 1.0f / mCubicFilterTempTexWidth;
  802.                     float    ih2 = 1.0f / mCubicFilterTempTexHeight;
  803.                     float    u3 = 0;
  804.                     float    v3 = 0;
  805.                     float    u4 = iw2 * (float)r.right;
  806.                     float    v4 = ih2 * (float)h;
  807.                     float    f3 = 0.0f;
  808.                     float    f4 = r.bottom / (float)mCubicFilterVTexSize;
  809.  
  810.                     mGL.glEnable(GL_FRAGMENT_PROGRAM_ARB);
  811.                     mGL.glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, mFPCubic);
  812.  
  813.                     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  814.                     mGL.glEnable(GL_TEXTURE_2D);
  815.                     mGL.glBindTexture(GL_TEXTURE_2D, texHandle);
  816.                     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  817.                     mGL.glEnable(GL_TEXTURE_2D);
  818.                     mGL.glBindTexture(GL_TEXTURE_2D, texHandle);
  819.                     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  820.                     mGL.glEnable(GL_TEXTURE_2D);
  821.                     mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterH);
  822.  
  823.                     mGL.glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, iw*0.5f, 0, 0, 0);
  824.  
  825.                     mGL.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubicFramebuffer);
  826.                     GLenum foo = mGL.glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  827.                     mGL.glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
  828.  
  829.                     mGL.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  830.  
  831.                     float du0 = -iw;
  832.                     float du1 = -0.25f * iw;
  833.                     float du2 = +iw;
  834.  
  835.                     mGL.glLoadIdentity();
  836.                     mGL.glOrtho(0, mCubicFilterTempTexWidth, 0, mCubicFilterTempTexHeight, 0, 1);
  837.                     mGL.glViewport(0, 0, mCubicFilterTempTexWidth, mCubicFilterTempTexHeight);
  838.                     mGL.glClear(GL_COLOR_BUFFER_BIT);
  839.  
  840.                     VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  841.                     mGL.glBegin(GL_QUADS);
  842.  
  843.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1+du0, v1);
  844.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1+du1, v1);
  845.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u1+du2, v1);
  846.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f1, 0.0f);
  847.                     mGL.glVertex2f(px1, py1);
  848.  
  849.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1+du0, v2);
  850.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1+du1, v2);
  851.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u1+du2, v2);
  852.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f1, 0.0f);
  853.                     mGL.glVertex2f(px1, py2);
  854.  
  855.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u2+du0, v2);
  856.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2+du1, v2);
  857.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2+du2, v2);
  858.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f2, 0.0f);
  859.                     mGL.glVertex2f(px2, py2);
  860.  
  861.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u2+du0, v1);
  862.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2+du1, v1);
  863.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2+du2, v1);
  864.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f2, 0.0f);
  865.                     mGL.glVertex2f(px2, py1);
  866.  
  867.                     mGL.glEnd();
  868.                     VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  869.  
  870.                     mGL.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  871.                     VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  872.                     mGL.glDrawBuffer(GL_BACK);
  873.                     VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  874.  
  875.                     mGL.glLoadIdentity();
  876.                     mGL.glOrtho(0, r.right, mbVerticalFlip ? 0 : r.bottom, mbVerticalFlip ? r.bottom : 0, -1, 1);
  877.  
  878.                     mGL.glViewport(0, 0, r.right, r.bottom);
  879.                     mGL.glClear(GL_COLOR_BUFFER_BIT);
  880.                     mGL.glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0, ih2*0.5f, 0, 0);
  881.  
  882.                     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  883.                     mGL.glEnable(GL_TEXTURE_2D);
  884.                     mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterTempTex);
  885.                     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  886.                     mGL.glEnable(GL_TEXTURE_2D);
  887.                     mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterTempTex);
  888.                     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  889.                     mGL.glEnable(GL_TEXTURE_2D);
  890.                     mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterTempTex);
  891.                     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  892.                     mGL.glEnable(GL_TEXTURE_2D);
  893.                     mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterV);
  894.  
  895.                     float dv0 = -ih2;
  896.                     float dv1 = -0.25f * ih2;
  897.                     float dv2 = +ih2;
  898.  
  899.                     mGL.glBegin(GL_QUADS);
  900.  
  901.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u3, v3+dv0);
  902.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v3+dv1);
  903.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u3, v3+dv2);
  904.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f3, 0.0f);
  905.                     mGL.glVertex2f(px3, py3);
  906.  
  907.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u3, v4+dv0);
  908.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v4+dv1);
  909.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u3, v4+dv2);
  910.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f4, 0.0f);
  911.                     mGL.glVertex2f(px3, py4);
  912.  
  913.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u4, v4+dv0);
  914.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u4, v4+dv1);
  915.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v4+dv2);
  916.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f4, 0.0f);
  917.                     mGL.glVertex2f(px4, py4);
  918.  
  919.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u4, v3+dv0);
  920.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u4, v3+dv1);
  921.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v3+dv2);
  922.                     mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, f3, 0.0f);
  923.                     mGL.glVertex2f(px4, py3);
  924.  
  925.                     mGL.glEnd();
  926.  
  927.                     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  928.                     mGL.glDisable(GL_TEXTURE_2D);
  929.                     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  930.                     mGL.glDisable(GL_TEXTURE_2D);
  931.                     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  932.                     mGL.glDisable(GL_TEXTURE_2D);
  933.                     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  934.                     mGL.glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
  935.                     mGL.glDisable(GL_FRAGMENT_PROGRAM_ARB);
  936.                 } else {
  937.                     float    px1 = 0;
  938.                     float    py1 = 0;
  939.                     float    px2 = (float)r.right;
  940.                     float    py2 = (float)r.bottom;
  941.                     float    u1 = 0;
  942.                     float    v1 = 0.25f * ih * bobOffset;
  943.                     float    u2 = iw * w;
  944.                     float    v2 = ih * h;
  945.  
  946.                     mGL.glOrtho(0, r.right, mbVerticalFlip ? 0 : r.bottom, mbVerticalFlip ? r.bottom : 0, -1, 1);
  947.                     mGL.glBegin(GL_QUADS);
  948.                     mGL.glColor4d(1.0f, 1.0f, 1.0f, 1.0f);
  949.                     mGL.glTexCoord2d(u1, v1);        mGL.glVertex2d(px1, py1);
  950.                     mGL.glTexCoord2d(u1, v2);        mGL.glVertex2d(px1, py2);
  951.                     mGL.glTexCoord2d(u2, v2);        mGL.glVertex2d(px2, py2);
  952.                     mGL.glTexCoord2d(u2, v1);        mGL.glVertex2d(px2, py1);
  953.                     mGL.glEnd();
  954.                 }
  955.             }
  956.         }
  957.  
  958.         VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  959.  
  960.         mGL.glFlush();
  961.  
  962.         mProfChan.Begin(0xa0c0e0, "Flip");
  963.         SwapBuffers(hdc);
  964.         mProfChan.End();
  965.  
  966.         // Workaround for Windows Vista DWM composition chain not updating.
  967.         if (mbFirstPresent) {
  968.             SetWindowPos(mhwndOGL, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
  969.             SetWindowPos(mhwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
  970.             mbFirstPresent = false;
  971.         }
  972.  
  973.         mGL.End();
  974.     }
  975.  
  976.     EndPaint(mhwndOGL, &ps);
  977. }
  978.  
  979. bool VDVideoDisplayMinidriverOpenGL::InitBicubic() {
  980.     if (!mGL.ARB_fragment_program || !mGL.ARB_multitexture)
  981.         return false;
  982.  
  983.     VDASSERT(!mFPCubic);
  984.  
  985.     mGL.glEnable(GL_FRAGMENT_PROGRAM_ARB);
  986.     mGL.glGenProgramsARB(1, &mFPCubic);
  987.     mGL.glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, mFPCubic);
  988.  
  989.     VDASSERT(mGL.glGetError() == GL_NO_ERROR);
  990.     mGL.glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, sizeof kFPCubic1 - 1, kFPCubic1);
  991.     if (mGL.glGetError()) {
  992.         VDDEBUG_DISP("VideoDisplay: GL fragment shader compilation failed.\n%s\n", mGL.glGetString(GL_PROGRAM_ERROR_STRING_ARB));
  993.         mGL.glDeleteProgramsARB(1, &mFPCubic);
  994.         mFPCubic = 0;
  995.     }
  996.     mGL.glDisable(GL_FRAGMENT_PROGRAM_ARB);
  997.  
  998.     if (!mFPCubic)
  999.         return false;
  1000.  
  1001.     return true;
  1002. }
  1003.  
  1004. void VDVideoDisplayMinidriverOpenGL::ShutdownBicubic() {
  1005.     if (mCubicFilterTempTex) {
  1006.         mGL.glDeleteTextures(1, &mCubicFilterTempTex);
  1007.         mCubicFilterTempTex = 0;
  1008.         mCubicFilterTempTexWidth = 0;
  1009.         mCubicFilterTempTexHeight = 0;
  1010.     }
  1011.  
  1012.     if (mCubicFramebuffer) {
  1013.         mGL.glDeleteFramebuffersEXT(1, &mCubicFramebuffer);
  1014.         mCubicFramebuffer = 0;
  1015.     }
  1016.  
  1017.     if (mCubicFilterH) {
  1018.         mGL.glDeleteTextures(1, &mCubicFilterH);
  1019.         mCubicFilterH = 0;
  1020.         mCubicFilterHSize = 0;
  1021.         mCubicFilterHTexSize = 0;
  1022.     }
  1023.  
  1024.     if (mCubicFilterV) {
  1025.         mGL.glDeleteTextures(1, &mCubicFilterV);
  1026.         mCubicFilterV = 0;
  1027.         mCubicFilterVSize = 0;
  1028.         mCubicFilterVTexSize = 0;
  1029.     }
  1030. }
  1031.  
  1032. void VDVideoDisplayMinidriverOpenGL::UpdateCubicTextures(uint32 w, uint32 h) {
  1033.     uint32 temptexw = 1;
  1034.     while(temptexw < w)
  1035.         temptexw += temptexw;
  1036.  
  1037.     uint32 temptexh = 1;
  1038.     while(temptexh < (uint32)mSource.pixmap.h)
  1039.         temptexh += temptexh;
  1040.  
  1041.     if (temptexw < 128)
  1042.         temptexw = 128;
  1043.  
  1044.     if (temptexh < 128)
  1045.         temptexh = 128;
  1046.  
  1047.     if (!mCubicFilterTempTex)
  1048.         mGL.glGenTextures(1, &mCubicFilterTempTex);
  1049.  
  1050.     if (mCubicFilterTempTex) {
  1051.         if (temptexw != mCubicFilterTempTexWidth || temptexh != mCubicFilterTempTexHeight) {
  1052.             mCubicFilterTempTexWidth = temptexw;
  1053.             mCubicFilterTempTexHeight = temptexh;
  1054.  
  1055.             mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterTempTex);
  1056.             mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, temptexw, temptexh, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
  1057.             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1058.             mGL.glBindTexture(GL_TEXTURE_2D, 0);
  1059.         }
  1060.  
  1061.         if (!mCubicFramebuffer) {
  1062.             mGL.glGenFramebuffersEXT(1, &mCubicFramebuffer);
  1063.             mGL.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mCubicFramebuffer);
  1064.             mGL.glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mCubicFilterTempTex, 0);
  1065.             mGL.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  1066.         }
  1067.     }
  1068.  
  1069.     if (mCubicFilterHSize != w) {
  1070.         mCubicFilterHSize = w;
  1071.  
  1072.         uint32 texw = 1;
  1073.         while(texw < w)
  1074.             texw += texw;
  1075.  
  1076.         if (!mCubicFilterH)
  1077.             mGL.glGenTextures(1, &mCubicFilterH);
  1078.  
  1079.         mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterH);
  1080.  
  1081.         if (mCubicFilterHTexSize != texw) {
  1082.             mCubicFilterHTexSize = texw;
  1083.             mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texw, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  1084.         }
  1085.  
  1086.         UpdateCubicTexture(w, mSource.pixmap.w);
  1087.  
  1088.         mGL.glBindTexture(GL_TEXTURE_2D, 0);
  1089.     }
  1090.  
  1091.     if (mCubicFilterVSize != h) {
  1092.         mCubicFilterVSize = h;
  1093.  
  1094.         uint32 texh = 1;
  1095.         while(texh < h)
  1096.             texh += texh;
  1097.  
  1098.         if (!mCubicFilterV)
  1099.             mGL.glGenTextures(1, &mCubicFilterV);
  1100.  
  1101.         mGL.glBindTexture(GL_TEXTURE_2D, mCubicFilterV);
  1102.  
  1103.         if (mCubicFilterVTexSize != texh) {
  1104.             mCubicFilterVTexSize = texh;
  1105.             mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texh, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
  1106.         }
  1107.  
  1108.         UpdateCubicTexture(h, mSource.pixmap.h);
  1109.  
  1110.         mGL.glBindTexture(GL_TEXTURE_2D, 0);
  1111.     }
  1112. }
  1113.  
  1114. void VDVideoDisplayMinidriverOpenGL::UpdateCubicTexture(uint32 dw, uint32 sw) {
  1115.     double dudx = (double)sw / (double)dw;
  1116.     double u = dudx * 0.5;
  1117.  
  1118.     vdfastvector<uint32> data(dw);
  1119.  
  1120.     for(int x = 0; x < (int)dw; ++x) {
  1121.         int ix = VDFloorToInt(u - 0.5);
  1122.         double d = u - ((double)ix + 0.5);
  1123.  
  1124.         static const double m = -0.75;
  1125.         double c0 = (( (m    )*d - 2.0*m    )*d +   m)*d;
  1126.         double c1 = (( (m+2.0)*d -     m-3.0)*d      )*d + 1.0;
  1127.         double c2 = ((-(m+2.0)*d + 2.0*m+3.0)*d -   m)*d;
  1128.         double c3 = ((-(m    )*d +     m    )*d      )*d;
  1129.  
  1130.         double k0 = d*(1-d)*m;
  1131.         double k2 = d*(1-d)*m;
  1132.  
  1133.         double c1bi = d*k0;
  1134.         double c2bi = (1-d)*k2;
  1135.         double c1ex = c1-c1bi;
  1136.         double c2ex = c2-c2bi;
  1137.  
  1138.         double o1 = c2ex/(c1ex+c2ex)-d;
  1139.  
  1140.         double blue        = d;                            // bilinear offset - p0 and p3
  1141.         double green    = o1*4;                            // bilinear offset - p1 and p2
  1142.         double red        = (d*(1-d))*4;                    // shift factor between the two
  1143.         double alpha    = d;                            // lerp constant between p0 and p3
  1144.  
  1145.         uint8 ib = VDClampedRoundFixedToUint8Fast((float)blue * 127.0f/255.0f + 128.0f/255.0f);
  1146.         uint8 ig = VDClampedRoundFixedToUint8Fast((float)green * 127.0f/255.0f + 128.0f/255.0f);
  1147.         uint8 ir = VDClampedRoundFixedToUint8Fast((float)red);
  1148.         uint8 ia = VDClampedRoundFixedToUint8Fast((float)alpha);
  1149.  
  1150.         data[x] = (uint32)ib + ((uint32)ig << 8) + ((uint32)ir << 16) + ((uint32)ia << 24);
  1151.  
  1152. #if 0
  1153.                 double fb = ((int)ib - 128) / 127.0f;
  1154.                 double fg = ((int)ig - 128) / 127.0f;
  1155.                 double fr = (double)ir / 255.0f;
  1156.                 double fa = (double)ia / 255.0f;
  1157.  
  1158.                 double g0 = fr*0.25f*0.75f;
  1159.                 double g1 = 2*(0.5f + fr*0.25f*0.75f);
  1160.                 double d1 = 0.25f * fg + d;
  1161.                 double g2 = fr*0.25f*0.75f;
  1162.  
  1163.                 double cr0 = -g0*(1-d);
  1164.                 double cr1 = -g0*d + g1*(1-d1);
  1165.                 double cr2 = g1*d1 + -g2*(1-d);
  1166.                 double cr3 = -g2*d;
  1167.  
  1168.                 if (fabsf(cr0-c0) > 0.01f)
  1169.                     __debugbreak();
  1170.                 if (fabsf(cr1-c1) > 0.01f)
  1171.                     __debugbreak();
  1172.                 if (fabsf(cr2-c2) > 0.01f)
  1173.                     __debugbreak();
  1174.                 if (fabsf(cr3-c3) > 0.01f)
  1175.                     __debugbreak();
  1176. #endif
  1177.  
  1178.         u += dudx;
  1179.     }
  1180.  
  1181.     mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, dw, 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data.data());
  1182.  
  1183.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  1184.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  1185.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1186.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1187. }
  1188.