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 "TextureD3D11.h" michael@0: #include "CompositorD3D11.h" michael@0: #include "gfxContext.h" michael@0: #include "Effects.h" michael@0: #include "mozilla/layers/YCbCrImageDataSerializer.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxD2DSurface.h" michael@0: #include "gfx2DGlue.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: using namespace gfx; michael@0: michael@0: namespace layers { michael@0: michael@0: static DXGI_FORMAT michael@0: SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) michael@0: { michael@0: switch (aFormat) { michael@0: case SurfaceFormat::B8G8R8A8: michael@0: return DXGI_FORMAT_B8G8R8A8_UNORM; michael@0: case SurfaceFormat::B8G8R8X8: michael@0: return DXGI_FORMAT_B8G8R8A8_UNORM; michael@0: case SurfaceFormat::A8: michael@0: return DXGI_FORMAT_A8_UNORM; michael@0: default: michael@0: MOZ_ASSERT(false, "unsupported format"); michael@0: return DXGI_FORMAT_UNKNOWN; michael@0: } michael@0: } michael@0: michael@0: static uint32_t michael@0: GetRequiredTilesD3D11(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: static IntRect michael@0: GetTileRectD3D11(uint32_t aID, IntSize aSize, uint32_t aMaxSize) michael@0: { michael@0: uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize); michael@0: uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize); michael@0: michael@0: uint32_t verticalTile = aID / horizontalTiles; michael@0: uint32_t horizontalTile = aID % horizontalTiles; michael@0: michael@0: return IntRect(horizontalTile * aMaxSize, michael@0: verticalTile * aMaxSize, michael@0: horizontalTile < (horizontalTiles - 1) ? aMaxSize : aSize.width % aMaxSize, michael@0: verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize); michael@0: } michael@0: michael@0: DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat, michael@0: CompositorD3D11* aCompositor, michael@0: TextureFlags aFlags) michael@0: : mCompositor(aCompositor) michael@0: , mFormat(aFormat) michael@0: , mFlags(aFlags) michael@0: , mCurrentTile(0) michael@0: , mIsTiled(false) michael@0: , mIterating(false) michael@0: { michael@0: MOZ_COUNT_CTOR(DataTextureSourceD3D11); michael@0: } michael@0: michael@0: DataTextureSourceD3D11::DataTextureSourceD3D11(SurfaceFormat aFormat, michael@0: CompositorD3D11* aCompositor, michael@0: ID3D11Texture2D* aTexture) michael@0: : mCompositor(aCompositor) michael@0: , mFormat(aFormat) michael@0: , mFlags(0) michael@0: , mCurrentTile(0) michael@0: , mIsTiled(false) michael@0: , mIterating(false) michael@0: { michael@0: MOZ_COUNT_CTOR(DataTextureSourceD3D11); michael@0: michael@0: mTexture = aTexture; michael@0: D3D11_TEXTURE2D_DESC desc; michael@0: aTexture->GetDesc(&desc); michael@0: michael@0: mSize = IntSize(desc.Width, desc.Height); michael@0: } michael@0: michael@0: michael@0: michael@0: DataTextureSourceD3D11::~DataTextureSourceD3D11() michael@0: { michael@0: MOZ_COUNT_DTOR(DataTextureSourceD3D11); michael@0: } michael@0: michael@0: michael@0: template // ID3D10Texture2D or ID3D11Texture2D michael@0: static void LockD3DTexture(T* aTexture) michael@0: { michael@0: MOZ_ASSERT(aTexture); michael@0: RefPtr mutex; michael@0: aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); michael@0: if (mutex) { michael@0: mutex->AcquireSync(0, INFINITE); michael@0: } michael@0: } michael@0: michael@0: template // ID3D10Texture2D or ID3D11Texture2D michael@0: static void UnlockD3DTexture(T* aTexture) michael@0: { michael@0: MOZ_ASSERT(aTexture); michael@0: RefPtr mutex; michael@0: aTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex)); michael@0: if (mutex) { michael@0: mutex->ReleaseSync(0); michael@0: } michael@0: } michael@0: michael@0: TemporaryRef michael@0: CreateTextureHostD3D11(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::TSurfaceDescriptorD3D10: { michael@0: result = new DXGITextureHostD3D11(aFlags, michael@0: aDesc.get_SurfaceDescriptorD3D10()); michael@0: break; michael@0: } michael@0: default: { michael@0: NS_WARNING("Unsupported SurfaceDescriptor type"); michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: TextureClientD3D11::TextureClientD3D11(gfx::SurfaceFormat aFormat, TextureFlags aFlags) michael@0: : TextureClient(aFlags) michael@0: , mFormat(aFormat) michael@0: , mIsLocked(false) michael@0: , mNeedsClear(false) michael@0: {} michael@0: michael@0: TextureClientD3D11::~TextureClientD3D11() michael@0: { michael@0: #ifdef DEBUG michael@0: // An Azure DrawTarget needs to be locked when it gets nullptr'ed as this is michael@0: // when it calls EndDraw. This EndDraw should not execute anything so it michael@0: // shouldn't -really- need the lock but the debug layer chokes on this. michael@0: if (mDrawTarget) { michael@0: MOZ_ASSERT(!mIsLocked); michael@0: MOZ_ASSERT(mTexture); michael@0: MOZ_ASSERT(mDrawTarget->refCount() == 1); michael@0: LockD3DTexture(mTexture.get()); michael@0: mDrawTarget = nullptr; michael@0: UnlockD3DTexture(mTexture.get()); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: TextureClientD3D11::Lock(OpenMode aMode) michael@0: { michael@0: if (!mTexture) { michael@0: return false; michael@0: } michael@0: MOZ_ASSERT(!mIsLocked, "The Texture is already locked!"); michael@0: LockD3DTexture(mTexture.get()); 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: TextureClientD3D11::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!"); michael@0: michael@0: if (mDrawTarget) { michael@0: // see the comment on TextureClient::GetAsDrawTarget. michael@0: // This DrawTarget is internal to the TextureClient and is only exposed to the michael@0: // outside world between Lock() and Unlock(). This assertion checks that no outside michael@0: // reference remains by the time Unlock() is called. michael@0: MOZ_ASSERT(mDrawTarget->refCount() == 1); michael@0: mDrawTarget->Flush(); michael@0: } michael@0: michael@0: // The DrawTarget is created only once, and is only usable between calls michael@0: // to Lock and Unlock. michael@0: UnlockD3DTexture(mTexture.get()); michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: TemporaryRef michael@0: TextureClientD3D11::GetAsDrawTarget() michael@0: { michael@0: MOZ_ASSERT(mIsLocked, "Calling TextureClient::GetAsDrawTarget without locking :("); michael@0: michael@0: if (!mTexture) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (mDrawTarget) { michael@0: return mDrawTarget; michael@0: } michael@0: michael@0: mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, mFormat); michael@0: return mDrawTarget; michael@0: } michael@0: michael@0: bool michael@0: TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags) michael@0: { michael@0: mSize = aSize; michael@0: ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device(); michael@0: michael@0: CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM, michael@0: aSize.width, aSize.height, 1, 1, michael@0: D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE); michael@0: michael@0: newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX; michael@0: michael@0: HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture)); michael@0: michael@0: if (FAILED(hr)) { michael@0: LOGD3D11("Error creating texture for client!"); michael@0: return false; michael@0: } michael@0: michael@0: // Defer clearing to the next time we lock to avoid an extra (expensive) lock. michael@0: mNeedsClear = aFlags & ALLOC_CLEAR_BUFFER; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TextureClientD3D11::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) michael@0: { michael@0: if (!IsAllocated()) { michael@0: return false; michael@0: } michael@0: michael@0: RefPtr resource; michael@0: mTexture->QueryInterface((IDXGIResource**)byRef(resource)); michael@0: HANDLE sharedHandle; michael@0: HRESULT hr = resource->GetSharedHandle(&sharedHandle); michael@0: michael@0: if (FAILED(hr)) { michael@0: LOGD3D11("Error getting shared handle for texture."); michael@0: return false; michael@0: } michael@0: michael@0: aOutDescriptor = SurfaceDescriptorD3D10((WindowsHandle)sharedHandle, mFormat, mSize); michael@0: return true; michael@0: } michael@0: michael@0: DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags, michael@0: const SurfaceDescriptorD3D10& aDescriptor) michael@0: : TextureHost(aFlags) michael@0: , mHandle(aDescriptor.handle()) michael@0: , mFormat(aDescriptor.format()) michael@0: , mIsLocked(false) michael@0: {} michael@0: michael@0: ID3D11Device* michael@0: DXGITextureHostD3D11::GetDevice() michael@0: { michael@0: return mCompositor ? mCompositor->GetDevice() : nullptr; michael@0: } michael@0: michael@0: void michael@0: DXGITextureHostD3D11::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: mCompositor = static_cast(aCompositor); michael@0: } michael@0: michael@0: bool michael@0: DXGITextureHostD3D11::Lock() michael@0: { michael@0: if (!GetDevice()) { michael@0: NS_WARNING("trying to lock a TextureHost without a D3D device"); michael@0: return false; michael@0: } michael@0: if (!mTextureSource) { michael@0: RefPtr tex; michael@0: HRESULT hr = GetDevice()->OpenSharedResource((HANDLE)mHandle, michael@0: __uuidof(ID3D11Texture2D), michael@0: (void**)(ID3D11Texture2D**)byRef(tex)); 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 DataTextureSourceD3D11(mFormat, mCompositor, tex); michael@0: D3D11_TEXTURE2D_DESC desc; michael@0: tex->GetDesc(&desc); michael@0: mSize = IntSize(desc.Width, desc.Height); michael@0: } michael@0: michael@0: LockD3DTexture(mTextureSource->GetD3D11Texture()); michael@0: michael@0: mIsLocked = true; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: DXGITextureHostD3D11::Unlock() michael@0: { michael@0: MOZ_ASSERT(mIsLocked); michael@0: UnlockD3DTexture(mTextureSource->GetD3D11Texture()); michael@0: mIsLocked = false; michael@0: } michael@0: michael@0: NewTextureSource* michael@0: DXGITextureHostD3D11::GetTextureSources() michael@0: { michael@0: return mTextureSource.get(); michael@0: } michael@0: michael@0: bool michael@0: DataTextureSourceD3D11::Update(DataSourceSurface* aSurface, michael@0: nsIntRegion* aDestRegion, michael@0: 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: MOZ_ASSERT(aSurface); michael@0: michael@0: if (!mCompositor || !mCompositor->GetDevice()) { michael@0: return false; michael@0: } michael@0: michael@0: uint32_t bpp = BytesPerPixel(aSurface->GetFormat()); michael@0: DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat()); michael@0: michael@0: mSize = aSurface->GetSize(); michael@0: mFormat = aSurface->GetFormat(); michael@0: michael@0: CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, michael@0: 1, 1, D3D11_BIND_SHADER_RESOURCE, michael@0: D3D11_USAGE_IMMUTABLE); michael@0: michael@0: int32_t maxSize = mCompositor->GetMaxTextureSize(); michael@0: if ((mSize.width <= maxSize && mSize.height <= maxSize) || michael@0: (mFlags & TEXTURE_DISALLOW_BIGIMAGE)) { michael@0: D3D11_SUBRESOURCE_DATA initData; michael@0: initData.pSysMem = aSurface->GetData(); michael@0: initData.SysMemPitch = aSurface->Stride(); michael@0: michael@0: mCompositor->GetDevice()->CreateTexture2D(&desc, &initData, byRef(mTexture)); michael@0: mIsTiled = false; michael@0: if (!mTexture) { michael@0: Reset(); michael@0: return false; michael@0: } michael@0: } else { michael@0: mIsTiled = true; michael@0: uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) * michael@0: GetRequiredTilesD3D11(mSize.height, maxSize); michael@0: 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: michael@0: desc.Width = tileRect.width; michael@0: desc.Height = tileRect.height; michael@0: michael@0: D3D11_SUBRESOURCE_DATA initData; michael@0: initData.pSysMem = aSurface->GetData() + michael@0: tileRect.y * aSurface->Stride() + michael@0: tileRect.x * bpp; michael@0: initData.SysMemPitch = aSurface->Stride(); michael@0: michael@0: mCompositor->GetDevice()->CreateTexture2D(&desc, &initData, byRef(mTileTextures[i])); michael@0: if (!mTileTextures[i]) { michael@0: Reset(); michael@0: return false; michael@0: } michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: ID3D11Texture2D* michael@0: DataTextureSourceD3D11::GetD3D11Texture() const michael@0: { michael@0: return mIterating ? mTileTextures[mCurrentTile] michael@0: : mTexture; michael@0: } michael@0: michael@0: void michael@0: DataTextureSourceD3D11::Reset() michael@0: { michael@0: mTexture = nullptr; michael@0: mTileTextures.resize(0); michael@0: mIsTiled = false; michael@0: mSize.width = 0; michael@0: mSize.height = 0; michael@0: } michael@0: michael@0: IntRect michael@0: DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const michael@0: { michael@0: return GetTileRectD3D11(aIndex, mSize, mCompositor->GetMaxTextureSize()); michael@0: } michael@0: michael@0: nsIntRect michael@0: DataTextureSourceD3D11::GetTileRect() michael@0: { michael@0: IntRect rect = GetTileRect(mCurrentTile); michael@0: return nsIntRect(rect.x, rect.y, rect.width, rect.height); michael@0: } michael@0: michael@0: void michael@0: DataTextureSourceD3D11::SetCompositor(Compositor* aCompositor) michael@0: { michael@0: CompositorD3D11* 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: CompositingRenderTargetD3D11::CompositingRenderTargetD3D11(ID3D11Texture2D* aTexture, michael@0: const gfx::IntPoint& aOrigin) michael@0: : CompositingRenderTarget(aOrigin) michael@0: { michael@0: MOZ_ASSERT(aTexture); michael@0: michael@0: mTexture = aTexture; michael@0: michael@0: RefPtr device; michael@0: mTexture->GetDevice(byRef(device)); michael@0: michael@0: HRESULT hr = device->CreateRenderTargetView(mTexture, nullptr, byRef(mRTView)); michael@0: michael@0: if (FAILED(hr)) { michael@0: LOGD3D11("Failed to create RenderTargetView."); michael@0: } michael@0: } michael@0: michael@0: IntSize michael@0: CompositingRenderTargetD3D11::GetSize() const michael@0: { michael@0: return TextureSourceD3D11::GetSize(); michael@0: } michael@0: michael@0: } michael@0: }