Bug 584754: Use the D3D9Ex device where available. r=vlad

This commit is contained in:
Bas Schouten 2010-08-11 01:39:45 +02:00
parent 16fbc64865
commit 1174dba84a
4 changed files with 243 additions and 81 deletions

View File

@ -70,9 +70,17 @@ CanvasLayerD3D9::Initialize(const Data& aData)
mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
device()->CreateTexture(mBounds.width, mBounds.height, 1, 0, if (mD3DManager->deviceManager()->HasDynamicTextures()) {
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, device()->CreateTexture(mBounds.width, mBounds.height, 1, D3DUSAGE_DYNAMIC,
getter_AddRefs(mTexture), NULL); D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
getter_AddRefs(mTexture), NULL);
} else {
// D3DPOOL_MANAGED is fine here since we require Dynamic Textures for D3D9Ex
// devices.
device()->CreateTexture(mBounds.width, mBounds.height, 1, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
getter_AddRefs(mTexture), NULL);
}
} }
void void

View File

@ -47,10 +47,17 @@ namespace layers {
const LPCWSTR kClassName = L"D3D9WindowClass"; const LPCWSTR kClassName = L"D3D9WindowClass";
#define USE_D3D9EX
typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)( typedef IDirect3D9* (WINAPI*Direct3DCreate9Func)(
UINT SDKVersion UINT SDKVersion
); );
typedef HRESULT (WINAPI*Direct3DCreate9ExFunc)(
UINT SDKVersion,
IDirect3D9Ex **ppD3D
);
struct vertex { struct vertex {
float x, y; float x, y;
}; };
@ -171,6 +178,7 @@ SwapChainD3D9::Reset()
#define LACKS_CAP(a, b) !(((a) & (b)) == (b)) #define LACKS_CAP(a, b) !(((a) & (b)) == (b))
DeviceManagerD3D9::DeviceManagerD3D9() DeviceManagerD3D9::DeviceManagerD3D9()
: mHasDynamicTextures(false)
{ {
} }
@ -178,6 +186,8 @@ bool
DeviceManagerD3D9::Init() DeviceManagerD3D9::Init()
{ {
WNDCLASSW wc; WNDCLASSW wc;
HRESULT hr;
if (!GetClassInfoW(GetModuleHandle(NULL), kClassName, &wc)) { if (!GetClassInfoW(GetModuleHandle(NULL), kClassName, &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW)); ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.hInstance = GetModuleHandle(NULL); wc.hInstance = GetModuleHandle(NULL);
@ -198,14 +208,32 @@ DeviceManagerD3D9::Init()
return false; return false;
} }
Direct3DCreate9Func d3d9create = (Direct3DCreate9Func) HMODULE d3d9 = LoadLibraryW(L"d3d9.dll");
GetProcAddress(LoadLibraryW(L"d3d9.dll"), "Direct3DCreate9"); Direct3DCreate9Func d3d9Create = (Direct3DCreate9Func)
GetProcAddress(d3d9, "Direct3DCreate9");
Direct3DCreate9ExFunc d3d9CreateEx = (Direct3DCreate9ExFunc)
GetProcAddress(d3d9, "Direct3DCreate9Ex");
if (!d3d9create) { #ifdef USE_D3D9EX
return false; if (d3d9CreateEx) {
hr = d3d9CreateEx(D3D_SDK_VERSION, getter_AddRefs(mD3D9Ex));
if (SUCCEEDED(hr)) {
mD3D9 = mD3D9Ex;
}
} }
#endif
mD3D9 = dont_AddRef(d3d9create(D3D_SDK_VERSION)); if (!mD3D9) {
if (!d3d9Create) {
return false;
}
mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION));
if (!mD3D9) {
return false;
}
}
D3DPRESENT_PARAMETERS pp; D3DPRESENT_PARAMETERS pp;
memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS)); memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
@ -218,18 +246,47 @@ DeviceManagerD3D9::Init()
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
pp.hDeviceWindow = mFocusWnd; pp.hDeviceWindow = mFocusWnd;
HRESULT hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT, if (mD3D9Ex) {
D3DDEVTYPE_HAL, hr = mD3D9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
mFocusWnd, D3DDEVTYPE_HAL,
D3DCREATE_FPU_PRESERVE | mFocusWnd,
D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE |
D3DCREATE_MIXED_VERTEXPROCESSING, D3DCREATE_MULTITHREADED |
&pp, D3DCREATE_MIXED_VERTEXPROCESSING,
getter_AddRefs(mDevice)); &pp,
NULL,
getter_AddRefs(mDeviceEx));
if (SUCCEEDED(hr)) {
mDevice = mDeviceEx;
}
if (FAILED(hr)) { D3DCAPS9 caps;
NS_WARNING("Failed to create Device for DeviceManagerD3D9."); if (mDeviceEx->GetDeviceCaps(&caps)) {
return false; if (LACKS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) {
// XXX - Should we actually hit this we'll need a CanvasLayer that
// supports static D3DPOOL_DEFAULT textures.
NS_WARNING("D3D9Ex device not used because of lack of support for \
dynamic textures. This is unexpected.");
mDevice = nsnull;
mDeviceEx = nsnull;
}
}
}
if (!mDevice) {
hr = mD3D9->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
mFocusWnd,
D3DCREATE_FPU_PRESERVE |
D3DCREATE_MULTITHREADED |
D3DCREATE_MIXED_VERTEXPROCESSING,
&pp,
getter_AddRefs(mDevice));
if (FAILED(hr)) {
NS_WARNING("Failed to create Device for DeviceManagerD3D9.");
return false;
}
} }
if (!VerifyCaps()) { if (!VerifyCaps()) {
@ -265,9 +322,9 @@ DeviceManagerD3D9::Init()
} }
hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4, hr = mDevice->CreateVertexBuffer(sizeof(vertex) * 4,
D3DUSAGE_WRITEONLY,
0, 0,
0, D3DPOOL_DEFAULT,
D3DPOOL_MANAGED,
getter_AddRefs(mVB), getter_AddRefs(mVB),
NULL); NULL);
@ -385,6 +442,27 @@ DeviceManagerD3D9::VerifyReadyForRendering()
HRESULT hr = mDevice->TestCooperativeLevel(); HRESULT hr = mDevice->TestCooperativeLevel();
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
if (IsD3D9Ex()) {
hr = mDeviceEx->CheckDeviceState(mFocusWnd);
if (FAILED(hr)) {
D3DPRESENT_PARAMETERS pp;
memset(&pp, 0, sizeof(D3DPRESENT_PARAMETERS));
pp.BackBufferWidth = 1;
pp.BackBufferHeight = 1;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.Windowed = TRUE;
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
pp.hDeviceWindow = mFocusWnd;
hr = mDeviceEx->ResetEx(&pp, NULL);
// Handle D3DERR_DEVICEREMOVED!
if (FAILED(hr)) {
return false;
}
}
}
return true; return true;
} }
@ -473,6 +551,10 @@ DeviceManagerD3D9::VerifyCaps()
return false; return false;
} }
if (HAS_CAP(caps.Caps2, D3DCAPS2_DYNAMICTEXTURES)) {
mHasDynamicTextures = true;
}
return true; return true;
} }

View File

@ -124,6 +124,10 @@ public:
IDirect3DDevice9 *device() { return mDevice; } IDirect3DDevice9 *device() { return mDevice; }
bool IsD3D9Ex() { return mDeviceEx; }
bool HasDynamicTextures() { return mHasDynamicTextures; }
enum ShaderMode { enum ShaderMode {
RGBLAYER, RGBLAYER,
YCBCRLAYER, YCBCRLAYER,
@ -153,9 +157,15 @@ private:
/* The D3D device we use */ /* The D3D device we use */
nsRefPtr<IDirect3DDevice9> mDevice; nsRefPtr<IDirect3DDevice9> mDevice;
/* The D3D9Ex device - only valid on Vista+ with WDDM */
nsRefPtr<IDirect3DDevice9Ex> mDeviceEx;
/* An instance of the D3D9 object */ /* An instance of the D3D9 object */
nsRefPtr<IDirect3D9> mD3D9; nsRefPtr<IDirect3D9> mD3D9;
/* An instance of the D3D9Ex object - only valid on Vista+ with WDDM */
nsRefPtr<IDirect3D9Ex> mD3D9Ex;
/* Vertex shader used for layer quads */ /* Vertex shader used for layer quads */
nsRefPtr<IDirect3DVertexShader9> mLayerVS; nsRefPtr<IDirect3DVertexShader9> mLayerVS;
@ -179,6 +189,9 @@ private:
*/ */
HWND mFocusWnd; HWND mFocusWnd;
/* If this device supports dynamic textures */
bool mHasDynamicTextures;
nsAutoRefCnt mRefCnt; nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD NS_DECL_OWNINGTHREAD

View File

@ -244,6 +244,7 @@ PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9(mozilla::layers::LayerManagerD3D9* aM
void void
PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData) PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData)
{ {
// XXX - For D3D9Ex we really should just copy to systemmem surfaces here.
// For now, we copy the data // For now, we copy the data
int width_shift = 0; int width_shift = 0;
int height_shift = 0; int height_shift = 0;
@ -309,76 +310,116 @@ PlanarYCbCrImageD3D9::AllocateTextures()
{ {
D3DLOCKED_RECT lockrect; D3DLOCKED_RECT lockrectY;
D3DLOCKED_RECT lockrectCb;
D3DLOCKED_RECT lockrectCr;
PRUint8* src; PRUint8* src;
PRUint8* dest; PRUint8* dest;
//XXX: ensure correct usage flags
mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mYTexture), NULL);
nsRefPtr<IDirect3DSurface9> tmpSurfaceY;
nsRefPtr<IDirect3DSurface9> tmpSurfaceCb;
nsRefPtr<IDirect3DSurface9> tmpSurfaceCr;
/* lock the entire texture */ if (mManager->deviceManager()->IsD3D9Ex()) {
mYTexture->LockRect(0, &lockrect, NULL, 0); // D3D9Ex does not support the managed pool, could use dynamic textures
// here. But since an Image is immutable static textures are probably a
// better idea.
mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
getter_AddRefs(mYTexture), NULL);
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
getter_AddRefs(mCbTexture), NULL);
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_DEFAULT,
getter_AddRefs(mCrTexture), NULL);
mManager->device()->CreateOffscreenPlainSurface(mData.mYSize.width,
mData.mYSize.height,
D3DFMT_L8,
D3DPOOL_SYSTEMMEM,
getter_AddRefs(tmpSurfaceY),
NULL);
mManager->device()->CreateOffscreenPlainSurface(mData.mCbCrSize.width,
mData.mCbCrSize.height,
D3DFMT_L8,
D3DPOOL_SYSTEMMEM,
getter_AddRefs(tmpSurfaceCb),
NULL);
mManager->device()->CreateOffscreenPlainSurface(mData.mCbCrSize.width,
mData.mCbCrSize.height,
D3DFMT_L8,
D3DPOOL_SYSTEMMEM,
getter_AddRefs(tmpSurfaceCr),
NULL);
tmpSurfaceY->LockRect(&lockrectY, NULL, 0);
tmpSurfaceCb->LockRect(&lockrectCb, NULL, 0);
tmpSurfaceCr->LockRect(&lockrectCr, NULL, 0);
} else {
mManager->device()->CreateTexture(mData.mYSize.width, mData.mYSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mYTexture), NULL);
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mCbTexture), NULL);
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mCrTexture), NULL);
/* lock the entire texture */
mYTexture->LockRect(0, &lockrectY, NULL, 0);
mCbTexture->LockRect(0, &lockrectCb, NULL, 0);
mCrTexture->LockRect(0, &lockrectCr, NULL, 0);
}
src = mData.mYChannel; src = mData.mYChannel;
//FIX cast //FIX cast
dest = (PRUint8*)lockrect.pBits; dest = (PRUint8*)lockrectY.pBits;
// copy over data // copy over data
for (int h=0; h<mData.mYSize.height; h++) { for (int h=0; h<mData.mYSize.height; h++) {
memcpy(dest, src, mData.mYSize.width); memcpy(dest, src, mData.mYSize.width);
dest += lockrect.Pitch; dest += lockrectY.Pitch;
src += mData.mYStride; src += mData.mYStride;
} }
mYTexture->UnlockRect(0);
//XXX: ensure correct usage flags
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mCbTexture), NULL);
/* lock the entire texture */
mCbTexture->LockRect(0, &lockrect, NULL, 0);
src = mData.mCbChannel; src = mData.mCbChannel;
//FIX cast //FIX cast
dest = (PRUint8*)lockrect.pBits; dest = (PRUint8*)lockrectCb.pBits;
// copy over data // copy over data
for (int h=0; h<mData.mCbCrSize.height; h++) { for (int h=0; h<mData.mCbCrSize.height; h++) {
memcpy(dest, src, mData.mCbCrSize.width); memcpy(dest, src, mData.mCbCrSize.width);
dest += lockrect.Pitch; dest += lockrectCb.Pitch;
src += mData.mCbCrStride; src += mData.mCbCrStride;
} }
mCbTexture->UnlockRect(0);
//XXX: ensure correct usage flags
mManager->device()->CreateTexture(mData.mCbCrSize.width, mData.mCbCrSize.height,
1, 0, D3DFMT_L8, D3DPOOL_MANAGED,
getter_AddRefs(mCrTexture), NULL);
/* lock the entire texture */
mCrTexture->LockRect(0, &lockrect, NULL, 0);
src = mData.mCrChannel; src = mData.mCrChannel;
//FIX cast //FIX cast
dest = (PRUint8*)lockrect.pBits; dest = (PRUint8*)lockrectCr.pBits;
// copy over data // copy over data
for (int h=0; h<mData.mCbCrSize.height; h++) { for (int h=0; h<mData.mCbCrSize.height; h++) {
memcpy(dest, src, mData.mCbCrSize.width); memcpy(dest, src, mData.mCbCrSize.width);
dest += lockrect.Pitch; dest += lockrectCr.Pitch;
src += mData.mCbCrStride; src += mData.mCbCrStride;
} }
mCrTexture->UnlockRect(0); if (mManager->deviceManager()->IsD3D9Ex()) {
tmpSurfaceY->UnlockRect();
tmpSurfaceCb->UnlockRect();
tmpSurfaceCr->UnlockRect();
nsRefPtr<IDirect3DSurface9> dstSurface;
mYTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
mManager->device()->UpdateSurface(tmpSurfaceY, NULL, dstSurface, NULL);
mCbTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
mManager->device()->UpdateSurface(tmpSurfaceCb, NULL, dstSurface, NULL);
mCrTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
mManager->device()->UpdateSurface(tmpSurfaceCr, NULL, dstSurface, NULL);
} else {
mYTexture->UnlockRect(0);
mCbTexture->UnlockRect(0);
mCrTexture->UnlockRect(0);
}
} }
void void
@ -426,31 +467,49 @@ CairoImageD3D9::SetData(const CairoImage::Data &aData)
context->SetSource(aData.mSurface); context->SetSource(aData.mSurface);
context->Paint(); context->Paint();
//XXX: make sure we're using the correct usage flags if (mManager->deviceManager()->IsD3D9Ex()) {
mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height, // D3D9Ex doesn't support managed textures. We could use dynamic textures
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, // here but since Images are immutable that probably isn't such a great
getter_AddRefs(mTexture), NULL); // idea.
mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height,
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
getter_AddRefs(mTexture), NULL);
nsRefPtr<IDirect3DSurface9> surface;
mManager->device()->CreateOffscreenPlainSurface(aData.mSize.width,
aData.mSize.height,
D3DFMT_A8R8G8B8,
D3DPOOL_SYSTEMMEM,
getter_AddRefs(surface),
NULL);
D3DLOCKED_RECT lockedRect;
surface->LockRect(&lockedRect, NULL, 0);
for (int y = 0; y < aData.mSize.height; y++) {
memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData.mSize.width * 4);
}
surface->UnlockRect();
nsRefPtr<IDirect3DSurface9> dstSurface;
mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
mManager->device()->UpdateSurface(surface, NULL, dstSurface, NULL);
} else {
mManager->device()->CreateTexture(aData.mSize.width, aData.mSize.height,
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
getter_AddRefs(mTexture), NULL);
D3DLOCKED_RECT lockrect;
/* lock the entire texture */
mTexture->LockRect(0, &lockrect, NULL, 0);
D3DLOCKED_RECT lockrect; // copy over data. If we don't need to do any swaping we can
/* lock the entire texture */ // use memcpy
mTexture->LockRect(0, &lockrect, NULL, 0); for (int y = 0; y < aData.mSize.height; y++) {
memcpy((char*)lockrect.pBits + lockrect.Pitch * y,
imageSurface->Data() + imageSurface->Stride() * y,
aData.mSize.width * 4);
}
PRUint8* src = imageSurface->Data(); mTexture->UnlockRect(0);
//FIX cast
PRUint8* dest = (PRUint8*)lockrect.pBits;
// copy over data. If we don't need to do any swaping we can
// use memcpy
for (int i=0; i<aData.mSize.width*aData.mSize.height; i++) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
dest += 4;
src += 4;
} }
mTexture->UnlockRect(0);
} }
already_AddRefed<gfxASurface> already_AddRefed<gfxASurface>