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)
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
25 #include "DX9SubPic.h"
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
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
);
56 m_pAllocator
->m_FreeSurfaces
.AddTail(m_pSurface
);
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
;
74 STDMETHODIMP
CDX9SubPic::GetDesc(SubPicDesc
& spd
) const
76 D3DSURFACE_DESC d3dsd
;
77 ZeroMemory(&d3dsd
, sizeof(d3dsd
));
78 if(FAILED(m_pSurface
->GetDesc(&d3dsd
))) {
86 d3dsd
.Format
== D3DFMT_A8R8G8B8
? 32 :
87 d3dsd
.Format
== D3DFMT_A4R4G4B4
? 16 : 0;
90 spd
.vidrect
= m_vidrect
;
95 STDMETHODIMP
CDX9SubPic::CopyTo(ISubPic
* pSubPic
)
98 if(FAILED(hr
= __super::CopyTo(pSubPic
))) {
102 if(m_rcDirty
.IsRectEmpty()) {
106 CComPtr
<IDirect3DDevice9
> pD3DDev
;
107 if(!m_pSurface
|| FAILED(m_pSurface
->GetDevice(&pD3DDev
)) || !pD3DDev
) {
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
);
124 SetRect(&r
, 0, 0, min(srcDesc
.Width
, dstDesc
.Width
), min(srcDesc
.Height
, dstDesc
.Height
));
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()) {
138 CComPtr
<IDirect3DDevice9
> pD3DDev
;
139 if(!m_pSurface
|| FAILED(m_pSurface
->GetDevice(&pD3DDev
)) || !pD3DDev
) {
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);
151 memsetw(ptr
, color
, 2 * m_rcDirty
.Width());
154 } else if(spd
.bpp
== 32) {
156 memsetd(ptr
, color
, 4 * m_rcDirty
.Width());
161 DWORD* ptr = (DWORD*)bm.bits;
162 DWORD* end = ptr + bm.h*bm.wBytes/4;
163 while(ptr < end) *ptr++ = color;
168 // HRESULT hr = pD3DDev->ColorFill(m_pSurface, m_rcDirty, color);
170 m_rcDirty
.SetRectEmpty();
175 STDMETHODIMP
CDX9SubPic::Lock(SubPicDesc
& spd
)
177 D3DSURFACE_DESC d3dsd
;
178 ZeroMemory(&d3dsd
, sizeof(d3dsd
));
179 if(FAILED(m_pSurface
->GetDesc(&d3dsd
))) {
183 D3DLOCKED_RECT LockedRect
;
184 ZeroMemory(&LockedRect
, sizeof(LockedRect
));
185 if(FAILED(m_pSurface
->LockRect(&LockedRect
, NULL
, D3DLOCK_NO_DIRTY_UPDATE
|D3DLOCK_NOSYSLOCK
))) {
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
;
202 STDMETHODIMP
CDX9SubPic::Unlock(RECT
* pDirtyRect
)
204 HRESULT hr
= m_pSurface
->UnlockRect();
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
);
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
);
227 STDMETHODIMP
CDX9SubPic::AlphaBlt(const RECT
* pSrc
, const RECT
* pDst
, SubPicDesc
* pTarget
)
229 ASSERT(pTarget
== NULL
);
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
;
246 D3DSURFACE_DESC d3dsd
;
247 ZeroMemory(&d3dsd
, sizeof(d3dsd
));
248 if(FAILED(pTexture
->GetLevelDesc(0, &d3dsd
)) /*|| d3dsd.Type != D3DRTYPE_TEXTURE*/) {
252 float w
= (float)d3dsd
.Width
;
253 float h
= (float)d3dsd
.Height
;
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
276 if (FAILED(pD3DDev
->GetRenderState(D3DRS_ALPHABLENDENABLE
, &abe
)))
278 if (FAILED(pD3DDev
->GetRenderState(D3DRS_SRCBLEND
, &sb
)))
280 if (FAILED(pD3DDev
->GetRenderState(D3DRS_DESTBLEND
, &db
)))
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
);
295 hr
= pD3DDev
->SetSamplerState(0, D3DSAMP_MAGFILTER
, D3DTEXF_POINT
);
296 hr
= pD3DDev
->SetSamplerState(0, D3DSAMP_MINFILTER
, D3DTEXF_POINT
);}
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);
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);
319 hr
= pD3DDev
->SetPixelShader(NULL
);
321 if((m_bExternalRenderer
) && (FAILED(hr
= pD3DDev
->BeginScene())))
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
);
345 // CDX9SubPicAllocator
348 CDX9SubPicAllocator::CDX9SubPicAllocator(IDirect3DDevice9
* pD3DDev
, SIZE maxsize
, bool fPow2Textures
, bool bExternalRenderer
)
349 : CSubPicAllocatorImpl(maxsize
, true, fPow2Textures
)
352 , m_bExternalRenderer(bExternalRenderer
)
356 CCritSec
CDX9SubPicAllocator::ms_SurfaceQueueLock
;
358 CDX9SubPicAllocator::~CDX9SubPicAllocator()
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();
386 STDMETHODIMP
CDX9SubPicAllocator::ChangeDevice(IUnknown
* pDev
)
389 CComQIPtr
<IDirect3DDevice9
> pD3DDev
= pDev
;
391 return E_NOINTERFACE
;
394 CAutoLock
cAutoLock(this);
397 return __super::ChangeDevice(pDev
);
400 STDMETHODIMP
CDX9SubPicAllocator::SetMaxTextureSize(SIZE MaxTextureSize
)
403 m_maxsize
= MaxTextureSize
;
404 SetCurSize(MaxTextureSize
);
408 // ISubPicAllocatorImpl
410 bool CDX9SubPicAllocator::Alloc(bool fStatic
, ISubPic
** ppSubPic
)
416 CAutoLock
cAutoLock(this);
420 CComPtr
<IDirect3DSurface9
> pSurface
;
422 int Width
= m_maxsize
.cx
;
423 int Height
= m_maxsize
.cy
;
425 if(m_fPow2Textures
) {
427 while(Width
< m_maxsize
.cx
) {
430 while(Height
< m_maxsize
.cy
) {
435 CAutoLock
cAutoLock(&ms_SurfaceQueueLock
);
436 POSITION FreeSurf
= m_FreeSurfaces
.GetHeadPosition();
438 pSurface
= m_FreeSurfaces
.GetHead();
439 m_FreeSurfaces
.RemoveHead();
444 CComPtr
<IDirect3DTexture9
> pTexture
;
445 if(FAILED(m_pD3DDev
->CreateTexture(Width
, Height
, 1, 0, D3DFMT_A8R8G8B8
, fStatic
?D3DPOOL_SYSTEMMEM
:D3DPOOL_DEFAULT
, &pTexture
, NULL
))) {
449 if(FAILED(pTexture
->GetSurfaceLevel(0, &pSurface
))) {
454 *ppSubPic
= DNew
CDX9SubPic(pSurface
, fStatic
? 0 : this, m_bExternalRenderer
);
459 (*ppSubPic
)->AddRef();
462 CAutoLock
cAutoLock(&ms_SurfaceQueueLock
);
463 m_AllocatedSurfaces
.AddHead((CDX9SubPic
*)*ppSubPic
);