diff -r 000000000000 -r 6474c204b198 gfx/2d/SourceSurfaceD2DTarget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/2d/SourceSurfaceD2DTarget.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SourceSurfaceD2DTarget.h" +#include "Logging.h" +#include "DrawTargetD2D.h" +#include "Tools.h" + +#include + +namespace mozilla { +namespace gfx { + +SourceSurfaceD2DTarget::SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget, + ID3D10Texture2D* aTexture, + SurfaceFormat aFormat) + : mDrawTarget(aDrawTarget) + , mTexture(aTexture) + , mFormat(aFormat) + , mOwnsCopy(false) +{ +} + +SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget() +{ + // We don't need to do anything special here to notify our mDrawTarget. It must + // already have cleared its mSnapshot field, otherwise this object would + // be kept alive. + if (mOwnsCopy) { + IntSize size = GetSize(); + + DrawTargetD2D::mVRAMUsageSS -= size.width * size.height * BytesPerPixel(mFormat); + } +} + +IntSize +SourceSurfaceD2DTarget::GetSize() const +{ + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + return IntSize(desc.Width, desc.Height); +} + +SurfaceFormat +SourceSurfaceD2DTarget::GetFormat() const +{ + return mFormat; +} + +TemporaryRef +SourceSurfaceD2DTarget::GetDataSurface() +{ + RefPtr dataSurf = + new DataSourceSurfaceD2DTarget(mFormat); + + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + desc.Usage = D3D10_USAGE_STAGING; + desc.BindFlags = 0; + desc.MiscFlags = 0; + + HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture)); + + if (FAILED(hr)) { + gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hr; + return nullptr; + } + Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); + + return dataSurf; +} + +void* +SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType) +{ + if (aType == NativeSurfaceType::D3D10_TEXTURE) { + return static_cast(mTexture.get()); + } + return nullptr; +} + +ID3D10ShaderResourceView* +SourceSurfaceD2DTarget::GetSRView() +{ + if (mSRView) { + return mSRView; + } + + HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, byRef(mSRView)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ShaderResourceView. Code: " << hr; + } + + return mSRView; +} + +void +SourceSurfaceD2DTarget::DrawTargetWillChange() +{ + RefPtr oldTexture = mTexture; + + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + // Our original texture might implement the keyed mutex flag. We shouldn't + // need that here. We actually specifically don't want it since we don't lock + // our texture for usage! + desc.MiscFlags = 0; + + // Get a copy of the surface data so the content at snapshot time was saved. + Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(mTexture)); + Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture); + + mBitmap = nullptr; + + DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat); + mOwnsCopy = true; + + // We now no longer depend on the source surface content remaining the same. + MarkIndependent(); +} + +ID2D1Bitmap* +SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) +{ + if (mBitmap) { + return mBitmap; + } + + HRESULT hr; + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + IntSize size(desc.Width, desc.Height); + + RefPtr surf; + hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr; + return nullptr; + } + + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); + hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); + + if (FAILED(hr)) { + // This seems to happen for SurfaceFormat::A8 sometimes... + hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), + D2D1::BitmapProperties(D2DPixelFormat(mFormat)), + byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed in CreateBitmap. Code: " << hr; + return nullptr; + } + + RefPtr rt; + + if (mDrawTarget) { + rt = mDrawTarget->mRT; + } + + if (!rt) { + // Okay, we already separated from our drawtarget. And we're an A8 + // surface the only way we can get to a bitmap is by creating a + // a rendertarget and from there copying to a bitmap! Terrible! + RefPtr surface; + + hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to QI texture to surface."; + return nullptr; + } + + D2D1_RENDER_TARGET_PROPERTIES props = + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat)); + hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create D2D render target for texture."; + return nullptr; + } + } + + mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr); + return mBitmap; + } + + return mBitmap; +} + +void +SourceSurfaceD2DTarget::MarkIndependent() +{ + if (mDrawTarget) { + MOZ_ASSERT(mDrawTarget->mSnapshot == this); + mDrawTarget->mSnapshot = nullptr; + mDrawTarget = nullptr; + } +} + +DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat) + : mFormat(aFormat) + , mMapped(false) +{ +} + +DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget() +{ + if (mMapped) { + mTexture->Unmap(0); + } +} + +IntSize +DataSourceSurfaceD2DTarget::GetSize() const +{ + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + return IntSize(desc.Width, desc.Height); +} + +SurfaceFormat +DataSourceSurfaceD2DTarget::GetFormat() const +{ + return mFormat; +} + +uint8_t* +DataSourceSurfaceD2DTarget::GetData() +{ + EnsureMapped(); + + return (unsigned char*)mMap.pData; +} + +int32_t +DataSourceSurfaceD2DTarget::Stride() +{ + EnsureMapped(); + return mMap.RowPitch; +} + +bool +DataSourceSurfaceD2DTarget::Map(MapType aMapType, MappedSurface *aMappedSurface) +{ + // DataSourceSurfaces used with the new Map API should not be used with GetData!! + MOZ_ASSERT(!mMapped); + MOZ_ASSERT(!mIsMapped); + + if (!mTexture) { + return false; + } + + D3D10_MAP mapType; + + if (aMapType == MapType::READ) { + mapType = D3D10_MAP_READ; + } else if (aMapType == MapType::WRITE) { + mapType = D3D10_MAP_WRITE; + } else { + mapType = D3D10_MAP_READ_WRITE; + } + + D3D10_MAPPED_TEXTURE2D map; + + HRESULT hr = mTexture->Map(0, mapType, 0, &map); + + if (FAILED(hr)) { + gfxWarning() << "Texture map failed with code: " << hr; + return false; + } + + aMappedSurface->mData = (uint8_t*)map.pData; + aMappedSurface->mStride = map.RowPitch; + mIsMapped = true; + + return true; +} + +void +DataSourceSurfaceD2DTarget::Unmap() +{ + MOZ_ASSERT(mIsMapped); + + mIsMapped = false; + mTexture->Unmap(0); +} + +void +DataSourceSurfaceD2DTarget::EnsureMapped() +{ + // Do not use GetData() after having used Map! + MOZ_ASSERT(!mIsMapped); + if (!mMapped) { + HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap); + if (FAILED(hr)) { + gfxWarning() << "Failed to map texture to memory. Code: " << hr; + return; + } + mMapped = true; + } +} + +} +}