mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1685437 - Add multiple texture methods to RenderCompositorD3D11SWGL. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D100972
This commit is contained in:
parent
c8d9a2b0bf
commit
1af68ae8c4
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user