Bug 1685437 - Add multiple texture methods to RenderCompositorD3D11SWGL. r=lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D100972
This commit is contained in:
Matt Woodrow 2021-01-10 22:49:39 +00:00
parent c8d9a2b0bf
commit 1af68ae8c4
3 changed files with 177 additions and 13 deletions

View File

@ -19,6 +19,23 @@ using namespace layers;
namespace wr {
RenderCompositorD3D11SWGL::UploadMode
RenderCompositorD3D11SWGL::GetUploadMode() {
int mode = StaticPrefs::gfx_webrender_software_d3d11_upload_mode();
switch (mode) {
case 1:
return Upload_Immediate;
case 2:
return Upload_Staging;
case 3:
return Upload_StagingNoBlock;
case 4:
return Upload_StagingPooled;
default:
return Upload_Staging;
}
}
UniquePtr<RenderCompositor> RenderCompositorD3D11SWGL::Create(
RefPtr<widget::CompositorWidget>&& aWidget, nsACString& aError) {
void* ctx = wr_swgl_create_context();
@ -69,6 +86,7 @@ bool RenderCompositorD3D11SWGL::BeginFrame() {
return false;
}
mInFrame = true;
mUploadMode = GetUploadMode();
return true;
}
@ -248,17 +266,86 @@ bool RenderCompositorD3D11SWGL::MapTile(wr::NativeTileId aId,
auto layerCursor = surface.mTiles.find(TileKey(aId.x, aId.y));
MOZ_RELEASE_ASSERT(layerCursor != surface.mTiles.end());
// Check if this tile's upload method matches what we're using for this frame,
// and if not then reallocate to fix it. Do this before we copy the struct
// into mCurrentTile.
if (mUploadMode == Upload_Immediate) {
if (layerCursor->second.mStagingTexture) {
MOZ_ASSERT(!layerCursor->second.mSurface);
layerCursor->second.mStagingTexture = nullptr;
layerCursor->second.mSurface = CreateStagingSurface(surface.TileSize());
}
} else {
if (layerCursor->second.mSurface) {
MOZ_ASSERT(!layerCursor->second.mStagingTexture);
layerCursor->second.mSurface = nullptr;
layerCursor->second.mStagingTexture =
CreateStagingTexture(surface.TileSize());
}
}
mCurrentTile = layerCursor->second;
mCurrentTileId = aId;
mCurrentTileDirty = IntRect(aDirtyRect.origin.x, aDirtyRect.origin.y,
aDirtyRect.size.width, aDirtyRect.size.height);
if (mUploadMode == Upload_Immediate) {
DataSourceSurface::MappedSurface map;
if (!mCurrentTile.mSurface->Map(DataSourceSurface::READ_WRITE, &map)) {
return false;
}
*aData =
map.mData + aValidRect.origin.y * map.mStride + aValidRect.origin.x * 4;
*aStride = map.mStride;
layerCursor->second.mValidRect =
gfx::Rect(aValidRect.origin.x, aValidRect.origin.y,
aValidRect.size.width, aValidRect.size.height);
return true;
}
RefPtr<ID3D11DeviceContext> context;
mCompositor->GetDevice()->GetImmediateContext(getter_AddRefs(context));
D3D11_MAPPED_SUBRESOURCE mappedSubresource;
DebugOnly<HRESULT> hr =
context->Map(mCurrentTile.mStagingTexture, 0, D3D11_MAP_READ_WRITE, 0,
&mappedSubresource);
bool shouldBlock = mUploadMode == Upload_Staging;
HRESULT hr = context->Map(
mCurrentTile.mStagingTexture, 0, D3D11_MAP_READ_WRITE,
shouldBlock ? 0 : D3D11_MAP_FLAG_DO_NOT_WAIT, &mappedSubresource);
if (hr == DXGI_ERROR_WAS_STILL_DRAWING) {
// mCurrentTile is a copy of the real tile data, so we can just replace the
// staging one with a temporary for this draw. The staging texture for the
// real tile remains untouched, so we'll go back to using that for future
// frames and discard the new one. In the future we could improve this by
// having a pool of shared staging textures for all the tiles.
// Mark the tile as having a temporary staging texture.
mCurrentTile.mIsTemp = true;
// Try grabbing a texture from the staging pool and see if we can use that.
if (mUploadMode == Upload_StagingPooled && surface.mStagingPool.Length()) {
mCurrentTile.mStagingTexture = surface.mStagingPool.ElementAt(0);
surface.mStagingPool.RemoveElementAt(0);
hr = context->Map(mCurrentTile.mStagingTexture, 0, D3D11_MAP_READ_WRITE,
D3D11_MAP_FLAG_DO_NOT_WAIT, &mappedSubresource);
// If that failed, put it back into the pool (but at the end).
if (hr == DXGI_ERROR_WAS_STILL_DRAWING) {
surface.mStagingPool.AppendElement(mCurrentTile.mStagingTexture);
}
}
// No staging textures, or we tried one and it was busy. Allocate a brand
// new one instead.
if (hr == DXGI_ERROR_WAS_STILL_DRAWING) {
mCurrentTile.mStagingTexture = CreateStagingTexture(surface.TileSize());
hr = context->Map(mCurrentTile.mStagingTexture, 0, D3D11_MAP_READ_WRITE,
0, &mappedSubresource);
}
}
MOZ_ASSERT(SUCCEEDED(hr));
// aData is expected to contain a pointer to the first pixel within the valid
@ -277,6 +364,19 @@ bool RenderCompositorD3D11SWGL::MapTile(wr::NativeTileId aId,
}
void RenderCompositorD3D11SWGL::UnmapTile() {
if (mCurrentTile.mSurface) {
MOZ_ASSERT(mUploadMode == Upload_Immediate);
mCurrentTile.mSurface->Unmap();
nsIntRegion dirty(mCurrentTileDirty);
// This uses UpdateSubresource, which blocks, so is likely implemented as a
// memcpy into driver owned memory, followed by an async upload. The staging
// method should avoid this extra copy, and is likely to be faster usually.
// We could possible do this call on a background thread so that sw-wr can
// start drawing the next tile while the memcpy is in progress.
mCurrentTile.mTexture->Update(mCurrentTile.mSurface, &dirty);
return;
}
RefPtr<ID3D11DeviceContext> context;
mCompositor->GetDevice()->GetImmediateContext(getter_AddRefs(context));
@ -293,6 +393,20 @@ void RenderCompositorD3D11SWGL::UnmapTile() {
context->CopySubresourceRegion(mCurrentTile.mTexture->GetD3D11Texture(), 0,
mCurrentTileDirty.x, mCurrentTileDirty.y, 0,
mCurrentTile.mStagingTexture, 0, &box);
// If we allocated a temp staging texture for this tile, and we're running
// in pooled mode, then consider adding it to the pool for later.
if (mCurrentTile.mIsTemp && mUploadMode == Upload_StagingPooled) {
auto surfaceCursor = mSurfaces.find(mCurrentTileId.surface_id);
MOZ_RELEASE_ASSERT(surfaceCursor != mSurfaces.end());
Surface& surface = surfaceCursor->second;
static const uint32_t kMaxPoolSize = 5;
if (surface.mStagingPool.Length() < kMaxPoolSize) {
surface.mStagingPool.AppendElement(mCurrentTile.mStagingTexture);
}
}
mCurrentTile.mStagingTexture = nullptr;
}
void RenderCompositorD3D11SWGL::CreateSurface(wr::NativeSurfaceId aId,
@ -317,6 +431,27 @@ void RenderCompositorD3D11SWGL::DestroySurface(NativeSurfaceId aId) {
mSurfaces.erase(surfaceCursor);
}
already_AddRefed<ID3D11Texture2D>
RenderCompositorD3D11SWGL::CreateStagingTexture(const gfx::IntSize aSize) {
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width,
aSize.height, 1, 1);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
RefPtr<ID3D11Texture2D> cpuTexture;
DebugOnly<HRESULT> hr = mCompositor->GetDevice()->CreateTexture2D(
&desc, nullptr, getter_AddRefs(cpuTexture));
MOZ_ASSERT(SUCCEEDED(hr));
return cpuTexture.forget();
}
already_AddRefed<DataSourceSurface>
RenderCompositorD3D11SWGL::CreateStagingSurface(const gfx::IntSize aSize) {
return Factory::CreateDataSourceSurface(aSize, SurfaceFormat::B8G8R8A8);
}
void RenderCompositorD3D11SWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX,
int32_t aY) {
auto surfaceCursor = mSurfaces.find(aId);
@ -324,6 +459,19 @@ void RenderCompositorD3D11SWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX,
Surface& surface = surfaceCursor->second;
MOZ_RELEASE_ASSERT(!surface.mIsExternal);
if (mUploadMode == Upload_Immediate) {
RefPtr<DataTextureSourceD3D11> source =
new DataTextureSourceD3D11(gfx::SurfaceFormat::B8G8R8A8, mCompositor,
layers::TextureFlags::NO_FLAGS);
RefPtr<DataSourceSurface> surf = CreateStagingSurface(surface.TileSize());
surface.mTiles.insert({TileKey(aX, aY), Tile{source, nullptr, surf}});
return;
}
MOZ_ASSERT(mUploadMode == Upload_Staging ||
mUploadMode == Upload_StagingNoBlock ||
mUploadMode == Upload_StagingPooled);
CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
surface.mTileSize.width, surface.mTileSize.height,
1, 1);
@ -336,16 +484,8 @@ void RenderCompositorD3D11SWGL::CreateTile(wr::NativeSurfaceId aId, int32_t aX,
RefPtr<DataTextureSourceD3D11> source = new DataTextureSourceD3D11(
mCompositor->GetDevice(), gfx::SurfaceFormat::B8G8R8A8, texture);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
RefPtr<ID3D11Texture2D> cpuTexture;
hr = mCompositor->GetDevice()->CreateTexture2D(&desc, nullptr,
getter_AddRefs(cpuTexture));
MOZ_ASSERT(SUCCEEDED(hr));
surface.mTiles.insert({TileKey(aX, aY), Tile{source, cpuTexture}});
RefPtr<ID3D11Texture2D> cpuTexture = CreateStagingTexture(surface.TileSize());
surface.mTiles.insert({TileKey(aX, aY), Tile{source, cpuTexture, nullptr}});
}
void RenderCompositorD3D11SWGL::DestroyTile(wr::NativeSurfaceId aId, int32_t aX,

View File

@ -107,6 +107,11 @@ class RenderCompositorD3D11SWGL : public RenderCompositor {
ID3D11Device* GetDevice() { return mCompositor->GetDevice(); }
private:
already_AddRefed<ID3D11Texture2D> CreateStagingTexture(
const gfx::IntSize aSize);
already_AddRefed<DataSourceSurface> CreateStagingSurface(
const gfx::IntSize aSize);
RefPtr<layers::CompositorD3D11> mCompositor;
void* mContext = nullptr;
@ -116,7 +121,9 @@ class RenderCompositorD3D11SWGL : public RenderCompositor {
// changed area into the texture.
RefPtr<layers::DataTextureSourceD3D11> mTexture;
RefPtr<ID3D11Texture2D> mStagingTexture;
RefPtr<DataSourceSurface> mSurface;
gfx::Rect mValidRect;
bool mIsTemp = false;
struct KeyHashFn {
std::size_t operator()(const TileKey& aId) const {
@ -141,6 +148,8 @@ class RenderCompositorD3D11SWGL : public RenderCompositor {
std::unordered_map<TileKey, Tile, Tile::KeyHashFn> mTiles;
RefPtr<RenderTextureHost> mExternalImage;
nsTArray<RefPtr<ID3D11Texture2D>> mStagingPool;
struct IdHashFn {
std::size_t operator()(const wr::NativeSurfaceId& aId) const {
return HashGeneric(wr::AsUint64(aId));
@ -149,9 +158,19 @@ class RenderCompositorD3D11SWGL : public RenderCompositor {
};
std::unordered_map<wr::NativeSurfaceId, Surface, Surface::IdHashFn> mSurfaces;
enum UploadMode {
Upload_Immediate,
Upload_Staging,
Upload_StagingNoBlock,
Upload_StagingPooled
};
UploadMode GetUploadMode();
UploadMode mUploadMode = Upload_Staging;
// Temporary state held between MapTile and UnmapTile
Tile mCurrentTile;
gfx::IntRect mCurrentTileDirty;
wr::NativeTileId mCurrentTileId;
// The set of surfaces added to be composited for the current frame
struct FrameSurface {

View File

@ -4793,6 +4793,11 @@
value: true
mirror: once
- name: gfx.webrender.software.d3d11.upload-mode
type: RelaxedAtomicInt32
value: 2
mirror: always
# Use vsync events generated by hardware
- name: gfx.work-around-driver-bugs
type: bool