michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TextureD3D9.h" michael@0: #include "CompositorD3D9.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxImageSurface.h" michael@0: #include "Effects.h" michael@0: #include "mozilla/layers/YCbCrImageDataSerializer.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfx2DGlue.h" michael@0: #include "gfxUtils.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: static uint32_t GetRequiredTilesD3D9(uint32_t aSize, uint32_t aMaxSize) michael@0: { michael@0: uint32_t requiredTiles = aSize / aMaxSize; michael@0: if (aSize % aMaxSize) { michael@0: requiredTiles++; michael@0: } michael@0: return requiredTiles; michael@0: } michael@0: michael@0: TextureSourceD3D9::~TextureSourceD3D9() michael@0: { michael@0: MOZ_ASSERT(!mCreatingDeviceManager || michael@0: mCreatingDeviceManager->IsInTextureHostList(this), michael@0: "Inconsistency in list of texture hosts."); michael@0: // Remove ourselves from the list of d3d9 texture hosts. michael@0: if (mPreviousHost) { michael@0: MOZ_ASSERT(mPreviousHost->mNextHost == this); michael@0: mPreviousHost->mNextHost = mNextHost; michael@0: } else if (mCreatingDeviceManager) { michael@0: mCreatingDeviceManager->RemoveTextureListHead(this); michael@0: } michael@0: if (mNextHost) { michael@0: MOZ_ASSERT(mNextHost->mPreviousHost == this); michael@0: mNextHost->mPreviousHost = mPreviousHost; michael@0: } michael@0: } michael@0: michael@0: TemporaryRef michael@0: CreateTextureHostD3D9(const SurfaceDescriptor& aDesc, michael@0: ISurfaceAllocator* aDeallocator, michael@0: TextureFlags aFlags) michael@0: { michael@0: RefPtr result; michael@0: switch (aDesc.type()) { michael@0: case SurfaceDescriptor::TSurfaceDescriptorShmem: michael@0: case SurfaceDescriptor::TSurfaceDescriptorMemory: { michael@0: result = CreateBackendIndependentTextureHost(aDesc, aDeallocator, aFlags); michael@0: break; michael@0: } michael@0: case SurfaceDescriptor::TSurfaceDescriptorD3D9: { michael@0: result = new TextureHostD3D9(aFlags, aDesc); michael@0: break; michael@0: } michael@0: case SurfaceDescriptor::TSurfaceDescriptorDIB: { michael@0: result = new DIBTextureHostD3D9(aFlags, aDesc); michael@0: break; michael@0: } michael@0: case SurfaceDescriptor::TSurfaceDescriptorD3D10: { michael@0: result = new DXGITextureHostD3D9(aFlags, aDesc); michael@0: break; michael@0: } michael@0: default: { michael@0: NS_WARNING("Unsupported SurfaceDescriptor type"); michael@0: } michael@0: } michael@0: return result.forget(); michael@0: } michael@0: michael@0: static SurfaceFormat michael@0: D3D9FormatToSurfaceFormat(_D3DFORMAT format) michael@0: { michael@0: switch (format) { michael@0: case D3DFMT_X8R8G8B8: michael@0: return SurfaceFormat::B8G8R8X8; michael@0: case D3DFMT_A8R8G8B8: michael@0: return SurfaceFormat::B8G8R8A8; michael@0: case D3DFMT_A8: michael@0: return SurfaceFormat::A8; michael@0: default: michael@0: NS_ERROR("Bad texture format"); michael@0: } michael@0: return SurfaceFormat::UNKNOWN; michael@0: } michael@0: michael@0: static _D3DFORMAT michael@0: SurfaceFormatToD3D9Format(SurfaceFormat format) michael@0: { michael@0: switch (format) { michael@0: case SurfaceFormat::B8G8R8X8: michael@0: return D3DFMT_X8R8G8B8; michael@0: case SurfaceFormat::B8G8R8A8: michael@0: return D3DFMT_A8R8G8B8; michael@0: case SurfaceFormat::A8: michael@0: return D3DFMT_A8; michael@0: default: michael@0: NS_ERROR("Bad texture format"); michael@0: } michael@0: return D3DFMT_A8R8G8B8; michael@0: } michael@0: michael@0: CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture, michael@0: SurfaceInitMode aInit, michael@0: const gfx::IntRect& aRect) michael@0: : CompositingRenderTarget(aRect.TopLeft()) michael@0: , mInitMode(aInit) michael@0: , mInitialized(false) michael@0: { michael@0: MOZ_COUNT_CTOR(CompositingRenderTargetD3D9); michael@0: MOZ_ASSERT(aTexture); michael@0: michael@0: mTexture = aTexture; michael@0: HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface)); michael@0: NS_ASSERTION(mSurface, "Couldn't create surface for texture"); michael@0: TextureSourceD3D9::SetSize(aRect.Size()); michael@0: } michael@0: michael@0: CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DSurface9* aSurface, michael@0: SurfaceInitMode aInit, michael@0: const gfx::IntRect& aRect) michael@0: : CompositingRenderTarget(aRect.TopLeft()) michael@0: , mSurface(aSurface) michael@0: , mInitMode(aInit) michael@0: , mInitialized(false) michael@0: { michael@0: MOZ_COUNT_CTOR(CompositingRenderTargetD3D9); michael@0: MOZ_ASSERT(mSurface); michael@0: TextureSourceD3D9::SetSize(aRect.Size()); michael@0: } michael@0: michael@0: CompositingRenderTargetD3D9::~CompositingRenderTargetD3D9() michael@0: { michael@0: MOZ_COUNT_DTOR(CompositingRenderTargetD3D9); michael@0: } michael@0: michael@0: void michael@0: CompositingRenderTargetD3D9::BindRenderTarget(IDirect3DDevice9* aDevice) michael@0: { michael@0: aDevice->SetRenderTarget(0, mSurface); michael@0: if (!mInitialized && michael@0: mInitMode == INIT_MODE_CLEAR) { michael@0: mInitialized = true; michael@0: aDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0); michael@0: } michael@0: } michael@0: michael@0: IntSize michael@0: CompositingRenderTargetD3D9::GetSize() const michael@0: { michael@0: return TextureSourceD3D9::GetSize(); michael@0: } michael@0: michael@0: /** michael@0: * Helper method for DataToTexture and SurfaceToTexture. michael@0: * The last three params are out params. michael@0: * Returns the created texture, or null if we fail. michael@0: */ michael@0: TemporaryRef michael@0: TextureSourceD3D9::InitTextures(DeviceManagerD3D9* aDeviceManager, michael@0: const IntSize &aSize, michael@0: _D3DFORMAT aFormat, michael@0: RefPtr& aSurface, michael@0: D3DLOCKED_RECT& aLockedRect) michael@0: { michael@0: if (!aDeviceManager) { michael@0: return nullptr; michael@0: } michael@0: RefPtr result; michael@0: // D3D9Ex doesn't support managed textures and we don't want the hassle even michael@0: // if we don't have Ex. We could use dynamic textures michael@0: // here but since Images are immutable that probably isn't such a great michael@0: // idea. michael@0: result = aDeviceManager->CreateTexture(aSize, aFormat, D3DPOOL_DEFAULT, this); michael@0: if (!result) { michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr tmpTexture = michael@0: aDeviceManager->CreateTexture(aSize, aFormat, D3DPOOL_SYSTEMMEM, this); michael@0: if (!tmpTexture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: tmpTexture->GetSurfaceLevel(0, byRef(aSurface)); michael@0: aSurface->LockRect(&aLockedRect, nullptr, 0); michael@0: if (!aLockedRect.pBits) { michael@0: NS_WARNING("Could not lock surface"); michael@0: return nullptr; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: /** michael@0: * Helper method for DataToTexture and SurfaceToTexture. michael@0: */ michael@0: static void michael@0: FinishTextures(DeviceManagerD3D9* aDeviceManager, michael@0: IDirect3DTexture9* aTexture, michael@0: IDirect3DSurface9* aSurface) michael@0: { michael@0: if (!aDeviceManager) { michael@0: return; michael@0: } michael@0: michael@0: aSurface->UnlockRect(); michael@0: nsRefPtr dstSurface; michael@0: aTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); michael@0: aDeviceManager->device()->UpdateSurface(aSurface, nullptr, dstSurface, michael@0: nullptr); michael@0: } michael@0: michael@0: TemporaryRef michael@0: TextureSourceD3D9::DataToTexture(DeviceManagerD3D9* aDeviceManager, michael@0: unsigned char *aData, michael@0: int aStride, michael@0: const IntSize &aSize, michael@0: _D3DFORMAT aFormat, michael@0: uint32_t aBPP) michael@0: { michael@0: RefPtr surface; michael@0: D3DLOCKED_RECT lockedRect; michael@0: RefPtr texture = InitTextures(aDeviceManager, aSize, aFormat, michael@0: surface, lockedRect); michael@0: if (!texture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: uint32_t width = aSize.width * aBPP; michael@0: michael@0: for (int y = 0; y < aSize.height; y++) { michael@0: memcpy((char*)lockedRect.pBits + lockedRect.Pitch * y, michael@0: aData + aStride * y, michael@0: width); michael@0: } michael@0: michael@0: FinishTextures(aDeviceManager, texture, surface); michael@0: michael@0: return texture; michael@0: } michael@0: michael@0: TemporaryRef michael@0: TextureSourceD3D9::TextureToTexture(DeviceManagerD3D9* aDeviceManager, michael@0: IDirect3DTexture9* aTexture, michael@0: const IntSize& aSize, michael@0: _D3DFORMAT aFormat) michael@0: { michael@0: if (!aDeviceManager) { michael@0: return nullptr; michael@0: } michael@0: michael@0: RefPtr texture = michael@0: aDeviceManager->CreateTexture(aSize, aFormat, D3DPOOL_DEFAULT, this); michael@0: if (!texture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: HRESULT hr = aDeviceManager->device()->UpdateTexture(aTexture, texture); michael@0: if (FAILED(hr)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return texture; michael@0: } michael@0: michael@0: TemporaryRef michael@0: TextureSourceD3D9::SurfaceToTexture(DeviceManagerD3D9* aDeviceManager, michael@0: gfxWindowsSurface* aSurface, michael@0: const IntSize& aSize, michael@0: _D3DFORMAT aFormat) michael@0: { michael@0: RefPtr surface; michael@0: D3DLOCKED_RECT lockedRect; michael@0: michael@0: RefPtr texture = InitTextures(aDeviceManager, aSize, aFormat, michael@0: surface, lockedRect); michael@0: if (!texture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr imgSurface = michael@0: new gfxImageSurface(reinterpret_cast(lockedRect.pBits), michael@0: gfxIntSize(aSize.width, aSize.height), michael@0: lockedRect.Pitch, michael@0: gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType())); michael@0: michael@0: nsRefPtr context = new gfxContext(imgSurface); michael@0: context->SetSource(aSurface); michael@0: context->SetOperator(gfxContext::OPERATOR_SOURCE); michael@0: context->Paint(); michael@0: michael@0: FinishTextures(aDeviceManager, texture, surface); michael@0: michael@0: return texture; michael@0: } michael@0: michael@0: class D3D9TextureClientData : public TextureClientData michael@0: { michael@0: public: michael@0: D3D9TextureClientData(IDirect3DTexture9* aTexture) michael@0: : mTexture(aTexture) michael@0: {} michael@0: michael@0: D3D9TextureClientData(gfxWindowsSurface* aWindowSurface) michael@0: : mWindowSurface(aWindowSurface) michael@0: {} michael@0: michael@0: virtual void DeallocateSharedData(ISurfaceAllocator*) MOZ_OVERRIDE michael@0: { michael@0: mWindowSurface = nullptr; michael@0: mTexture = nullptr; michael@0: } michael@0: michael@0: private: michael@0: RefPtr mTexture; michael@0: nsRefPtr mWindowSurface; michael@0: }; michael@0: michael@0: DataTextureSourceD3D9::DataTextureSourceD3D9(gfx::SurfaceFormat aFormat, michael@0: CompositorD3D9* aCompositor, michael@0: TextureFlags aFlags, michael@0: StereoMode aStereoMode) michael@0: : mFormat(aFormat) michael@0: , mCompositor(aCompositor) michael@0: , mCurrentTile(0) michael@0: , mFlags(aFlags) michael@0: , mIsTiled(false) michael@0: , mIterating(false) michael@0: { michael@0: mStereoMode = aStereoMode; michael@0: MOZ_COUNT_CTOR(DataTextureSourceD3D9); michael@0: } michael@0: michael@0: DataTextureSourceD3D9::DataTextureSourceD3D9(gfx::SurfaceFormat aFormat, michael@0: gfx::IntSize aSize, michael@0: CompositorD3D9* aCompositor, michael@0: IDirect3DTexture9* aTexture, michael@0: TextureFlags aFlags) michael@0: : mFormat(aFormat) michael@0: , mCompositor(aCompositor) michael@0: , mCurrentTile(0) michael@0: , mFlags(aFlags) michael@0: , mIsTiled(false) michael@0: , mIterating(false) michael@0: { michael@0: mSize = aSize; michael@0: mTexture = aTexture; michael@0: mStereoMode = StereoMode::MONO; michael@0: MOZ_COUNT_CTOR(DataTextureSourceD3D9); michael@0: } michael@0: michael@0: DataTextureSourceD3D9::~DataTextureSourceD3D9() michael@0: { michael@0: MOZ_COUNT_DTOR(DataTextureSourceD3D9); michael@0: } michael@0: michael@0: IDirect3DTexture9* michael@0: DataTextureSourceD3D9::GetD3D9Texture() michael@0: { michael@0: return mIterating ? mTileTextures[mCurrentTile] michael@0: : mTexture; michael@0: } michael@0: michael@0: bool michael@0: DataTextureSourceD3D9::Update(gfx::DataSourceSurface* aSurface, michael@0: nsIntRegion* aDestRegion, michael@0: gfx::IntPoint* aSrcOffset) michael@0: { michael@0: // Right now we only support full surface update. If aDestRegion is provided, michael@0: // It will be ignored. Incremental update with a source offset is only used michael@0: // on Mac so it is not clear that we ever will need to support it for D3D. michael@0: MOZ_ASSERT(!aSrcOffset); michael@0: michael@0: if (!mCompositor || !mCompositor->device()) { michael@0: NS_WARNING("No D3D device to update the texture."); michael@0: return false; michael@0: } michael@0: mSize = aSurface->GetSize(); michael@0: michael@0: uint32_t bpp = 0; michael@0: michael@0: _D3DFORMAT format = D3DFMT_A8R8G8B8; michael@0: mFormat = aSurface->GetFormat(); michael@0: switch (mFormat) { michael@0: case SurfaceFormat::B8G8R8X8: michael@0: format = D3DFMT_X8R8G8B8; michael@0: bpp = 4; michael@0: break; michael@0: case SurfaceFormat::B8G8R8A8: michael@0: format = D3DFMT_A8R8G8B8; michael@0: bpp = 4; michael@0: break; michael@0: case SurfaceFormat::A8: michael@0: format = D3DFMT_A8; michael@0: bpp = 1; michael@0: break; michael@0: default: michael@0: NS_WARNING("Bad image format"); michael@0: return false; michael@0: } michael@0: michael@0: int32_t maxSize = mCompositor->GetMaxTextureSize(); michael@0: DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if ((mSize.width <= maxSize && mSize.height <= maxSize) || michael@0: (mFlags & TEXTURE_DISALLOW_BIGIMAGE)) { michael@0: mTexture = DataToTexture(deviceManager, michael@0: aSurface->GetData(), aSurface->Stride(), michael@0: IntSize(mSize), format, bpp); michael@0: if (!mTexture) { michael@0: NS_WARNING("Could not upload texture"); michael@0: Reset(); michael@0: return false; michael@0: } michael@0: mIsTiled = false; michael@0: } else { michael@0: mIsTiled = true; michael@0: uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) * michael@0: GetRequiredTilesD3D9(mSize.height, maxSize); michael@0: mTileTextures.resize(tileCount); michael@0: mTexture = nullptr; michael@0: michael@0: for (uint32_t i = 0; i < tileCount; i++) { michael@0: IntRect tileRect = GetTileRect(i); michael@0: unsigned char* data = aSurface->GetData() + michael@0: tileRect.y * aSurface->Stride() + michael@0: tileRect.x * bpp; michael@0: mTileTextures[i] = DataToTexture(deviceManager, michael@0: data, michael@0: aSurface->Stride(), michael@0: IntSize(tileRect.width, tileRect.height), michael@0: format, michael@0: bpp); michael@0: if (!mTileTextures[i]) { michael@0: NS_WARNING("Could not upload texture"); michael@0: Reset(); michael@0: return false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: DataTextureSourceD3D9::Update(gfxWindowsSurface* aSurface) michael@0: { michael@0: MOZ_ASSERT(aSurface); michael@0: if (!mCompositor || !mCompositor->device()) { michael@0: NS_WARNING("No D3D device to update the texture."); michael@0: return false; michael@0: } michael@0: mSize = ToIntSize(aSurface->GetSize()); michael@0: michael@0: uint32_t bpp = 0; michael@0: michael@0: _D3DFORMAT format = D3DFMT_A8R8G8B8; michael@0: mFormat = ImageFormatToSurfaceFormat( michael@0: gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType())); michael@0: switch (mFormat) { michael@0: case SurfaceFormat::B8G8R8X8: michael@0: format = D3DFMT_X8R8G8B8; michael@0: bpp = 4; michael@0: break; michael@0: case SurfaceFormat::B8G8R8A8: michael@0: format = D3DFMT_A8R8G8B8; michael@0: bpp = 4; michael@0: break; michael@0: case SurfaceFormat::A8: michael@0: format = D3DFMT_A8; michael@0: bpp = 1; michael@0: break; michael@0: default: michael@0: NS_WARNING("Bad image format"); michael@0: return false; michael@0: } michael@0: michael@0: int32_t maxSize = mCompositor->GetMaxTextureSize(); michael@0: DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if ((mSize.width <= maxSize && mSize.height <= maxSize) || michael@0: (mFlags & TEXTURE_DISALLOW_BIGIMAGE)) { michael@0: mTexture = SurfaceToTexture(deviceManager, aSurface, mSize, format); michael@0: michael@0: if (!mTexture) { michael@0: NS_WARNING("Could not upload texture"); michael@0: Reset(); michael@0: return false; michael@0: } michael@0: mIsTiled = false; michael@0: } else { michael@0: mIsTiled = true; michael@0: uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) * michael@0: GetRequiredTilesD3D9(mSize.height, maxSize); michael@0: mTileTextures.resize(tileCount); michael@0: mTexture = nullptr; michael@0: nsRefPtr imgSurface = aSurface->GetAsImageSurface(); michael@0: michael@0: for (uint32_t i = 0; i < tileCount; i++) { michael@0: IntRect tileRect = GetTileRect(i); michael@0: unsigned char* data = imgSurface->Data() + michael@0: tileRect.y * imgSurface->Stride() + michael@0: tileRect.x * bpp; michael@0: mTileTextures[i] = DataToTexture(deviceManager, michael@0: data, michael@0: imgSurface->Stride(), michael@0: IntSize(tileRect.width, tileRect.height), michael@0: format, michael@0: bpp); michael@0: if (!mTileTextures[i]) { michael@0: NS_WARNING("Could not upload texture"); michael@0: Reset(); michael@0: return false; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DataTextureSourceD3D9::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: CompositorD3D9* d3dCompositor = static_cast(aCompositor); michael@0: if (mCompositor && mCompositor != d3dCompositor) { michael@0: Reset(); michael@0: } michael@0: mCompositor = d3dCompositor; michael@0: } michael@0: michael@0: void michael@0: DataTextureSourceD3D9::Reset() michael@0: { michael@0: mSize.width = 0; michael@0: mSize.height = 0; michael@0: mIsTiled = false; michael@0: mTexture = nullptr; michael@0: mTileTextures.clear(); michael@0: } michael@0: michael@0: IntRect michael@0: DataTextureSourceD3D9::GetTileRect(uint32_t aTileIndex) const michael@0: { michael@0: uint32_t maxSize = mCompositor->GetMaxTextureSize(); michael@0: uint32_t horizontalTiles = GetRequiredTilesD3D9(mSize.width, maxSize); michael@0: uint32_t verticalTiles = GetRequiredTilesD3D9(mSize.height, maxSize); michael@0: michael@0: uint32_t verticalTile = aTileIndex / horizontalTiles; michael@0: uint32_t horizontalTile = aTileIndex % horizontalTiles; michael@0: michael@0: return IntRect(horizontalTile * maxSize, michael@0: verticalTile * maxSize, michael@0: horizontalTile < (horizontalTiles - 1) ? maxSize : mSize.width % maxSize, michael@0: verticalTile < (verticalTiles - 1) ? maxSize : mSize.height % maxSize); michael@0: } michael@0: michael@0: nsIntRect michael@0: DataTextureSourceD3D9::GetTileRect() michael@0: { michael@0: return ThebesIntRect(GetTileRect(mCurrentTile)); michael@0: } michael@0: michael@0: CairoTextureClientD3D9::CairoTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) michael@0: : TextureClient(aFlags) michael@0: , mFormat(aFormat) michael@0: , mIsLocked(false) michael@0: , mNeedsClear(false) michael@0: , mLockRect(false) michael@0: { michael@0: MOZ_COUNT_CTOR(CairoTextureClientD3D9); michael@0: } michael@0: michael@0: CairoTextureClientD3D9::~CairoTextureClientD3D9() michael@0: { michael@0: MOZ_COUNT_DTOR(CairoTextureClientD3D9); michael@0: } michael@0: michael@0: bool michael@0: CairoTextureClientD3D9::Lock(OpenMode) michael@0: { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: if (!IsValid() || !IsAllocated()) { michael@0: return false; michael@0: } michael@0: michael@0: if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) { michael@0: // If the device has failed then we should not lock the surface, michael@0: // even if we could. michael@0: mD3D9Surface = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: if (!mD3D9Surface) { michael@0: HRESULT hr = mTexture->GetSurfaceLevel(0, getter_AddRefs(mD3D9Surface)); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to get texture surface level."); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: mIsLocked = true; michael@0: michael@0: if (mNeedsClear) { michael@0: mDrawTarget = GetAsDrawTarget(); michael@0: mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); michael@0: mNeedsClear = false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: CairoTextureClientD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!"); michael@0: if (mDrawTarget) { michael@0: mDrawTarget->Flush(); michael@0: mDrawTarget = nullptr; michael@0: } michael@0: michael@0: if (mLockRect) { michael@0: mD3D9Surface->UnlockRect(); michael@0: mLockRect = false; michael@0: } michael@0: michael@0: if (mSurface) { michael@0: mSurface = nullptr; michael@0: } michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: bool michael@0: CairoTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) michael@0: { michael@0: MOZ_ASSERT(IsValid()); michael@0: if (!IsAllocated()) { michael@0: return false; michael@0: } michael@0: michael@0: mTexture->AddRef(); // Release in TextureHostD3D9::TextureHostD3D9 michael@0: aOutDescriptor = SurfaceDescriptorD3D9(reinterpret_cast(mTexture.get())); michael@0: return true; michael@0: } michael@0: michael@0: TemporaryRef michael@0: CairoTextureClientD3D9::GetAsDrawTarget() michael@0: { michael@0: MOZ_ASSERT(mIsLocked && mD3D9Surface); michael@0: if (mDrawTarget) { michael@0: return mDrawTarget; michael@0: } michael@0: michael@0: if (ContentForFormat(mFormat) == gfxContentType::COLOR) { michael@0: mSurface = new gfxWindowsSurface(mD3D9Surface); michael@0: if (!mSurface || mSurface->CairoStatus()) { michael@0: NS_WARNING("Could not create surface for d3d9 surface"); michael@0: mSurface = nullptr; michael@0: return nullptr; michael@0: } michael@0: } else { michael@0: // gfxWindowsSurface don't support transparency so we can't use the d3d9 michael@0: // windows surface optimization. michael@0: // Instead we have to use a gfxImageSurface and fallback for font drawing. michael@0: D3DLOCKED_RECT rect; michael@0: mD3D9Surface->LockRect(&rect, nullptr, 0); michael@0: mSurface = new gfxImageSurface((uint8_t*)rect.pBits, ThebesIntSize(mSize), michael@0: rect.Pitch, SurfaceFormatToImageFormat(mFormat)); michael@0: mLockRect = true; michael@0: } michael@0: michael@0: mDrawTarget = michael@0: gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize); michael@0: michael@0: return mDrawTarget; michael@0: } michael@0: michael@0: bool michael@0: CairoTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) michael@0: { michael@0: MOZ_ASSERT(!IsAllocated()); michael@0: mSize = aSize; michael@0: _D3DFORMAT format = SurfaceFormatToD3D9Format(mFormat); michael@0: michael@0: DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if (!deviceManager || michael@0: !(mTexture = deviceManager->CreateTexture(mSize, format, D3DPOOL_SYSTEMMEM, nullptr))) { michael@0: NS_WARNING("Could not create d3d9 texture"); michael@0: return false; michael@0: } michael@0: michael@0: mNeedsClear = aFlags & ALLOC_CLEAR_BUFFER; michael@0: michael@0: MOZ_ASSERT(mTexture); michael@0: return true; michael@0: } michael@0: michael@0: TextureClientData* michael@0: CairoTextureClientD3D9::DropTextureData() michael@0: { michael@0: TextureClientData* data = new D3D9TextureClientData(mTexture); michael@0: mTexture = nullptr; michael@0: MarkInvalid(); michael@0: return data; michael@0: } michael@0: michael@0: DIBTextureClientD3D9::DIBTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) michael@0: : TextureClient(aFlags) michael@0: , mFormat(aFormat) michael@0: , mIsLocked(false) michael@0: { michael@0: MOZ_COUNT_CTOR(DIBTextureClientD3D9); michael@0: } michael@0: michael@0: DIBTextureClientD3D9::~DIBTextureClientD3D9() michael@0: { michael@0: MOZ_COUNT_DTOR(DIBTextureClientD3D9); michael@0: } michael@0: michael@0: bool michael@0: DIBTextureClientD3D9::Lock(OpenMode) michael@0: { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: if (!IsValid()) { michael@0: return false; michael@0: } michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DIBTextureClientD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!"); michael@0: if (mDrawTarget) { michael@0: mDrawTarget->Flush(); michael@0: mDrawTarget = nullptr; michael@0: } michael@0: michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: bool michael@0: DIBTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) michael@0: { michael@0: MOZ_ASSERT(IsValid()); michael@0: if (!IsAllocated()) { michael@0: return false; michael@0: } michael@0: MOZ_ASSERT(mSurface); michael@0: // The host will release this ref when it receives the surface descriptor. michael@0: // We AddRef in case we die before the host receives the pointer. michael@0: aOutDescriptor = SurfaceDescriptorDIB(reinterpret_cast(mSurface.get())); michael@0: mSurface->AddRef(); michael@0: return true; michael@0: } michael@0: michael@0: TemporaryRef michael@0: DIBTextureClientD3D9::GetAsDrawTarget() michael@0: { michael@0: MOZ_ASSERT(mIsLocked && IsAllocated()); michael@0: michael@0: if (!mDrawTarget) { michael@0: mDrawTarget = michael@0: gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize); michael@0: } michael@0: michael@0: return mDrawTarget; michael@0: } michael@0: michael@0: bool michael@0: DIBTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) michael@0: { michael@0: MOZ_ASSERT(!IsAllocated()); michael@0: mSize = aSize; michael@0: michael@0: mSurface = new gfxWindowsSurface(gfxIntSize(aSize.width, aSize.height), michael@0: SurfaceFormatToImageFormat(mFormat)); michael@0: if (!mSurface || mSurface->CairoStatus()) michael@0: { michael@0: NS_WARNING("Could not create surface"); michael@0: mSurface = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: TextureClientData* michael@0: DIBTextureClientD3D9::DropTextureData() michael@0: { michael@0: TextureClientData* data = new D3D9TextureClientData(mSurface); michael@0: mSurface = nullptr; michael@0: MarkInvalid(); michael@0: return data; michael@0: } michael@0: michael@0: SharedTextureClientD3D9::SharedTextureClientD3D9(gfx::SurfaceFormat aFormat, TextureFlags aFlags) michael@0: : TextureClient(aFlags) michael@0: , mFormat(aFormat) michael@0: , mHandle(0) michael@0: , mIsLocked(false) michael@0: { michael@0: MOZ_COUNT_CTOR(SharedTextureClientD3D9); michael@0: } michael@0: michael@0: SharedTextureClientD3D9::~SharedTextureClientD3D9() michael@0: { michael@0: MOZ_COUNT_DTOR(SharedTextureClientD3D9); michael@0: } michael@0: michael@0: TextureClientData* michael@0: SharedTextureClientD3D9::DropTextureData() michael@0: { michael@0: TextureClientData* data = new D3D9TextureClientData(mTexture); michael@0: mTexture = nullptr; michael@0: MarkInvalid(); michael@0: return data; michael@0: } michael@0: michael@0: bool michael@0: SharedTextureClientD3D9::Lock(OpenMode) michael@0: { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: if (!IsValid()) { michael@0: return false; michael@0: } michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: SharedTextureClientD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked, "Unlock called while the texture is not locked!"); michael@0: } michael@0: michael@0: bool michael@0: SharedTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) michael@0: { michael@0: MOZ_ASSERT(IsValid()); michael@0: if (!IsAllocated()) { michael@0: return false; michael@0: } michael@0: michael@0: aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)(mHandle), mFormat, GetSize()); michael@0: return true; michael@0: } michael@0: michael@0: TextureHostD3D9::TextureHostD3D9(TextureFlags aFlags, michael@0: const SurfaceDescriptorD3D9& aDescriptor) michael@0: : TextureHost(aFlags) michael@0: , mFormat(SurfaceFormat::UNKNOWN) michael@0: , mIsLocked(false) michael@0: { michael@0: mTexture = reinterpret_cast(aDescriptor.texture()); michael@0: mTexture->Release(); // see AddRef in CairoTextureClientD3D9::ToSurfaceDescriptor michael@0: MOZ_ASSERT(mTexture); michael@0: D3DSURFACE_DESC desc; michael@0: HRESULT hr = mTexture->GetLevelDesc(0, &desc); michael@0: if (!FAILED(hr)) { michael@0: mFormat = D3D9FormatToSurfaceFormat(desc.Format); michael@0: mSize.width = desc.Width; michael@0: mSize.height = desc.Height; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: DataTextureSourceD3D9::UpdateFromTexture(IDirect3DTexture9* aTexture, michael@0: const nsIntRegion* aRegion) michael@0: { michael@0: MOZ_ASSERT(aTexture); michael@0: michael@0: D3DSURFACE_DESC desc; michael@0: HRESULT hr = aTexture->GetLevelDesc(0, &desc); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } else { michael@0: // If we changed the compositor, the size might have been reset to zero michael@0: // Otherwise the texture size must not change. michael@0: MOZ_ASSERT(mFormat == D3D9FormatToSurfaceFormat(desc.Format)); michael@0: MOZ_ASSERT(!mSize.width || mSize.width == desc.Width); michael@0: MOZ_ASSERT(!mSize.height || mSize.height == desc.Height); michael@0: mSize = IntSize(desc.Width, desc.Height); michael@0: } michael@0: michael@0: DeviceManagerD3D9* dm = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if (!mTexture) { michael@0: mTexture = dm->CreateTexture(mSize, SurfaceFormatToD3D9Format(mFormat), michael@0: D3DPOOL_DEFAULT, this); michael@0: if (!mTexture) { michael@0: NS_WARNING("Failed to create a texture"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: RefPtr srcSurface; michael@0: RefPtr dstSurface; michael@0: michael@0: hr = aTexture->GetSurfaceLevel(0, byRef(srcSurface)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: hr = mTexture->GetSurfaceLevel(0, byRef(dstSurface)); michael@0: if (FAILED(hr)) { michael@0: return false; michael@0: } michael@0: michael@0: if (aRegion) { michael@0: nsIntRegionRectIterator iter(*aRegion); michael@0: const nsIntRect *iterRect; michael@0: while ((iterRect = iter.Next())) { michael@0: RECT rect; michael@0: rect.left = iterRect->x; michael@0: rect.top = iterRect->y; michael@0: rect.right = iterRect->XMost(); michael@0: rect.bottom = iterRect->YMost(); michael@0: michael@0: POINT point; michael@0: point.x = iterRect->x; michael@0: point.y = iterRect->y; michael@0: hr = dm->device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed Update the surface"); michael@0: return false; michael@0: } michael@0: } michael@0: } else { michael@0: hr = dm->device()->UpdateSurface(srcSurface, nullptr, dstSurface, nullptr); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed Update the surface"); michael@0: return false; michael@0: } michael@0: } michael@0: mIsTiled = false; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TextureHostD3D9::Updated(const nsIntRegion* aRegion) michael@0: { michael@0: if (!mTexture) { michael@0: return; michael@0: } michael@0: michael@0: if (!mTextureSource) { michael@0: mTextureSource = new DataTextureSourceD3D9(mFormat, mSize, mCompositor, michael@0: nullptr, mFlags); michael@0: } michael@0: michael@0: mTextureSource->UpdateFromTexture(mTexture, aRegion); michael@0: } michael@0: michael@0: IDirect3DDevice9* michael@0: TextureHostD3D9::GetDevice() michael@0: { michael@0: return mCompositor ? mCompositor->device() : nullptr; michael@0: } michael@0: michael@0: void michael@0: TextureHostD3D9::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: mCompositor = static_cast(aCompositor); michael@0: if (mTextureSource) { michael@0: mTextureSource->SetCompositor(aCompositor); michael@0: } michael@0: } michael@0: michael@0: NewTextureSource* michael@0: TextureHostD3D9::GetTextureSources() michael@0: { michael@0: MOZ_ASSERT(mIsLocked); michael@0: return mTextureSource; michael@0: } michael@0: michael@0: bool michael@0: TextureHostD3D9::Lock() michael@0: { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TextureHostD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked); michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: void michael@0: TextureHostD3D9::DeallocateDeviceData() michael@0: { michael@0: mTextureSource = nullptr; michael@0: } michael@0: michael@0: DIBTextureHostD3D9::DIBTextureHostD3D9(TextureFlags aFlags, michael@0: const SurfaceDescriptorDIB& aDescriptor) michael@0: : TextureHost(aFlags) michael@0: , mIsLocked(false) michael@0: { michael@0: // We added an extra ref for transport, so we shouldn't AddRef now. michael@0: mSurface = michael@0: dont_AddRef(reinterpret_cast(aDescriptor.surface())); michael@0: MOZ_ASSERT(mSurface); michael@0: michael@0: mSize = ToIntSize(mSurface->GetSize()); michael@0: mFormat = ImageFormatToSurfaceFormat( michael@0: gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType())); michael@0: } michael@0: michael@0: NewTextureSource* michael@0: DIBTextureHostD3D9::GetTextureSources() michael@0: { michael@0: if (!mTextureSource) { michael@0: Updated(); michael@0: } michael@0: michael@0: return mTextureSource; michael@0: } michael@0: michael@0: void michael@0: DIBTextureHostD3D9::Updated(const nsIntRegion*) michael@0: { michael@0: if (!mTextureSource) { michael@0: mTextureSource = new DataTextureSourceD3D9(mFormat, mCompositor, mFlags); michael@0: } michael@0: michael@0: if (!mTextureSource->Update(mSurface)) { michael@0: mTextureSource = nullptr; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: DIBTextureHostD3D9::Lock() michael@0: { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DIBTextureHostD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked); michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: void michael@0: DIBTextureHostD3D9::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: mCompositor = static_cast(aCompositor); michael@0: } michael@0: michael@0: void michael@0: DIBTextureHostD3D9::DeallocateDeviceData() michael@0: { michael@0: mTextureSource = nullptr; michael@0: } michael@0: michael@0: DXGITextureHostD3D9::DXGITextureHostD3D9(TextureFlags aFlags, michael@0: const SurfaceDescriptorD3D10& aDescriptor) michael@0: : TextureHost(aFlags) michael@0: , mHandle(aDescriptor.handle()) michael@0: , mFormat(aDescriptor.format()) michael@0: , mSize(aDescriptor.size()) michael@0: , mIsLocked(false) michael@0: { michael@0: MOZ_ASSERT(mHandle); michael@0: } michael@0: michael@0: NewTextureSource* michael@0: DXGITextureHostD3D9::GetTextureSources() michael@0: { michael@0: return mTextureSource; michael@0: } michael@0: michael@0: bool michael@0: DXGITextureHostD3D9::Lock() michael@0: { michael@0: DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); michael@0: if (!deviceManager) { michael@0: NS_WARNING("trying to lock a TextureHost without a D3D device"); michael@0: return false; michael@0: } michael@0: michael@0: if (!mTextureSource) { michael@0: nsRefPtr tex; michael@0: HRESULT hr = deviceManager->device()->CreateTexture(mSize.width, michael@0: mSize.height, michael@0: 1, michael@0: D3DUSAGE_RENDERTARGET, michael@0: SurfaceFormatToD3D9Format(mFormat), michael@0: D3DPOOL_DEFAULT, michael@0: getter_AddRefs(tex), michael@0: (HANDLE*)&mHandle); michael@0: if (FAILED(hr)) { michael@0: NS_WARNING("Failed to open shared texture"); michael@0: return false; michael@0: } michael@0: michael@0: mTextureSource = new DataTextureSourceD3D9(mFormat, mSize, mCompositor, tex); michael@0: } michael@0: michael@0: MOZ_ASSERT(!mIsLocked); michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DXGITextureHostD3D9::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked); michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: void michael@0: DXGITextureHostD3D9::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: mCompositor = static_cast(aCompositor); michael@0: } michael@0: michael@0: void michael@0: DXGITextureHostD3D9::DeallocateDeviceData() michael@0: { michael@0: mTextureSource = nullptr; michael@0: } michael@0: michael@0: } michael@0: }