MythTV  0.26-pre
mythrender_d3d9.cpp
Go to the documentation of this file.
00001 #define _WIN32_WINNT 0x500
00002 
00003 #include <algorithm>
00004 using std::min;
00005 
00006 #include <QLibrary>
00007 #include <QRect>
00008 #include <QMap>
00009 #include <QMutex>
00010 
00011 #include "mythlogging.h"
00012 #include "mythrender_d3d9.h"
00013 
00014 #define DXVA2_E_NEW_VIDEO_DEVICE MAKE_HRESULT(1, 4, 4097)
00015 
00016 class MythD3DVertexBuffer
00017 {
00018   public:
00019     MythD3DVertexBuffer(IDirect3DTexture9* tex = NULL) :
00020         m_color(0xFFFFFFFF), m_dest(QRect(QPoint(0,0),QSize(0,0))),
00021         m_src(QRect(QPoint(0,0),QSize(0,0))), m_texture(tex)
00022     {
00023     }
00024 
00025     uint32_t           m_color;
00026     QRect              m_dest;
00027     QRect              m_src;
00028     IDirect3DTexture9 *m_texture;
00029 };
00030 
00031 class MythD3DSurface
00032 {
00033   public:
00034     MythD3DSurface(QSize size = QSize(0,0), D3DFORMAT fmt = D3DFMT_UNKNOWN) :
00035         m_size(size), m_fmt(fmt)
00036     {
00037     }
00038 
00039     QSize     m_size;
00040     D3DFORMAT m_fmt;
00041 };
00042 
00043 typedef struct
00044 {
00045     FLOAT       x;
00046     FLOAT       y;
00047     FLOAT       z;
00048     FLOAT       rhw;
00049     D3DCOLOR    diffuse;
00050     FLOAT       t1u;
00051     FLOAT       t1v;
00052     FLOAT       t2u;
00053     FLOAT       t2v;
00054 } TEXTUREVERTEX;
00055 
00056 typedef struct
00057 {
00058     FLOAT       x;
00059     FLOAT       y;
00060     FLOAT       z;
00061     FLOAT       rhw;
00062     D3DCOLOR    diffuse;
00063 } VERTEX;
00064 
00065 D3D9Image::D3D9Image(MythRenderD3D9 *render, QSize size, bool video)
00066   : m_size(size), m_valid(false), m_render(render), m_vertexbuffer(NULL),
00067     m_texture(NULL), m_surface(NULL)
00068 {
00069     if (m_render)
00070     {
00071         m_texture      = m_render->CreateTexture(m_size);
00072         m_vertexbuffer = m_render->CreateVertexBuffer(m_texture);
00073         m_surface      = m_render->CreateSurface(m_size, video);
00074     }
00075     m_valid = m_texture && m_vertexbuffer && m_surface;
00076 }
00077 
00078 D3D9Image::~D3D9Image()
00079 {
00080     if (!m_render)
00081         return;
00082 
00083     if (m_texture)
00084         m_render->DeleteTexture(m_texture);
00085     if (m_vertexbuffer)
00086         m_render->DeleteVertexBuffer(m_vertexbuffer);
00087     if (m_surface)
00088         m_render->DeleteSurface(m_surface);
00089 }
00090 
00091 bool D3D9Image::SetAsRenderTarget(void)
00092 {
00093     if (m_valid)
00094         return m_render->SetRenderTarget(m_texture);
00095     return m_valid;
00096 }
00097 
00098 bool D3D9Image::UpdateImage(IDirect3DSurface9 *surface)
00099 {
00100     if (m_valid)
00101         return m_render->StretchRect(m_texture, surface, false);
00102     return false;
00103 }
00104 
00105 bool D3D9Image::UpdateImage(const MythImage *img)
00106 {
00107     bool result = true;
00108     if (m_valid)
00109     {
00110         result &= m_render->UpdateSurface(m_surface, img);
00111         result &= m_render->StretchRect(m_texture, m_surface);
00112     }
00113     return m_valid && result;
00114 }
00115 
00116 bool D3D9Image::UpdateVertices(const QRect &dvr, const QRect &vr, int alpha,
00117                                bool video)
00118 {
00119     if (m_valid)
00120         return m_render->UpdateVertexBuffer(m_vertexbuffer, dvr, vr,
00121                                             alpha, video);
00122     return m_valid;
00123 }
00124 
00125 bool D3D9Image::Draw(void)
00126 {
00127     if (m_valid)
00128         return m_render->DrawTexturedQuad(m_vertexbuffer);
00129     return m_valid;
00130 }
00131 
00132 uint8_t* D3D9Image::GetBuffer(bool &hardware_conv, uint &pitch)
00133 {
00134     if (!m_valid)
00135         return NULL;
00136 
00137     hardware_conv = m_render->HardwareYUVConversion();
00138     return m_render->GetBuffer(m_surface, pitch);
00139 }
00140 
00141 void D3D9Image::ReleaseBuffer(void)
00142 {
00143     if (!m_valid)
00144         return;
00145     m_render->ReleaseBuffer(m_surface);
00146     m_render->StretchRect(m_texture, m_surface);
00147 }
00148 
00149 QRect D3D9Image::GetRect(void)
00150 {
00151     if (!m_valid)
00152         return QRect();
00153     return m_render->GetRect(m_vertexbuffer);
00154 }
00155 
00156 #define mD3DFMT_YV12 (D3DFORMAT)MAKEFOURCC('Y','V','1','2')
00157 #define mD3DFMT_IYUV (D3DFORMAT)MAKEFOURCC('I','Y','U','V')
00158 #define mD3DFMT_I420 (D3DFORMAT)MAKEFOURCC('I','4','2','0')
00159 #define mD3DFMT_YV16 (D3DFORMAT)MAKEFOURCC('Y','V','1','6')
00160 #define D3DFVF_TEXTUREVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1|D3DFVF_TEX2)
00161 #define D3DFVF_VERTEX        (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
00162 #define D3DLOC QString("MythRenderD3D9: ")
00163 
00164 D3D9Locker::D3D9Locker(MythRenderD3D9 *render) : m_render(render)
00165 {
00166 }
00167 
00168 D3D9Locker::~D3D9Locker()
00169 {
00170     if (m_render)
00171         m_render->ReleaseDevice();
00172 }
00173 
00174 IDirect3DDevice9* D3D9Locker::Acquire(void)
00175 {
00176     IDirect3DDevice9* result = NULL;
00177     if (m_render)
00178         result = m_render->AcquireDevice();
00179     if (!result)
00180         LOG(VB_GENERAL, LOG_ERR, "D3D9Locker: Failed to acquire device.");
00181     return result;
00182 }
00183 
00184 void* MythRenderD3D9::ResolveAddress(const char* lib, const char* proc)
00185 {
00186     return QLibrary::resolve(lib, proc);
00187 }
00188 
00189 MythRenderD3D9::MythRenderD3D9(void)
00190   : MythRender(kRenderDirect3D9),
00191     m_d3d(NULL), m_rootD3DDevice(NULL),
00192     m_adaptor_fmt(D3DFMT_UNKNOWN),
00193     m_videosurface_fmt(D3DFMT_UNKNOWN),
00194     m_surface_fmt(D3DFMT_UNKNOWN), m_texture_fmt(D3DFMT_UNKNOWN),
00195     m_rect_vertexbuffer(NULL), m_default_surface(NULL), m_current_surface(NULL),
00196     m_lock(QMutex::Recursive),
00197     m_blend(true), m_multi_texturing(true), m_texture_vertices(true),
00198     m_deviceManager(NULL), m_deviceHandle(NULL), m_deviceManagerToken(0)
00199 {
00200 }
00201 
00202 MythRenderD3D9::~MythRenderD3D9(void)
00203 {
00204     QMutexLocker locker(&m_lock);
00205 
00206     LOG(VB_GENERAL, LOG_INFO, D3DLOC + "Deleting D3D9 resources.");
00207 
00208     if (m_rect_vertexbuffer)
00209         m_rect_vertexbuffer->Release();
00210     if (m_current_surface)
00211         m_current_surface->Release();
00212     if (m_default_surface)
00213         m_default_surface->Release();
00214 
00215     DeleteTextures();
00216     DeleteVertexBuffers();
00217     DeleteSurfaces();
00218 
00219     DestroyDeviceManager();
00220 
00221     if (m_rootD3DDevice)
00222     {
00223         LOG(VB_GENERAL, LOG_INFO, D3DLOC + "Deleting D3D9 device.");
00224         m_rootD3DDevice->Release();
00225     }
00226 
00227     if (m_d3d)
00228     {
00229         LOG(VB_GENERAL, LOG_INFO, D3DLOC + "Deleting D3D9.");
00230         m_d3d->Release();
00231     }
00232 }
00233 
00234 static const QString toString(D3DFORMAT fmt)
00235 {
00236     switch (fmt)
00237     {
00238         case D3DFMT_A8:
00239             return "A8";
00240         case D3DFMT_A8R8G8B8:
00241             return "A8R8G8B8";
00242         case D3DFMT_X8R8G8B8:
00243             return "X8R8G8B8";
00244         case D3DFMT_A8B8G8R8:
00245             return "A8B8G8R8";
00246         case D3DFMT_X8B8G8R8:
00247             return "X8B8G8R8";
00248         case mD3DFMT_YV12:
00249             return "YV12";
00250         case D3DFMT_UYVY:
00251             return "UYVY";
00252         case D3DFMT_YUY2:
00253             return "YUY2";
00254         case mD3DFMT_IYUV:
00255             return "IYUV";
00256         case mD3DFMT_I420:
00257             return "I420";
00258         case mD3DFMT_YV16:
00259             return "YV16";
00260         default:
00261             break;
00262     }
00263     return QString().setNum((ulong)fmt,16);
00264 }
00265 
00266 bool MythRenderD3D9::Create(QSize size, HWND window)
00267 {
00268     QMutexLocker locker(&m_lock);
00269 
00270     typedef LPDIRECT3D9 (WINAPI *LPFND3DC)(UINT SDKVersion);
00271     static  LPFND3DC  OurDirect3DCreate9 = NULL;
00272 
00273     OurDirect3DCreate9 = (LPFND3DC)ResolveAddress("D3D9","Direct3DCreate9");
00274     if (!OurDirect3DCreate9)
00275     {
00276         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00277             "FATAL: Failed to find Direct3DCreate9.");
00278         return false;
00279     }
00280 
00281     m_d3d = OurDirect3DCreate9(D3D_SDK_VERSION);
00282     if (!m_d3d)
00283     {
00284         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00285             "Could not create Direct3D9 instance.");
00286         return false;
00287     }
00288 
00289     D3DCAPS9 d3dCaps;
00290     ZeroMemory(&d3dCaps, sizeof(d3dCaps));
00291     if (D3D_OK != m_d3d->GetDeviceCaps(
00292             D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps))
00293     {
00294         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00295             "Could not read adapter capabilities.");
00296     }
00297 
00298     D3DDISPLAYMODE d3ddm;
00299     if (D3D_OK != m_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))
00300     {
00301         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00302             "Could not read adapter display mode.");
00303         return false;
00304     }
00305 
00306     // Check the adaptor format is reasonable
00307     static const D3DFORMAT bfmt[] =
00308     {
00309         D3DFMT_A8R8G8B8,
00310         D3DFMT_A8B8G8R8,
00311         D3DFMT_X8R8G8B8,
00312         D3DFMT_X8B8G8R8,
00313         D3DFMT_R8G8B8
00314     };
00315 
00316     m_adaptor_fmt = d3ddm.Format;
00317     bool is_reasonable = false;
00318     for (uint i = 0; i < sizeof(bfmt) / sizeof(bfmt[0]); i++)
00319         if (bfmt[i] == m_adaptor_fmt)
00320             is_reasonable = true;
00321     LOG(VB_GENERAL, LOG_INFO, D3DLOC + QString("Default adaptor format %1.")
00322                                          .arg(toString(m_adaptor_fmt)));
00323     if (!is_reasonable)
00324     {
00325         LOG(VB_GENERAL, LOG_WARNING, D3DLOC +
00326             "Warning: Default adaptor format may not work.");
00327     }
00328 
00329     // Choose a surface format
00330     for (unsigned i = 0; i < sizeof bfmt / sizeof bfmt[0]; ++i)
00331     {
00332         if (SUCCEEDED(m_d3d->CheckDeviceType(D3DADAPTER_DEFAULT,
00333                       D3DDEVTYPE_HAL, m_adaptor_fmt, bfmt[i], TRUE)))
00334         {
00335             m_surface_fmt = bfmt[i];
00336             break;
00337         }
00338     }
00339 
00340     if (D3DFMT_UNKNOWN == m_surface_fmt)
00341     {
00342         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to choose surface format - "
00343                                           "using default back buffer format.");
00344         m_surface_fmt = m_adaptor_fmt;
00345     }
00346 
00347     m_texture_fmt = m_surface_fmt;
00348     LOG(VB_GENERAL, LOG_INFO, D3DLOC +
00349         QString("Chosen surface and texture format: %1")
00350             .arg(toString(m_surface_fmt)));
00351 
00352 
00353     // Test whether a YV12 video surface is available
00354     if (FAILED(m_d3d->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT,
00355                D3DDEVTYPE_HAL, D3DFMT_UNKNOWN, m_adaptor_fmt)) &&
00356         SUCCEEDED(m_d3d->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT,
00357                   D3DDEVTYPE_HAL, mD3DFMT_YV12, m_surface_fmt)))
00358     {
00359         m_videosurface_fmt = mD3DFMT_YV12;
00360     }
00361     else
00362     {
00363         m_videosurface_fmt = m_surface_fmt;
00364     }
00365 
00366     LOG(VB_GENERAL, LOG_INFO, D3DLOC +
00367         QString("Chosen video surface format %1.")
00368             .arg(toString(m_videosurface_fmt)));
00369     LOG(VB_GENERAL, LOG_INFO, D3DLOC +
00370         QString("Hardware YV12 to RGB conversion %1.")
00371             .arg(m_videosurface_fmt != mD3DFMT_YV12 ?
00372                  "unavailable" : "available"));
00373 
00374     D3DPRESENT_PARAMETERS d3dpp;
00375     ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
00376     d3dpp.BackBufferFormat       = m_adaptor_fmt;
00377     d3dpp.hDeviceWindow          = window;
00378     d3dpp.Windowed               = true;
00379     d3dpp.BackBufferWidth        = size.width();
00380     d3dpp.BackBufferHeight       = size.height();
00381     d3dpp.BackBufferCount        = 1;
00382     d3dpp.MultiSampleType        = D3DMULTISAMPLE_NONE;
00383     d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
00384     d3dpp.Flags                  = D3DPRESENTFLAG_VIDEO;
00385     d3dpp.PresentationInterval   = D3DPRESENT_INTERVAL_ONE;
00386 
00387     if (D3D_OK != m_d3d->CreateDevice(D3DADAPTER_DEFAULT,
00388                                       D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
00389                                       D3DCREATE_SOFTWARE_VERTEXPROCESSING |
00390                                       D3DCREATE_MULTITHREADED,
00391                                       &d3dpp, &m_rootD3DDevice))
00392     {
00393         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Could not create the D3D device.");
00394         return false;
00395     }
00396 
00397     static bool debugged = false;
00398     if (!debugged)
00399     {
00400         debugged = true;
00401         D3DADAPTER_IDENTIFIER9 ident;
00402         if (D3D_OK == m_d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident))
00403         {
00404             LOG(VB_GENERAL, LOG_INFO, D3DLOC + QString("Device: %1")
00405                     .arg(ident.Description));
00406             LOG(VB_GENERAL, LOG_INFO,  D3DLOC +QString("Driver: %1.%2.%3.%4")
00407                     .arg(HIWORD(ident.DriverVersion.HighPart))
00408                     .arg(LOWORD(ident.DriverVersion.HighPart))
00409                     .arg(HIWORD(ident.DriverVersion.LowPart))
00410                     .arg(LOWORD(ident.DriverVersion.LowPart)));
00411         }
00412     }
00413 
00414     CreateDeviceManager();
00415     Init2DState();
00416     return true;
00417 }
00418 
00419 bool MythRenderD3D9::HardwareYUVConversion(void)
00420 {
00421     return m_videosurface_fmt == mD3DFMT_YV12;
00422 }
00423 
00424 bool MythRenderD3D9::Test(bool &reset)
00425 {
00426     D3D9Locker locker(this);
00427     IDirect3DDevice9* dev = locker.Acquire();
00428     if (!dev)
00429         return false;
00430 
00431     bool result = true;
00432     HRESULT hr = dev->TestCooperativeLevel();
00433     if (FAILED(hr))
00434     {
00435         switch (hr)
00436         {
00437                 case D3DERR_DEVICENOTRESET:
00438                     LOG(VB_GENERAL, LOG_NOTICE, D3DLOC +
00439                         "The device was lost and needs to be reset.");
00440                     result  = false;
00441                     reset  |= true;
00442                     break;
00443 
00444                 case D3DERR_DEVICELOST:
00445                     LOG(VB_GENERAL, LOG_NOTICE, D3DLOC +
00446                         "The device has been lost and cannot be reset "
00447                         "at this time.");
00448                     result = false;
00449                     break;
00450 
00451                 case D3DERR_DRIVERINTERNALERROR:
00452                     LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00453                         "Internal driver error. "
00454                         "Please shut down the application.");
00455                     result = false;
00456                     break;
00457 
00458                 default:
00459                     LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00460                         "TestCooperativeLevel() failed.");
00461                     result = false;
00462         }
00463     }
00464     return result;
00465 }
00466 
00467 bool MythRenderD3D9::ClearBuffer(void)
00468 {
00469     D3D9Locker locker(this);
00470     IDirect3DDevice9* dev = locker.Acquire();
00471     if (!dev)
00472         return false;
00473 
00474     HRESULT hr = dev->Clear(0, NULL, D3DCLEAR_TARGET,
00475                             D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);
00476     if (FAILED(hr))
00477     {
00478         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Clear() failed.");
00479         return false;
00480     }
00481     return true;
00482 }
00483 
00484 bool MythRenderD3D9::Begin(void)
00485 {
00486     D3D9Locker locker(this);
00487     IDirect3DDevice9* dev = locker.Acquire();
00488     if (!dev)
00489         return false;
00490 
00491     HRESULT hr = dev->BeginScene();
00492     if (FAILED(hr))
00493     {
00494         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "BeginScene() failed.");
00495         return false;
00496     }
00497     return true;
00498 }
00499 
00500 bool MythRenderD3D9::End(void)
00501 {
00502     D3D9Locker locker(this);
00503     IDirect3DDevice9* dev = locker.Acquire();
00504     if (!dev)
00505         return false;
00506 
00507     HRESULT hr = dev->EndScene();
00508     if (FAILED(hr))
00509     {
00510         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "EndScene() failed.");
00511         return false;
00512     }
00513     return true;
00514 }
00515 
00516 void MythRenderD3D9::CopyFrame(void* surface, D3D9Image *img)
00517 {
00518     if (surface && img)
00519         img->UpdateImage((IDirect3DSurface9*)surface);
00520 }
00521 
00522 bool MythRenderD3D9::StretchRect(IDirect3DTexture9 *texture,
00523                                  IDirect3DSurface9 *surface,
00524                                  bool known_surface)
00525 {
00526     if (!m_textures.contains(texture) ||
00527        (known_surface && !m_surfaces.contains(surface)))
00528         return false;
00529 
00530     D3D9Locker locker(this);
00531     IDirect3DDevice9* dev = locker.Acquire();
00532     if (!dev)
00533         return false;
00534 
00535     LPDIRECT3DSURFACE9 d3ddest;
00536     HRESULT hr = texture->GetSurfaceLevel(0, &d3ddest);
00537     if (FAILED(hr))
00538     {
00539         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "GetSurfaceLevel() failed");
00540         return false;
00541     }
00542 
00543     hr = dev->StretchRect(surface, NULL, d3ddest,
00544                                   NULL, D3DTEXF_POINT);
00545     d3ddest->Release();
00546     if (FAILED(hr))
00547     {
00548         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "StretchRect() failed");
00549         return false;
00550     }
00551     return true;
00552 }
00553 
00554 bool MythRenderD3D9::DrawTexturedQuad(IDirect3DVertexBuffer9 *vertexbuffer)
00555 {
00556     if (!m_vertexbuffers.contains(vertexbuffer))
00557         return false;
00558 
00559     D3D9Locker locker(this);
00560     IDirect3DDevice9* dev = locker.Acquire();
00561     if (!dev)
00562         return false;
00563 
00564     IDirect3DTexture9 *texture = m_vertexbuffers[vertexbuffer].m_texture;
00565 
00566     if (texture && !SetTexture(dev, texture))
00567         return false;
00568 
00569     EnableBlending(dev, true);
00570     SetTextureVertices(dev, true);
00571     MultiTexturing(dev, false);
00572 
00573     HRESULT hr = dev->SetStreamSource(0, vertexbuffer,
00574                                               0, sizeof(TEXTUREVERTEX));
00575     if (FAILED(hr))
00576     {
00577         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "SetStreamSource() failed");
00578         return false;
00579     }
00580 
00581     hr = dev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
00582     if (FAILED(hr))
00583     {
00584         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "DrawPrimitive() failed");
00585         return false;
00586     }
00587 
00588     return true;
00589 }
00590 
00591 void MythRenderD3D9::DrawRect(const QRect &rect, const QColor &color, int alpha)
00592 {
00593     D3D9Locker locker(this);
00594     IDirect3DDevice9* dev = locker.Acquire();
00595     if (!dev)
00596         return;
00597 
00598     if (!m_rect_vertexbuffer)
00599     {
00600         HRESULT hr = dev->CreateVertexBuffer(
00601                 sizeof(VERTEX)*4,     D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
00602                 D3DFVF_VERTEX,        D3DPOOL_DEFAULT,
00603                 &m_rect_vertexbuffer, NULL);
00604 
00605         if (FAILED(hr))
00606         {
00607             LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to create vertex buffer");
00608             return;
00609         }
00610     }
00611 
00612     EnableBlending(dev, true);
00613     SetTextureVertices(dev, false);
00614     MultiTexturing(dev, false);
00615     SetTexture(dev, NULL, 0);
00616 
00617     int alphamod = (int)(color.alpha() * (alpha / 255.0));
00618     D3DCOLOR clr = D3DCOLOR_ARGB(alphamod, color.red(),
00619                                  color.green(), color.blue());
00620     VERTEX *p_vertices;
00621     HRESULT hr = m_rect_vertexbuffer->Lock(0, 0, (VOID **)(&p_vertices),
00622                                            D3DLOCK_DISCARD);
00623     if (FAILED(hr))
00624     {
00625         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to lock vertex buffer.");
00626         return;
00627     }
00628 
00629     p_vertices[0].x       = (float)rect.left();
00630     p_vertices[0].y       = (float)rect.top();
00631     p_vertices[0].z       = 0.0f;
00632     p_vertices[0].diffuse = clr;
00633     p_vertices[0].rhw     = 1.0f;
00634     p_vertices[1].x       = (float)(rect.left() + rect.width());
00635     p_vertices[1].y       = (float)rect.top();
00636     p_vertices[1].z       = 0.0f;
00637     p_vertices[1].diffuse = clr;
00638     p_vertices[1].rhw     = 1.0f;
00639     p_vertices[2].x       = (float)(rect.left() + rect.width());
00640     p_vertices[2].y       = (float)(rect.top() + rect.height());
00641     p_vertices[2].z       = 0.0f;
00642     p_vertices[2].diffuse = clr;
00643     p_vertices[2].rhw     = 1.0f;
00644     p_vertices[3].x       = (float)rect.left();
00645     p_vertices[3].y       = (float)(rect.top() + rect.height());
00646     p_vertices[3].z       = 0.0f;
00647     p_vertices[3].diffuse = clr;
00648     p_vertices[3].rhw     = 1.0f;
00649 
00650     hr = m_rect_vertexbuffer->Unlock();
00651     if (FAILED(hr))
00652     {
00653         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to unlock vertex buffer");
00654         return;
00655     }
00656 
00657     hr = dev->SetStreamSource(0, m_rect_vertexbuffer,
00658                                       0, sizeof(VERTEX));
00659     if (FAILED(hr))
00660     {
00661         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "SetStreamSource() failed");
00662         return;
00663     }
00664 
00665     hr = dev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
00666     if (FAILED(hr))
00667     {
00668         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "DrawPrimitive() failed");
00669         return;
00670     }
00671 }
00672 
00673 void MythRenderD3D9::MultiTexturing(IDirect3DDevice9* dev, bool enable,
00674                                     IDirect3DTexture9 *texture)
00675 {
00676     if (m_multi_texturing == enable)
00677         return;
00678 
00679     if (!dev)
00680         return;
00681 
00682     if (enable)
00683     {
00684         SetTexture(dev, texture, 1);
00685         dev->SetTextureStageState(1, D3DTSS_COLOROP,   D3DTOP_SELECTARG2);
00686         dev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
00687         dev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
00688         dev->SetTextureStageState(1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
00689         dev->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
00690         dev->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
00691         dev->SetTextureStageState(2, D3DTSS_COLOROP,   D3DTOP_DISABLE);
00692         dev->SetTextureStageState(2, D3DTSS_ALPHAOP,   D3DTOP_DISABLE);
00693     }
00694     else
00695     {
00696         dev->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
00697         dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
00698         dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
00699         dev->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE);
00700         dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
00701         dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
00702         dev->SetTextureStageState(1, D3DTSS_COLOROP,   D3DTOP_DISABLE);
00703         dev->SetTextureStageState(1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE);
00704         SetTexture(dev, NULL, 1);
00705     }
00706     m_multi_texturing = enable;
00707 }
00708 
00709 bool MythRenderD3D9::Present(HWND win)
00710 {
00711     D3D9Locker locker(this);
00712     IDirect3DDevice9* dev = locker.Acquire();
00713     if (!dev)
00714         return false;
00715 
00716     HRESULT hr = dev->Present(NULL, NULL, win, NULL);
00717     if (FAILED(hr))
00718     {
00719         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Present() failed)");
00720         return false;
00721     }
00722     SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
00723     return true;
00724 }
00725 
00726 QRect MythRenderD3D9::GetRect(IDirect3DVertexBuffer9 *vertexbuffer)
00727 {
00728     if (!m_vertexbuffers.contains(vertexbuffer))
00729         return QRect();
00730     return m_vertexbuffers[vertexbuffer].m_dest;
00731 }
00732 
00733 bool MythRenderD3D9::SetRenderTarget(IDirect3DTexture9 *texture)
00734 {
00735     D3D9Locker locker(this);
00736     IDirect3DDevice9* dev = locker.Acquire();
00737     if (!dev)
00738         return false;
00739 
00740     bool ret = true;
00741     HRESULT hr;
00742     if (texture && m_textures.contains(texture))
00743     {
00744         if (!m_default_surface)
00745         {
00746             hr = dev->GetRenderTarget(0, &m_default_surface);
00747             if (FAILED(hr))
00748             {
00749                 LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00750                     "Failed to get default surface.");
00751                 return false;
00752             }
00753         }
00754 
00755         IDirect3DSurface9 *new_surface = NULL;
00756         hr = texture->GetSurfaceLevel(0, &new_surface);
00757         if (FAILED(hr))
00758             LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to get surface level.");
00759         else
00760         {
00761             if (m_current_surface && m_current_surface != new_surface)
00762                 m_current_surface->Release();
00763             m_current_surface = new_surface;
00764             hr = dev->SetRenderTarget(0, m_current_surface);
00765             if (FAILED(hr))
00766                 LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00767                     "Failed to set render target.");
00768         }
00769     }
00770     else if (!texture)
00771     {
00772         if (m_default_surface)
00773         {
00774             hr = dev->SetRenderTarget(0, m_default_surface);
00775             if (FAILED(hr))
00776                 LOG(VB_GENERAL, LOG_ERR, D3DLOC + 
00777                     "Failed to set render target.");
00778         }
00779         else
00780             LOG(VB_GENERAL, LOG_ERR, D3DLOC + 
00781                 "No default surface for render target.");
00782     }
00783     else
00784         ret = false;
00785     return ret;
00786 }
00787 
00788 bool MythRenderD3D9::SetTexture(IDirect3DDevice9* dev,
00789                                 IDirect3DTexture9 *texture, int num)
00790 {
00791     if (!dev)
00792         return false;
00793 
00794     HRESULT hr = dev->SetTexture(num, (LPDIRECT3DBASETEXTURE9)texture);
00795     if (FAILED(hr))
00796     {
00797         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "SetTexture() failed");
00798         return false;
00799     }
00800     return true;
00801 }
00802 
00803 IDirect3DTexture9* MythRenderD3D9::CreateTexture(const QSize &size)
00804 {
00805     D3D9Locker locker(this);
00806     IDirect3DDevice9* dev = locker.Acquire();
00807     if (!dev)
00808         return NULL;
00809 
00810     IDirect3DTexture9* temp_texture = NULL;
00811 
00812     HRESULT hr = dev->CreateTexture(
00813                     size.width(),  size.height(), 1, D3DUSAGE_RENDERTARGET,
00814                     m_texture_fmt, D3DPOOL_DEFAULT, &temp_texture, NULL);
00815 
00816     if (FAILED(hr) || !temp_texture)
00817     {
00818         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to create texture.");
00819         return NULL;
00820     }
00821 
00822     m_textures[temp_texture] = size;;
00823     return temp_texture;
00824 }
00825 
00826 void MythRenderD3D9::DeleteTextures(void)
00827 {
00828     QMap<IDirect3DTexture9*,QSize>::iterator it;
00829     for (it = m_textures.begin(); it != m_textures.end(); ++it)
00830         it.key()->Release();
00831     m_textures.clear();
00832 }
00833 
00834 void MythRenderD3D9::DeleteTexture(IDirect3DTexture9* texture)
00835 {
00836     QMutexLocker locker(&m_lock);
00837     if (m_textures.contains(texture))
00838     {
00839         texture->Release();
00840         m_textures.remove(texture);
00841     }
00842 }
00843 
00844 IDirect3DSurface9* MythRenderD3D9::CreateSurface(const QSize &size, bool video)
00845 {
00846     D3D9Locker locker(this);
00847     IDirect3DDevice9* dev = locker.Acquire();
00848     if (!dev)
00849         return NULL;
00850 
00851     IDirect3DSurface9* temp_surface = NULL;
00852 
00853     D3DFORMAT format = video ? m_videosurface_fmt : m_surface_fmt;
00854 
00855     HRESULT hr = dev->CreateOffscreenPlainSurface(
00856                     size.width(), size.height(), format,
00857                     D3DPOOL_DEFAULT, &temp_surface, NULL);
00858 
00859     if (FAILED(hr)|| !temp_surface)
00860     {
00861         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to create surface.");
00862         return NULL;
00863     }
00864 
00865     m_surfaces[temp_surface] = MythD3DSurface(size, format);
00866     dev->ColorFill(temp_surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) );
00867 
00868     return temp_surface;
00869 }
00870 
00871 bool MythRenderD3D9::UpdateSurface(IDirect3DSurface9 *surface,
00872                                    const MythImage *image)
00873 {
00874     if (!surface || !image || !m_surfaces.contains(surface))
00875         return false;
00876 
00877     if (m_surfaces[surface].m_size.width()  != image->width() ||
00878         m_surfaces[surface].m_size.height() != image->height())
00879     {
00880         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
00881             "Frame size does not equal surface size.");
00882         return false;
00883     }
00884 
00885     uint d3dpitch = 0;
00886     uint8_t *buf = GetBuffer(surface, d3dpitch);
00887 
00888     if (!(buf && d3dpitch))
00889         return false;
00890 
00891     D3DFORMAT format = m_surfaces[surface].m_fmt;
00892     switch (format)
00893     {
00894         case D3DFMT_A8R8G8B8:
00895         case D3DFMT_X8R8G8B8:
00896             {
00897                 uint pitch = image->width() << 2;
00898                 uint8_t *dst = buf;
00899                 uint8_t *src = (uint8_t*)image->bits();
00900                 for (int i = 0; i < image->height(); i++)
00901                 {
00902                     memcpy(dst, src, pitch);
00903                     dst += d3dpitch;
00904                     src += pitch;
00905                 }
00906             }
00907             break;
00908         default:
00909             LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Surface format not supported.");
00910             break;
00911     }
00912 
00913     ReleaseBuffer(surface);
00914     return true;
00915 }
00916 
00917 void MythRenderD3D9::DeleteSurfaces(void)
00918 {
00919     QMap<IDirect3DSurface9*, MythD3DSurface>::iterator it;
00920     for (it = m_surfaces.begin(); it != m_surfaces.end(); ++it)
00921         it.key()->Release();
00922     m_surfaces.clear();
00923 }
00924 
00925 void MythRenderD3D9::DeleteSurface(IDirect3DSurface9 *surface)
00926 {
00927     QMutexLocker locker(&m_lock);
00928     if (m_surfaces.contains(surface))
00929     {
00930         surface->Release();
00931         m_surfaces.remove(surface);
00932     }
00933 }
00934 
00935 uint8_t* MythRenderD3D9::GetBuffer(IDirect3DSurface9* surface, uint &pitch)
00936 {
00937     if (!m_surfaces.contains(surface))
00938         return NULL;
00939 
00940     m_lock.lock(); // unlocked in release buffer
00941     D3DLOCKED_RECT d3drect;
00942     HRESULT hr = surface->LockRect(&d3drect, NULL, 0);
00943 
00944     if (FAILED(hr))
00945     {
00946         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to lock picture surface.");
00947         m_lock.unlock();
00948         return false;
00949     }
00950 
00951     pitch = d3drect.Pitch;
00952     return (uint8_t*)d3drect.pBits;
00953 }
00954 
00955 void MythRenderD3D9::ReleaseBuffer(IDirect3DSurface9* surface)
00956 {
00957     if (!m_surfaces.contains(surface))
00958         return;
00959 
00960     HRESULT hr = surface->UnlockRect();
00961     if (FAILED(hr))
00962         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to unlock picture surface.");
00963     m_lock.unlock();
00964 }
00965 
00966 IDirect3DVertexBuffer9* MythRenderD3D9::CreateVertexBuffer(IDirect3DTexture9* texture)
00967 {
00968     D3D9Locker locker(this);
00969     IDirect3DDevice9* dev = locker.Acquire();
00970     if (!dev)
00971         return NULL;
00972 
00973     if (texture && !m_textures.contains(texture))
00974         return false;
00975 
00976     IDirect3DVertexBuffer9* temp_vbuf = NULL;
00977     HRESULT hr = dev->CreateVertexBuffer(
00978         sizeof(TEXTUREVERTEX)*4, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
00979         D3DFVF_TEXTUREVERTEX,    D3DPOOL_DEFAULT,
00980         &temp_vbuf,             NULL);
00981 
00982     if (FAILED(hr))
00983     {
00984         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to create vertex buffer");
00985         return false;
00986     }
00987 
00988     m_vertexbuffers[temp_vbuf] = MythD3DVertexBuffer(texture);
00989     return temp_vbuf;
00990 }
00991 
00992 void MythRenderD3D9::DeleteVertexBuffers(void)
00993 {
00994     QMap<IDirect3DVertexBuffer9*,MythD3DVertexBuffer>::iterator it;
00995     for (it = m_vertexbuffers.begin();
00996          it != m_vertexbuffers.end(); ++it)
00997     {
00998         it.key()->Release();
00999     }
01000     m_vertexbuffers.clear();
01001 }
01002 
01003 void MythRenderD3D9::DeleteVertexBuffer(IDirect3DVertexBuffer9 *vertexbuffer)
01004 {
01005     QMutexLocker locker(&m_lock);
01006     if (m_vertexbuffers.contains(vertexbuffer))
01007     {
01008         vertexbuffer->Release();
01009         m_vertexbuffers.remove(vertexbuffer);
01010     }
01011 }
01012 
01013 bool MythRenderD3D9::UpdateVertexBuffer(IDirect3DVertexBuffer9* vertexbuffer,
01014                                         const QRect &dst, const QRect &src,
01015                                         int alpha, bool video)
01016 {
01017     if (!m_vertexbuffers.contains(vertexbuffer))
01018         return false;
01019 
01020     MythD3DVertexBuffer mythvb = m_vertexbuffers[vertexbuffer];
01021     uint32_t clr = (alpha << 24) + (255 << 16) + (255 << 8) + 255;
01022 
01023     int width  = dst.width();
01024     int height = dst.height();
01025     if (!video)
01026     {
01027         width  = min(src.width(),  width);
01028         height = min(src.height(), height);
01029     }
01030     QRect dest(dst.left(), dst.top(), width, height);
01031 
01032     // FIXME - with alpha pulse, this updates far more textures than necessary
01033     if (dest == mythvb.m_dest &&
01034         src  == mythvb.m_src  &&
01035         clr  == mythvb.m_color)
01036         return true;
01037 
01038     QSize norm = src.size();
01039     if (video && mythvb.m_texture)
01040         norm = m_textures[mythvb.m_texture];
01041 
01042     QMutexLocker locker(&m_lock);
01043     TEXTUREVERTEX *p_vertices;
01044     HRESULT hr = vertexbuffer->Lock(0, 0, (VOID **)(&p_vertices),
01045                                     D3DLOCK_DISCARD);
01046     D3DCOLOR color = D3DCOLOR_ARGB(alpha, 255, 255, 255);
01047     if (FAILED(hr))
01048     {
01049         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to lock vertex buffer.");
01050         return false;
01051     }
01052 
01053     p_vertices[0].x       = (float)dest.left();
01054     p_vertices[0].y       = (float)dest.top();
01055     p_vertices[0].z       = 0.0f;
01056     p_vertices[0].diffuse = color;
01057     p_vertices[0].rhw     = 1.0f;
01058     p_vertices[0].t1u     = ((float)src.left() - 0.5f) / (float)norm.width();
01059     p_vertices[0].t1v     = ((float)src.top() - 0.5f) / (float)norm.height();
01060 
01061     p_vertices[1].x       = (float)(dest.left() + dest.width());
01062     p_vertices[1].y       = (float)dest.top();
01063     p_vertices[1].z       = 0.0f;
01064     p_vertices[1].diffuse = color;
01065     p_vertices[1].rhw     = 1.0f;
01066     p_vertices[1].t1u     = ((float)(src.left() + src.width()) - 0.5f) /
01067                             (float)norm.width();
01068     p_vertices[1].t1v     = ((float)src.top() - 0.5f) / (float)norm.height();
01069 
01070     p_vertices[2].x       = (float)(dest.left() + dest.width());
01071     p_vertices[2].y       = (float)(dest.top() + dest.height());
01072     p_vertices[2].z       = 0.0f;
01073     p_vertices[2].diffuse = color;
01074     p_vertices[2].rhw     = 1.0f;
01075     p_vertices[2].t1u     = ((float)(src.left() + src.width()) - 0.5f) /
01076                             (float)norm.width();
01077     p_vertices[2].t1v     = ((float)(src.top() + src.height()) - 0.5f) /
01078                             (float)norm.height();
01079 
01080     p_vertices[3].x       = (float)dest.left();
01081     p_vertices[3].y       = (float)(dest.top() + dest.height());
01082     p_vertices[3].z       = 0.0f;
01083     p_vertices[3].diffuse = color;
01084     p_vertices[3].rhw     = 1.0f;
01085     p_vertices[3].t1u     = ((float)src.left() - 0.5f) / (float)norm.width();
01086     p_vertices[3].t1v     = ((float)(src.top() + src.height()) - 0.5f) /
01087                             (float)norm.height();
01088 
01089     p_vertices[0].t2u     = p_vertices[0].t1u;
01090     p_vertices[0].t2v     = p_vertices[0].t1v;
01091     p_vertices[1].t2u     = p_vertices[1].t1u;
01092     p_vertices[1].t2v     = p_vertices[1].t1v;
01093     p_vertices[2].t2u     = p_vertices[2].t1u;
01094     p_vertices[2].t2v     = p_vertices[2].t1v;
01095     p_vertices[3].t2u     = p_vertices[3].t1u;
01096     p_vertices[3].t2v     = p_vertices[3].t1v;
01097 
01098     hr = vertexbuffer->Unlock();
01099     if (FAILED(hr))
01100     {
01101         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to unlock vertex buffer");
01102         return false;
01103     }
01104 
01105     m_vertexbuffers[vertexbuffer].m_dest  = dest;
01106     m_vertexbuffers[vertexbuffer].m_src   = src;
01107     m_vertexbuffers[vertexbuffer].m_color = clr;
01108     return true;
01109 }
01110 
01111 void MythRenderD3D9::Init2DState(void)
01112 {
01113     IDirect3DDevice9* dev = AcquireDevice();
01114     if (!dev)
01115         return;
01116 
01117     dev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
01118     dev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
01119     dev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
01120     dev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
01121     dev->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
01122     dev->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
01123     dev->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
01124     dev->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
01125     dev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255));
01126     dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
01127     dev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
01128     dev->SetRenderState(D3DRS_LIGHTING, FALSE);
01129     dev->SetRenderState(D3DRS_DITHERENABLE, TRUE);
01130     dev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
01131     dev->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
01132     dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
01133     dev->SetVertexShader(NULL);
01134     SetTextureVertices(dev, false);
01135     MultiTexturing(dev, false);
01136     EnableBlending(dev, false);
01137 
01138     ReleaseDevice();
01139 }
01140 
01141 void MythRenderD3D9::EnableBlending(IDirect3DDevice9* dev, bool enable)
01142 {
01143     if (m_blend == enable)
01144         return;
01145     m_blend = enable;
01146 
01147     if (dev)
01148         dev->SetRenderState(D3DRS_ALPHABLENDENABLE, enable);
01149 }
01150 
01151 void MythRenderD3D9::SetTextureVertices(IDirect3DDevice9* dev, bool enable)
01152 {
01153     if (m_texture_vertices == enable)
01154         return;
01155     m_texture_vertices = enable;
01156 
01157     if (dev)
01158         dev->SetFVF(enable ? D3DFVF_TEXTUREVERTEX : D3DFVF_VERTEX);
01159 }
01160 
01161 IDirect3DDevice9* MythRenderD3D9::AcquireDevice(void)
01162 {
01163     m_lock.lock();
01164 #ifdef USING_DXVA2
01165     if (m_deviceManager)
01166     {
01167         IDirect3DDevice9* result = NULL;
01168 
01169         HRESULT hr = IDirect3DDeviceManager9_LockDevice(m_deviceManager, m_deviceHandle, &result, true);
01170 
01171         if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
01172         {
01173             hr = IDirect3DDeviceManager9_CloseDeviceHandle(m_deviceManager, m_deviceHandle);
01174 
01175             if (SUCCEEDED(hr))
01176                 hr = IDirect3DDeviceManager9_OpenDeviceHandle(m_deviceManager, &m_deviceHandle);
01177 
01178             if (SUCCEEDED(hr))
01179                 hr = IDirect3DDeviceManager9_LockDevice(m_deviceManager, m_deviceHandle, &result, true);
01180         }
01181 
01182         if (SUCCEEDED(hr))
01183             return result;
01184 
01185         LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to acquire D3D9 device.");
01186         m_lock.unlock();
01187         return NULL;
01188     }
01189 #endif
01190     return m_rootD3DDevice;
01191 }
01192 
01193 void MythRenderD3D9::ReleaseDevice(void)
01194 {
01195 #ifdef USING_DXVA2
01196     if (m_deviceManager)
01197     {
01198         HRESULT hr = IDirect3DDeviceManager9_UnlockDevice(m_deviceManager, m_deviceHandle, false);
01199         if (!SUCCEEDED(hr))
01200             LOG(VB_GENERAL, LOG_ERR, D3DLOC + "Failed to release D3D9 device.");
01201     }
01202 #endif
01203     m_lock.unlock();
01204 }
01205 
01206 #ifdef USING_DXVA2
01207 typedef HRESULT (WINAPI *CreateDeviceManager9Ptr)(UINT *pResetToken,
01208                                                   IDirect3DDeviceManager9 **);
01209 #endif
01210 
01211 void MythRenderD3D9::CreateDeviceManager(void)
01212 {
01213 #ifdef USING_DXVA2
01214     CreateDeviceManager9Ptr CreateDeviceManager9 =
01215         (CreateDeviceManager9Ptr)ResolveAddress("DXVA2",
01216                                                 "DXVA2CreateDirect3DDeviceManager9");
01217     if (CreateDeviceManager9)
01218     {
01219         UINT resetToken = 0;
01220         HRESULT hr = CreateDeviceManager9(&resetToken, &m_deviceManager);
01221         if (SUCCEEDED(hr))
01222         {
01223             IDirect3DDeviceManager9_ResetDevice(m_deviceManager, m_rootD3DDevice, resetToken);
01224             IDirect3DDeviceManager9_AddRef(m_deviceManager);
01225             m_deviceManagerToken = resetToken;
01226             LOG(VB_GENERAL, LOG_INFO, D3DLOC + "Created DXVA2 device manager.");
01227             hr = IDirect3DDeviceManager9_OpenDeviceHandle(m_deviceManager, &m_deviceHandle);
01228             if (SUCCEEDED(hr))
01229             {
01230                 LOG(VB_GENERAL, LOG_INFO, D3DLOC + "Retrieved device handle.");
01231                 return;
01232             }
01233             LOG(VB_GENERAL, LOG_ERR, D3DLOC +
01234                 "Failed to retrieve device handle.");
01235         }
01236         else
01237         {
01238             LOG(VB_GENERAL, LOG_ERR, D3DLOC +
01239                 "Failed to create DXVA2 device manager.");
01240         }
01241     }
01242     else
01243     {
01244         LOG(VB_GENERAL, LOG_ERR, D3DLOC +
01245             "Failed to get DXVA2CreateDirect3DDeviceManager9 proc address.");
01246     }
01247 #endif
01248     m_deviceManager = NULL;
01249     m_deviceManagerToken = 0;
01250     LOG(VB_GENERAL, LOG_NOTICE, D3DLOC +
01251         "DXVA2 support not available - not using device manager");
01252 }
01253 
01254 void MythRenderD3D9::DestroyDeviceManager(void)
01255 {
01256 #ifdef USING_DXVA2
01257     if (m_deviceHandle && m_deviceManager)
01258         IDirect3DDeviceManager9_CloseDeviceHandle(m_deviceManager, m_deviceHandle);
01259     if (m_deviceManager)
01260         IDirect3DDeviceManager9_Release(m_deviceManager);
01261 #endif
01262     m_deviceHandle  = NULL;
01263     m_deviceManager = NULL;
01264 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends