mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
326 lines
7.8 KiB
C++
326 lines
7.8 KiB
C++
/* -*- 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 <algorithm>
|
|
|
|
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;
|
|
}
|
|
|
|
already_AddRefed<DataSourceSurface>
|
|
SourceSurfaceD2DTarget::GetDataSurface()
|
|
{
|
|
RefPtr<DataSourceSurfaceD2DTarget> 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;
|
|
|
|
if (!Factory::GetDirect3D10Device()) {
|
|
gfxCriticalError() << "Invalid D3D10 device in D2D target surface";
|
|
return nullptr;
|
|
}
|
|
|
|
HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(dataSurf->mTexture));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture);
|
|
|
|
return dataSurf.forget();
|
|
}
|
|
|
|
void*
|
|
SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType)
|
|
{
|
|
if (aType == NativeSurfaceType::D3D10_TEXTURE) {
|
|
return static_cast<void*>(mTexture.get());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ID3D10ShaderResourceView*
|
|
SourceSurfaceD2DTarget::GetSRView()
|
|
{
|
|
if (mSRView) {
|
|
return mSRView;
|
|
}
|
|
|
|
if (!Factory::GetDirect3D10Device()) {
|
|
gfxCriticalError() << "Invalid D3D10 device in D2D target surface";
|
|
return nullptr;
|
|
}
|
|
|
|
HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << "Failed to create ShaderResourceView. Code: " << hexa(hr);
|
|
}
|
|
|
|
return mSRView;
|
|
}
|
|
|
|
void
|
|
SourceSurfaceD2DTarget::DrawTargetWillChange()
|
|
{
|
|
RefPtr<ID3D10Texture2D> 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, getter_AddRefs(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<IDXGISurface> surf;
|
|
hr = mTexture->QueryInterface((IDXGISurface**)getter_AddRefs(surf));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
|
|
D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat));
|
|
hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, getter_AddRefs(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)),
|
|
getter_AddRefs(mBitmap));
|
|
|
|
if (FAILED(hr)) {
|
|
gfxWarning() << "Failed in CreateBitmap. Code: " << hexa(hr);
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<ID2D1RenderTarget> 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<IDXGISurface> surface;
|
|
|
|
hr = mTexture->QueryInterface((IDXGISurface**)getter_AddRefs(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, getter_AddRefs(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: " << hexa(hr);
|
|
return false;
|
|
}
|
|
|
|
aMappedSurface->mData = (uint8_t*)map.pData;
|
|
aMappedSurface->mStride = map.RowPitch;
|
|
mIsMapped = !!aMappedSurface->mData;
|
|
|
|
return mIsMapped;
|
|
}
|
|
|
|
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: " << hexa(hr);
|
|
return;
|
|
}
|
|
mMapped = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|