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