Bugfix: PGS YVU => YUV
[xy_vsfilter.git] / src / subpic / DX9SubPic.cpp
blob99f6e0260f4ed96a7a8371ce214e2e7761f6fc86
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include <d3d9.h>
24 #include <vmr9.h>
25 #include "DX9SubPic.h"
28 // CDX9SubPic
31 CDX9SubPic::CDX9SubPic(IDirect3DSurface9* pSurface, CDX9SubPicAllocator *pAllocator, bool bExternalRenderer)
32 : m_pSurface(pSurface), m_pAllocator(pAllocator), m_bExternalRenderer(bExternalRenderer)
34 D3DSURFACE_DESC d3dsd;
35 ZeroMemory(&d3dsd, sizeof(d3dsd));
36 if(SUCCEEDED(m_pSurface->GetDesc(&d3dsd))) {
37 m_maxsize.SetSize(d3dsd.Width, d3dsd.Height);
38 m_rcDirty.SetRect(0, 0, d3dsd.Width, d3dsd.Height);
42 CDX9SubPic::~CDX9SubPic()
45 CAutoLock Lock(&CDX9SubPicAllocator::ms_SurfaceQueueLock);
46 // Add surface to cache
47 if (m_pAllocator) {
48 for (POSITION pos = m_pAllocator->m_AllocatedSurfaces.GetHeadPosition(); pos; ) {
49 POSITION ThisPos = pos;
50 CDX9SubPic *pSubPic = m_pAllocator->m_AllocatedSurfaces.GetNext(pos);
51 if (pSubPic == this) {
52 m_pAllocator->m_AllocatedSurfaces.RemoveAt(ThisPos);
53 break;
56 m_pAllocator->m_FreeSurfaces.AddTail(m_pSurface);
62 // ISubPic
64 STDMETHODIMP_(void*) CDX9SubPic::GetObject() const
66 CComPtr<IDirect3DTexture9> pTexture;
67 if(SUCCEEDED(m_pSurface->GetContainer(IID_IDirect3DTexture9, (void**)&pTexture))) {
68 return (void*)(IDirect3DTexture9*)pTexture;
71 return NULL;
74 STDMETHODIMP CDX9SubPic::GetDesc(SubPicDesc& spd) const
76 D3DSURFACE_DESC d3dsd;
77 ZeroMemory(&d3dsd, sizeof(d3dsd));
78 if(FAILED(m_pSurface->GetDesc(&d3dsd))) {
79 return E_FAIL;
82 spd.type = 0;
83 spd.w = m_size.cx;
84 spd.h = m_size.cy;
85 spd.bpp =
86 d3dsd.Format == D3DFMT_A8R8G8B8 ? 32 :
87 d3dsd.Format == D3DFMT_A4R4G4B4 ? 16 : 0;
88 spd.pitch = 0;
89 spd.bits = NULL;
90 spd.vidrect = m_vidrect;
92 return S_OK;
95 STDMETHODIMP CDX9SubPic::CopyTo(ISubPic* pSubPic)
97 HRESULT hr;
98 if(FAILED(hr = __super::CopyTo(pSubPic))) {
99 return hr;
102 if(m_rcDirty.IsRectEmpty()) {
103 return S_FALSE;
106 CComPtr<IDirect3DDevice9> pD3DDev;
107 if(!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) {
108 return E_FAIL;
111 IDirect3DTexture9* pSrcTex = (IDirect3DTexture9*)GetObject();
112 CComPtr<IDirect3DSurface9> pSrcSurf;
113 pSrcTex->GetSurfaceLevel(0, &pSrcSurf);
114 D3DSURFACE_DESC srcDesc;
115 pSrcSurf->GetDesc(&srcDesc);
117 IDirect3DTexture9* pDstTex = (IDirect3DTexture9*)pSubPic->GetObject();
118 CComPtr<IDirect3DSurface9> pDstSurf;
119 pDstTex->GetSurfaceLevel(0, &pDstSurf);
120 D3DSURFACE_DESC dstDesc;
121 pDstSurf->GetDesc(&dstDesc);
123 RECT r;
124 SetRect(&r, 0, 0, min(srcDesc.Width, dstDesc.Width), min(srcDesc.Height, dstDesc.Height));
125 POINT p = { 0, 0 };
126 hr = pD3DDev->UpdateSurface(pSrcSurf, &r, pDstSurf, &p);
127 // ASSERT (SUCCEEDED (hr));
129 return SUCCEEDED(hr) ? S_OK : E_FAIL;
132 STDMETHODIMP CDX9SubPic::ClearDirtyRect(DWORD color)
134 if(m_rcDirty.IsRectEmpty()) {
135 return S_FALSE;
138 CComPtr<IDirect3DDevice9> pD3DDev;
139 if(!m_pSurface || FAILED(m_pSurface->GetDevice(&pD3DDev)) || !pD3DDev) {
140 return E_FAIL;
143 SubPicDesc spd;
144 if(SUCCEEDED(Lock(spd))) {
145 int h = m_rcDirty.Height();
147 BYTE* ptr = (BYTE*)spd.bits + spd.pitch*m_rcDirty.top + (m_rcDirty.left*spd.bpp>>3);
149 if(spd.bpp == 16) {
150 while(h-- > 0) {
151 memsetw(ptr, color, 2 * m_rcDirty.Width());
152 ptr += spd.pitch;
154 } else if(spd.bpp == 32) {
155 while(h-- > 0) {
156 memsetd(ptr, color, 4 * m_rcDirty.Width());
157 ptr += spd.pitch;
161 DWORD* ptr = (DWORD*)bm.bits;
162 DWORD* end = ptr + bm.h*bm.wBytes/4;
163 while(ptr < end) *ptr++ = color;
165 Unlock(NULL);
168 // HRESULT hr = pD3DDev->ColorFill(m_pSurface, m_rcDirty, color);
170 m_rcDirty.SetRectEmpty();
172 return S_OK;
175 STDMETHODIMP CDX9SubPic::Lock(SubPicDesc& spd)
177 D3DSURFACE_DESC d3dsd;
178 ZeroMemory(&d3dsd, sizeof(d3dsd));
179 if(FAILED(m_pSurface->GetDesc(&d3dsd))) {
180 return E_FAIL;
183 D3DLOCKED_RECT LockedRect;
184 ZeroMemory(&LockedRect, sizeof(LockedRect));
185 if(FAILED(m_pSurface->LockRect(&LockedRect, NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK))) {
186 return E_FAIL;
189 spd.type = 0;
190 spd.w = m_size.cx;
191 spd.h = m_size.cy;
192 spd.bpp =
193 d3dsd.Format == D3DFMT_A8R8G8B8 ? 32 :
194 d3dsd.Format == D3DFMT_A4R4G4B4 ? 16 : 0;
195 spd.pitch = LockedRect.Pitch;
196 spd.bits = LockedRect.pBits;
197 spd.vidrect = m_vidrect;
199 return S_OK;
202 STDMETHODIMP CDX9SubPic::Unlock(RECT* pDirtyRect)
204 HRESULT hr = m_pSurface->UnlockRect();
206 if(pDirtyRect) {
207 m_rcDirty = *pDirtyRect;
208 if (!((CRect*)pDirtyRect)->IsRectEmpty()) {
209 m_rcDirty.InflateRect(1, 1);
210 m_rcDirty.left &= ~127;
211 m_rcDirty.top &= ~63;
212 m_rcDirty.right = (m_rcDirty.right + 127) & ~127;
213 m_rcDirty.bottom = (m_rcDirty.bottom + 63) & ~63;
214 m_rcDirty &= CRect(CPoint(0, 0), m_size);
216 } else {
217 m_rcDirty = CRect(CPoint(0, 0), m_size);
220 CComPtr<IDirect3DTexture9> pTexture = (IDirect3DTexture9*)GetObject();
221 if (pTexture && !((CRect*)pDirtyRect)->IsRectEmpty()) {
222 hr = pTexture->AddDirtyRect(&m_rcDirty);
224 return S_OK;
227 STDMETHODIMP CDX9SubPic::AlphaBlt(const RECT* pSrc, const RECT* pDst, SubPicDesc* pTarget)
229 ASSERT(pTarget == NULL);
231 if(!pSrc || !pDst) {
232 return E_POINTER;
235 CRect src(*pSrc), dst(*pDst);
237 CComPtr<IDirect3DDevice9> pD3DDev;
238 CComPtr<IDirect3DTexture9> pTexture = (IDirect3DTexture9*)GetObject();
239 if(!pTexture || FAILED(pTexture->GetDevice(&pD3DDev)) || !pD3DDev) {
240 return E_NOINTERFACE;
243 HRESULT hr;
245 do {
246 D3DSURFACE_DESC d3dsd;
247 ZeroMemory(&d3dsd, sizeof(d3dsd));
248 if(FAILED(pTexture->GetLevelDesc(0, &d3dsd)) /*|| d3dsd.Type != D3DRTYPE_TEXTURE*/) {
249 break;
252 float w = (float)d3dsd.Width;
253 float h = (float)d3dsd.Height;
255 struct {
256 float x, y, z, rhw;
257 float tu, tv;
259 pVertices[] = {
260 {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h},
261 {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h},
262 {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h},
263 {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h},
266 for(ptrdiff_t i = 0; i < countof(pVertices); i++) {
267 pVertices[i].x -= 0.5;
268 pVertices[i].y -= 0.5;
271 hr = pD3DDev->SetTexture(0, pTexture);
273 // GetRenderState fails for devices created with D3DCREATE_PUREDEVICE
274 // so we need to provide default values in case GetRenderState fails
275 DWORD abe, sb, db;
276 if (FAILED(pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe)))
277 abe = FALSE;
278 if (FAILED(pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb)))
279 sb = D3DBLEND_ONE;
280 if (FAILED(pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db)))
281 db = D3DBLEND_ZERO;
283 hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
284 hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
285 hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
286 hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
287 hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ...
288 hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst
290 hr = pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
291 hr = pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
292 hr = pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
294 if(pSrc == pDst) {
295 hr = pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
296 hr = pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);}
297 else {
298 hr = pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
299 hr = pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);}
300 hr = pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
302 hr = pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
303 hr = pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
304 hr = pD3DDev->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0xFF000000);
306 /*//
308 D3DCAPS9 d3dcaps9;
309 hr = pD3DDev->GetDeviceCaps(&d3dcaps9);
310 if(d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS)
312 hr = pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE);
313 hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
314 hr = pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS);
317 *///
319 hr = pD3DDev->SetPixelShader(NULL);
321 if((m_bExternalRenderer) && (FAILED(hr = pD3DDev->BeginScene())))
322 break;
324 hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
325 hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0]));
327 if(m_bExternalRenderer)
328 hr = pD3DDev->EndScene();
332 pD3DDev->SetTexture(0, NULL);
334 pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe);
335 pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb);
336 pD3DDev->SetRenderState(D3DRS_DESTBLEND, db);
338 return S_OK;
339 } while(0);
341 return E_FAIL;
345 // CDX9SubPicAllocator
348 CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9* pD3DDev, SIZE maxsize, bool fPow2Textures, bool bExternalRenderer)
349 : CSubPicAllocatorImpl(maxsize, true, fPow2Textures)
350 , m_pD3DDev(pD3DDev)
351 , m_maxsize(maxsize)
352 , m_bExternalRenderer(bExternalRenderer)
356 CCritSec CDX9SubPicAllocator::ms_SurfaceQueueLock;
358 CDX9SubPicAllocator::~CDX9SubPicAllocator()
360 ClearCache();
363 void CDX9SubPicAllocator::GetStats(int &_nFree, int &_nAlloc)
365 CAutoLock Lock(&ms_SurfaceQueueLock);
366 _nFree = m_FreeSurfaces.GetCount();
367 _nAlloc = m_AllocatedSurfaces.GetCount();
370 void CDX9SubPicAllocator::ClearCache()
373 // Clear the allocator of any remaining subpics
374 CAutoLock Lock(&ms_SurfaceQueueLock);
375 for (POSITION pos = m_AllocatedSurfaces.GetHeadPosition(); pos; ) {
376 CDX9SubPic *pSubPic = m_AllocatedSurfaces.GetNext(pos);
377 pSubPic->m_pAllocator = NULL;
379 m_AllocatedSurfaces.RemoveAll();
380 m_FreeSurfaces.RemoveAll();
384 // ISubPicAllocator
386 STDMETHODIMP CDX9SubPicAllocator::ChangeDevice(IUnknown* pDev)
388 ClearCache();
389 CComQIPtr<IDirect3DDevice9> pD3DDev = pDev;
390 if(!pD3DDev) {
391 return E_NOINTERFACE;
394 CAutoLock cAutoLock(this);
395 m_pD3DDev = pD3DDev;
397 return __super::ChangeDevice(pDev);
400 STDMETHODIMP CDX9SubPicAllocator::SetMaxTextureSize(SIZE MaxTextureSize)
402 ClearCache();
403 m_maxsize = MaxTextureSize;
404 SetCurSize(MaxTextureSize);
405 return S_OK;
408 // ISubPicAllocatorImpl
410 bool CDX9SubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic)
412 if(!ppSubPic) {
413 return false;
416 CAutoLock cAutoLock(this);
418 *ppSubPic = NULL;
420 CComPtr<IDirect3DSurface9> pSurface;
422 int Width = m_maxsize.cx;
423 int Height = m_maxsize.cy;
425 if(m_fPow2Textures) {
426 Width = Height = 1;
427 while(Width < m_maxsize.cx) {
428 Width <<= 1;
430 while(Height < m_maxsize.cy) {
431 Height <<= 1;
434 if (!fStatic) {
435 CAutoLock cAutoLock(&ms_SurfaceQueueLock);
436 POSITION FreeSurf = m_FreeSurfaces.GetHeadPosition();
437 if (FreeSurf) {
438 pSurface = m_FreeSurfaces.GetHead();
439 m_FreeSurfaces.RemoveHead();
443 if (!pSurface) {
444 CComPtr<IDirect3DTexture9> pTexture;
445 if(FAILED(m_pD3DDev->CreateTexture(Width, Height, 1, 0, D3DFMT_A8R8G8B8, fStatic?D3DPOOL_SYSTEMMEM:D3DPOOL_DEFAULT, &pTexture, NULL))) {
446 return false;
449 if(FAILED(pTexture->GetSurfaceLevel(0, &pSurface))) {
450 return false;
454 *ppSubPic = DNew CDX9SubPic(pSurface, fStatic ? 0 : this, m_bExternalRenderer);
455 if(!(*ppSubPic)) {
456 return false;
459 (*ppSubPic)->AddRef();
461 if (!fStatic) {
462 CAutoLock cAutoLock(&ms_SurfaceQueueLock);
463 m_AllocatedSurfaces.AddHead((CDX9SubPic *)*ppSubPic);
466 return true;