From d6482934be2e8b1361e20c2a86afea72f98dffaf Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Tue, 24 Sep 2013 13:14:11 +1200 Subject: [PATCH] Bug 912766. DIB texture client/host. r=mattwoodrow,jrmuizel --- gfx/layers/d3d9/TextureD3D9.cpp | 284 ++++++++++++++++++++------- gfx/layers/d3d9/TextureD3D9.h | 59 +++++- gfx/layers/ipc/ISurfaceAllocator.cpp | 1 + gfx/layers/ipc/LayersSurfaces.ipdlh | 6 + 4 files changed, 279 insertions(+), 71 deletions(-) diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index aabf476e7f65..c75014016f6c 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -460,6 +460,112 @@ DeprecatedTextureHostSystemMemD3D9::UpdateImpl(const SurfaceDescriptor& aImage, format, bpp); texture->UnlockRect(0); + if (!mTileTextures[i]) { + NS_WARNING("Could not upload texture"); + mSize.width = 0; + mSize.height = 0; + mIsTiled = false; + return; + } + } + } +} + +static TemporaryRef +SurfaceToTexture(IDirect3DDevice9* aDevice, + gfxWindowsSurface* aSurface, + const gfxIntSize& aSize, + _D3DFORMAT aFormat) +{ + RefPtr texture; + RefPtr surface; + D3DLOCKED_RECT lockedRect; + bool usingD3D9Ex; + + if (!InitTextures(aDevice, aSize, aFormat, + texture, surface, lockedRect, usingD3D9Ex)) { + return nullptr; + } + + nsRefPtr imgSurface = + new gfxImageSurface(reinterpret_cast(lockedRect.pBits), + gfxIntSize(aSize.width, aSize.height), + lockedRect.Pitch, + gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType())); + + nsRefPtr context = new gfxContext(imgSurface); + context->SetSource(aSurface); + context->SetOperator(gfxContext::OPERATOR_SOURCE); + context->Paint(); + + FinishTextures(aDevice, texture, surface, usingD3D9Ex); + + return texture.forget(); +} + +void +DeprecatedTextureHostDIB::UpdateImpl(const SurfaceDescriptor& aImage, + nsIntRegion *aRegion, + nsIntPoint *aOffset) +{ + MOZ_ASSERT(aImage.type() == SurfaceDescriptor::TSurfaceDescriptorDIB); + MOZ_ASSERT(mCompositor, "Must have compositor to update."); + + nsRefPtr surf = + reinterpret_cast(aImage.get_SurfaceDescriptorDIB().surface()); + // We added an extra ref for transport, we can release it now. + surf->Release(); + + gfxIntSize size = surf->GetSize(); + mSize = IntSize(size.width, size.height); + + uint32_t bpp = 0; + + _D3DFORMAT format = D3DFMT_A8R8G8B8; + switch (gfxPlatform::GetPlatform()->OptimalFormatForContent(surf->GetContentType())) { + case gfxImageSurface::ImageFormatRGB24: + mFormat = FORMAT_B8G8R8X8; + format = D3DFMT_X8R8G8B8; + bpp = 4; + break; + case gfxImageSurface::ImageFormatARGB32: + mFormat = FORMAT_B8G8R8A8; + format = D3DFMT_A8R8G8B8; + bpp = 4; + break; + case gfxImageSurface::ImageFormatA8: + mFormat = FORMAT_A8; + format = D3DFMT_A8; + bpp = 1; + break; + default: + NS_ERROR("Bad image format"); + } + + int32_t maxSize = mCompositor->GetMaxTextureSize(); + if (size.width <= maxSize && size.height <= maxSize) { + mTextures[0] = SurfaceToTexture(mDevice, surf, size, format); + NS_ASSERTION(mTextures[0], "Could not upload texture"); + mIsTiled = false; + } else { + mIsTiled = true; + + uint32_t tileCount = GetRequiredTiles(mSize.width, maxSize) * + GetRequiredTiles(mSize.height, maxSize); + mTileTextures.resize(tileCount); + + for (uint32_t i = 0; i < tileCount; i++) { + IntRect tileRect = GetTileRect(i); + nsRefPtr imgSurface = surf->GetAsImageSurface(); + unsigned char* data = imgSurface->Data() + + tileRect.y * imgSurface->Stride() + + tileRect.x * bpp; + mTileTextures[i] = DataToTexture(mDevice, + data, + imgSurface->Stride(), + gfxIntSize(tileRect.width, tileRect.height), + format, + bpp); } } } @@ -467,8 +573,6 @@ DeprecatedTextureHostSystemMemD3D9::UpdateImpl(const SurfaceDescriptor& aImage, DeprecatedTextureClientD3D9::DeprecatedTextureClientD3D9(CompositableForwarder* aCompositableForwarder, const TextureInfo& aTextureInfo) : DeprecatedTextureClient(aCompositableForwarder, aTextureInfo) - , mDC(nullptr) - , mTextureLocked(false) { MOZ_COUNT_CTOR(DeprecatedTextureClientD3D9); } @@ -479,7 +583,7 @@ DeprecatedTextureClientD3D9::~DeprecatedTextureClientD3D9() Unlock(); mDescriptor = SurfaceDescriptor(); - ClearDT(); + mDrawTarget = nullptr; } bool @@ -506,15 +610,12 @@ DeprecatedTextureClientD3D9::EnsureAllocated(gfx::IntSize aSize, switch (aType) { case gfxASurface::CONTENT_COLOR: format = D3DFMT_X8R8G8B8; - mIsOpaque = true; break; case gfxASurface::CONTENT_COLOR_ALPHA: - format = D3DFMT_A8R8G8B8; - mIsOpaque = false; - break; + // fallback to DIB texture client + return false; case gfxASurface::CONTENT_ALPHA: format = D3DFMT_A8; - mIsOpaque = true; break; default: NS_ERROR("Bad image type"); @@ -534,15 +635,6 @@ DeprecatedTextureClientD3D9::EnsureAllocated(gfx::IntSize aSize, MOZ_ASSERT(mTexture); mDescriptor = SurfaceDescriptorD3D9(reinterpret_cast(mTexture.get())); - if (!mIsOpaque) { - nsRefPtr surface = LockSurface(); - nsRefPtr ctx = new gfxContext(surface); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetColor(gfxRGBA(0.0, 0.0, 0.0, 0.0)); - ctx->Paint(); - Unlock(); - } - mContentType = aType; return true; } @@ -556,41 +648,21 @@ DeprecatedTextureClientD3D9::LockSurface() MOZ_ASSERT(mTexture, "Cannot lock surface without a texture to lock"); - if (mIsOpaque) { - MOZ_ASSERT(!mTextureLocked, "Shouldn't lock texture and have a surface"); - if (!mD3D9Surface) { - HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface)); - if (FAILED(hr)) { - NS_WARNING("Failed to get texture surface level."); - return nullptr; - } - } - - if (!mDC) { - HRESULT hr = mD3D9Surface->GetDC(&mDC); - if (FAILED(hr)) { - NS_WARNING("Failed to get device context for texture surface."); - return nullptr; - } - } - NS_ASSERTION(mDC, "We need a DC here"); - mSurface = new gfxWindowsSurface(mDC); - } else { - // d3d9 SYSTEMMEM surfaces do not support GDI with an alpha channel - MOZ_ASSERT(!mD3D9Surface && !mDC, "Shouldn't lock texture and have a surface"); - if (!mTextureLocked) { - D3DLOCKED_RECT lockedRect; - mTexture->LockRect(0, &lockedRect, nullptr, 0); - mTextureLocked = true; - - mSurface = new gfxImageSurface(reinterpret_cast(lockedRect.pBits), - gfxIntSize(mSize.width, mSize.height), - lockedRect.Pitch, - gfxASurface::ImageFormatARGB32); + if (!mD3D9Surface) { + HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface)); + if (FAILED(hr)) { + NS_WARNING("Failed to get texture surface level."); + return nullptr; } } - NS_ASSERTION(mSurface, "should have a surface one way or the other"); + mSurface = new gfxWindowsSurface(mD3D9Surface); + if (!mSurface || mSurface->CairoStatus()) { + NS_WARNING("Could not create surface for d3d9 surface"); + mSurface = nullptr; + return nullptr; + } + return mSurface.get(); } @@ -598,8 +670,10 @@ DrawTarget* DeprecatedTextureClientD3D9::LockDrawTarget() { if (!mDrawTarget) { - mDrawTarget = - gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(LockSurface(), mSize); + if (gfxASurface* surface = LockSurface()) { + mDrawTarget = + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(LockSurface(), mSize); + } } return mDrawTarget.get(); @@ -613,17 +687,6 @@ DeprecatedTextureClientD3D9::Unlock() mDrawTarget = nullptr; } - if (mTextureLocked) { - MOZ_ASSERT(!mD3D9Surface && !mDC, "Shouldn't lock texture and have a surface"); - mTexture->UnlockRect(0); - mTextureLocked = false; - } else if (mDC) { - MOZ_ASSERT(mD3D9Surface, "we need a D3D9Surface to release our DC"); - MOZ_ASSERT(!mTextureLocked, "Shouldn't lock texture and have a surface"); - mD3D9Surface->ReleaseDC(mDC); - mDC = nullptr; - } - if (mSurface) { mSurface = nullptr; } @@ -639,7 +702,7 @@ DeprecatedTextureClientD3D9::SetDescriptor(const SurfaceDescriptor& aDescriptor) mDescriptor = aDescriptor; mSurface = nullptr; - ClearDT(); + mDrawTarget = nullptr; if (aDescriptor.type() == SurfaceDescriptor::T__None) { return; @@ -652,14 +715,103 @@ DeprecatedTextureClientD3D9::SetDescriptor(const SurfaceDescriptor& aDescriptor) mDescriptor.get_SurfaceDescriptorD3D9().texture()); } -void -DeprecatedTextureClientD3D9::ClearDT() +DeprecatedTextureClientDIB::DeprecatedTextureClientDIB(CompositableForwarder* aCompositableForwarder, + const TextureInfo& aTextureInfo) + : DeprecatedTextureClient(aCompositableForwarder, aTextureInfo) +{ + MOZ_COUNT_CTOR(DeprecatedTextureClientDIB); +} + +DeprecatedTextureClientDIB::~DeprecatedTextureClientDIB() +{ + MOZ_COUNT_DTOR(DeprecatedTextureClientDIB); + Unlock(); + mDescriptor = SurfaceDescriptor(); + mDrawTarget = nullptr; +} + +bool +DeprecatedTextureClientDIB::EnsureAllocated(gfx::IntSize aSize, + gfxASurface::gfxContentType aType) +{ + if (mSurface) { + gfxIntSize size = mSurface->GetSize(); + if (size.width == aSize.width && + size.height == aSize.height) { + return true; + } + + Unlock(); + mSurface = nullptr; + } + + mSurface = new gfxWindowsSurface(gfxIntSize(aSize.width, aSize.height), + gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)); + if (!mSurface || mSurface->CairoStatus()) + { + NS_WARNING("Could not create surface"); + mSurface = nullptr; + return false; + } + mSize = aSize; + mContentType = aType; + + mDescriptor = SurfaceDescriptorDIB(reinterpret_cast(mSurface.get())); + // The host will release this ref when it receives the surface descriptor. + // We AddRef in case we die before the host receives the pointer. + mSurface->AddRef(); + + return true; +} + +gfxASurface* +DeprecatedTextureClientDIB::LockSurface() +{ + if (mSurface) { + return mSurface.get(); + } + + return nullptr; +} + +DrawTarget* +DeprecatedTextureClientDIB::LockDrawTarget() +{ + if (!mDrawTarget) { + if (gfxASurface* surface = LockSurface()) { + mDrawTarget = + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(LockSurface(), mSize); + } + } + + return mDrawTarget.get(); +} + +void +DeprecatedTextureClientDIB::Unlock() { - // Perhaps this should be debug only. if (mDrawTarget) { + mDrawTarget->Flush(); mDrawTarget = nullptr; } } +void +DeprecatedTextureClientDIB::SetDescriptor(const SurfaceDescriptor& aDescriptor) +{ + mDescriptor = aDescriptor; + mDrawTarget = nullptr; + + if (aDescriptor.type() == SurfaceDescriptor::T__None) { + mSurface = nullptr; + return; + } + + MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorDIB); + Unlock(); + mSurface = reinterpret_cast( + mDescriptor.get_SurfaceDescriptorDIB().surface()); +} + } } diff --git a/gfx/layers/d3d9/TextureD3D9.h b/gfx/layers/d3d9/TextureD3D9.h index 718bad3fbb96..4f5048f41eb2 100644 --- a/gfx/layers/d3d9/TextureD3D9.h +++ b/gfx/layers/d3d9/TextureD3D9.h @@ -212,6 +212,21 @@ private: RefPtr mDevice; }; +class DeprecatedTextureHostDIB : public DeprecatedTextureHostD3D9 +{ +public: +#ifdef MOZ_LAYERS_HAVE_LOG + virtual const char* Name() { return "DeprecatedTextureHostDIB"; } +#endif + +protected: + virtual void UpdateImpl(const SurfaceDescriptor& aSurface, + nsIntRegion* aRegion, + nsIntPoint *aOffset = nullptr) MOZ_OVERRIDE; + + nsRefPtr mTexture; +}; + // If we want to use d3d9 textures for transport, use this class. // If we are using shmem, then use DeprecatedTextureClientShmem with DeprecatedTextureHostShmemD3D9 // Since we pass a raw pointer, you should not use this texture client for @@ -246,17 +261,51 @@ public: } private: - void ClearDT(); - nsRefPtr mTexture; nsRefPtr mSurface; nsRefPtr mD3D9Surface; - HDC mDC; RefPtr mDrawTarget; gfx::IntSize mSize; gfxContentType mContentType; - bool mTextureLocked; - bool mIsOpaque; +}; + +// Retains a DIB and uses it for transport. +// Used where we can't efficently use a gfxWindowsSurface wrapped around +// a DC from a IDirect3DSurface9, which is for surfaces with alpha. +class DeprecatedTextureClientDIB : public DeprecatedTextureClient +{ +public: + DeprecatedTextureClientDIB(CompositableForwarder* aCompositableForwarder, + const TextureInfo& aTextureInfo); + virtual ~DeprecatedTextureClientDIB(); + + virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE + { + return aType == TEXTURE_CONTENT; + } + + virtual bool EnsureAllocated(gfx::IntSize aSize, + gfxASurface::gfxContentType aType) MOZ_OVERRIDE; + + virtual gfxASurface* LockSurface() MOZ_OVERRIDE; + virtual gfx::DrawTarget* LockDrawTarget() MOZ_OVERRIDE; + virtual gfx::BackendType BackendType() MOZ_OVERRIDE + { + return gfx::BACKEND_CAIRO; + } + virtual void Unlock() MOZ_OVERRIDE; + + virtual void SetDescriptor(const SurfaceDescriptor& aDescriptor) MOZ_OVERRIDE; + virtual gfxASurface::gfxContentType GetContentType() MOZ_OVERRIDE + { + return mContentType; + } + +private: + nsRefPtr mSurface; + RefPtr mDrawTarget; + gfx::IntSize mSize; + gfxContentType mContentType; }; } diff --git a/gfx/layers/ipc/ISurfaceAllocator.cpp b/gfx/layers/ipc/ISurfaceAllocator.cpp index 00c572f22cfd..c826f2ff77db 100644 --- a/gfx/layers/ipc/ISurfaceAllocator.cpp +++ b/gfx/layers/ipc/ISurfaceAllocator.cpp @@ -134,6 +134,7 @@ ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface) DeallocShmem(aSurface->get_RGBImage().data()); break; case SurfaceDescriptor::TSurfaceDescriptorD3D9: + case SurfaceDescriptor::TSurfaceDescriptorDIB: case SurfaceDescriptor::TSurfaceDescriptorD3D10: break; case SurfaceDescriptor::TMemoryImage: diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index ec1cf5e7c9bb..4c773fa03c9f 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -42,6 +42,11 @@ struct SurfaceDescriptorD3D9 { uintptr_t texture; }; +struct SurfaceDescriptorDIB { + // gfxWindowsSurface* + uintptr_t surface; +}; + struct SurfaceDescriptorD3D10 { WindowsHandle handle; bool hasAlpha; @@ -167,6 +172,7 @@ union SurfaceDescriptor { SurfaceDescriptorShmem; SurfaceDescriptorMemory; SurfaceDescriptorD3D9; + SurfaceDescriptorDIB; SurfaceDescriptorD3D10; SurfaceDescriptorX11; SharedTextureDescriptor;