Support component-alpha for intermediate surfaces in Advanced Layers. (bug 1402737 part 2, r=mattwoodrow)

--HG--
extra : rebase_source : dc2121d9f479f8c75237cae8ad4ea9f751f42ab6
This commit is contained in:
David Anderson 2017-10-10 17:39:42 -07:00
parent 2b8bc13b5c
commit ef626c4458
6 changed files with 147 additions and 18 deletions

View File

@ -21,7 +21,8 @@ using namespace gfx;
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
: ContainerLayer(aManager, nullptr),
LayerMLGPU(aManager),
mInvalidateEntireSurface(false)
mInvalidateEntireSurface(false),
mSurfaceCopyNeeded(false)
{
}
@ -35,6 +36,8 @@ ContainerLayerMLGPU::~ContainerLayerMLGPU()
bool
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
{
mView = nullptr;
if (!UseIntermediateSurface()) {
// Set this so we invalidate the entire cached render target (if any)
// if our container uses an intermediate surface again later.
@ -67,6 +70,19 @@ ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
mRenderTarget = nullptr;
}
// Note that if a surface copy is needed, we always redraw the
// whole surface (on-demand). This is a rare case - the old
// Compositor already does this - and it saves us having to
// do much more complicated invalidation.
bool surfaceCopyNeeded = false;
DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
if (surfaceCopyNeeded != mSurfaceCopyNeeded ||
surfaceCopyNeeded)
{
mInvalidateEntireSurface = true;
}
mSurfaceCopyNeeded = surfaceCopyNeeded;
gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
if (!mRenderTarget ||
!gfxPrefs::AdvancedLayersUseInvalidation() ||

View File

@ -13,6 +13,7 @@ namespace mozilla {
namespace layers {
class MLGDevice;
class RenderViewMLGPU;
class ContainerLayerMLGPU final : public ContainerLayer
, public LayerMLGPU
@ -53,6 +54,17 @@ public:
mInvalidRect.SetEmpty();
}
bool IsContentOpaque() override;
bool NeedsSurfaceCopy() const {
return mSurfaceCopyNeeded;
}
RenderViewMLGPU* GetRenderView() const {
return mView;
}
void SetRenderView(RenderViewMLGPU* aView) {
MOZ_ASSERT(!mView);
mView = aView;
}
protected:
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
@ -71,6 +83,11 @@ private:
// is in layer coordinates.
gfx::IntRect mInvalidRect;
bool mInvalidateEntireSurface;
bool mSurfaceCopyNeeded;
// This is only valid for intermediate surfaces while an instance of
// FrameBuilder is live.
RenderViewMLGPU* mView;
};
} // namespace layers

View File

@ -305,6 +305,11 @@ ShaderRenderPass::ExecuteRendering()
return;
}
// Change the blend state if needed.
if (Maybe<MLGBlendState> blendState = GetBlendState()) {
mDevice->SetBlendState(blendState.value());
}
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
if (MaskOperation* mask = GetMask()) {
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
@ -994,5 +999,48 @@ RenderViewPass::SetupPipeline()
mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
}
void
RenderViewPass::ExecuteRendering()
{
if (mAssignedLayer->NeedsSurfaceCopy()) {
RenderWithBackdropCopy();
return;
}
TexturedRenderPass::ExecuteRendering();
}
void
RenderViewPass::RenderWithBackdropCopy()
{
MOZ_ASSERT(mAssignedLayer->NeedsSurfaceCopy());
DebugOnly<Matrix> transform2d;
const Matrix4x4& transform = mAssignedLayer->GetEffectiveTransform();
MOZ_ASSERT(transform.Is2D(&transform2d) &&
!gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
IntRect visible = mAssignedLayer->GetShadowVisibleRegion().GetBounds().ToUnknownRect();
visible += IntPoint::Truncate(transform._41, transform._42);
visible -= mParentView->GetTargetOffset();
RefPtr<MLGTexture> dest = mAssignedLayer->GetRenderTarget()->GetTexture();
RefPtr<MLGTexture> source = mParentView->GetRenderTarget()->GetTexture();
// Clamp the rect so that we don't read pixels outside the source texture, or
// write pixels outside the destination texture.
visible = visible.Intersect(IntRect(IntPoint(0, 0), source->GetSize()));
visible = visible.Intersect(IntRect(visible.TopLeft(), dest->GetSize()));
mDevice->CopyTexture(dest, IntPoint(0, 0), source, visible);
RenderViewMLGPU* childView = mAssignedLayer->GetRenderView();
childView->RenderAfterBackdropCopy();
mParentView->RestoreDeviceState();
TexturedRenderPass::ExecuteRendering();
}
} // namespace layers
} // namespace mozilla

View File

@ -464,8 +464,10 @@ private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
bool OnPrepareBuffers() override;
void ExecuteRendering() override;
float GetOpacity() const override;
bool PrepareBlendState();
void RenderWithBackdropCopy();
private:
ConstantBufferSection mBlendConstants;

View File

@ -62,6 +62,8 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
this,
aContainer->GetLayer(),
Stringify(mInvalidBounds).c_str());
mContainer->SetRenderView(this);
}
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent)
@ -72,6 +74,7 @@ RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParen
mFinishedBuilding(false),
mCurrentLayerBufferIndex(kInvalidResourceIndex),
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
mCurrentDepthMode(MLGDepthTestMode::Disabled),
mNextSortIndex(1),
mUseDepthBuffer(gfxPrefs::AdvancedLayersEnableDepthBuffer()),
mDepthBufferNeedsClear(false)
@ -111,11 +114,23 @@ RenderViewMLGPU::AddChild(RenderViewMLGPU* aParent)
void
RenderViewMLGPU::Render()
{
// We render tiles front-to-back, depth-first, to minimize render target switching.
// We render views depth-first to minimize render target switching.
for (const auto& child : mChildren) {
child->Render();
}
// If the view requires a surface copy (of its backdrop), then we delay
// rendering it until it is added to a batch.
if (mContainer && mContainer->NeedsSurfaceCopy()) {
return;
}
ExecuteRendering();
}
void
RenderViewMLGPU::RenderAfterBackdropCopy()
{
MOZ_ASSERT(mContainer && mContainer->NeedsSurfaceCopy());
ExecuteRendering();
}
@ -385,26 +400,19 @@ RenderViewMLGPU::ExecuteRendering()
if (!mTarget) {
return;
}
// Note: we unbind slot 0 (which is where the render target could have been
// bound on a previous frame). Otherwise we trigger D3D11_DEVICE_PSSETSHADERRESOURCES_HAZARD.
mDevice->UnsetPSTexture(0);
mDevice->SetRenderTarget(mTarget);
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
mDevice->SetScissorRect(Some(mInvalidBounds));
if (!mWorldConstants.IsValid()) {
gfxWarning() << "Failed to allocate constant buffer for world transform";
return;
}
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
SetDeviceState();
// If using the depth buffer, clear it (if needed) and enable writes.
if (mUseDepthBuffer) {
if (mDepthBufferNeedsClear) {
mDevice->ClearDepthBuffer(mTarget);
}
mDevice->SetDepthTestMode(MLGDepthTestMode::Write);
SetDepthTestMode(MLGDepthTestMode::Write);
}
// Opaque items, rendered front-to-back.
@ -415,7 +423,7 @@ RenderViewMLGPU::ExecuteRendering()
if (mUseDepthBuffer) {
// From now on we might be rendering transparent pixels, so we disable
// writing to the z-buffer.
mDevice->SetDepthTestMode(MLGDepthTestMode::ReadOnly);
SetDepthTestMode(MLGDepthTestMode::ReadOnly);
}
// Clear any pixels that are not occluded, and therefore might require
@ -466,14 +474,37 @@ RenderViewMLGPU::ExecutePass(RenderPassMLGPU* aPass)
mDevice->SetVSConstantBuffer(kMaskBufferSlot, &section);
}
// Change the blend state if needed.
if (Maybe<MLGBlendState> blendState = aPass->GetBlendState()) {
mDevice->SetBlendState(blendState.value());
}
aPass->ExecuteRendering();
}
void
RenderViewMLGPU::SetDeviceState()
{
// Note: we unbind slot 0 (which is where the render target could have been
// bound on a previous frame). Otherwise we trigger D3D11_DEVICE_PSSETSHADERRESOURCES_HAZARD.
mDevice->UnsetPSTexture(0);
mDevice->SetRenderTarget(mTarget);
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
mDevice->SetScissorRect(Some(mInvalidBounds));
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
}
void
RenderViewMLGPU::SetDepthTestMode(MLGDepthTestMode aMode)
{
mDevice->SetDepthTestMode(aMode);
mCurrentDepthMode = aMode;
}
void
RenderViewMLGPU::RestoreDeviceState()
{
SetDeviceState();
mDevice->SetDepthTestMode(mCurrentDepthMode);
mCurrentLayerBufferIndex = kInvalidResourceIndex;
mCurrentMaskRectBufferIndex = kInvalidResourceIndex;
}
int32_t
RenderViewMLGPU::PrepareDepthBuffer()
{
@ -514,6 +545,11 @@ RenderViewMLGPU::PrepareDepthBuffer()
void
RenderViewMLGPU::PrepareClears()
{
// We don't do any clearing if we're copying from a source backdrop.
if (mContainer && mContainer->NeedsSurfaceCopy()) {
return;
}
// Get the list of rects to clear. If using the depth buffer, we don't
// care if it's accurate since the GPU will do occlusion testing for us.
// If not using the depth buffer, we subtract out the occluded region.

View File

@ -52,6 +52,11 @@ public:
return mUseDepthBuffer;
}
// Render after having previously delayed rendering due to the view
// requiring a backdrop copy.
void RenderAfterBackdropCopy();
void RestoreDeviceState();
// The size and render target cannot be read until the view has finished
// building, since we try to right-size the render target to the visible
// region.
@ -72,6 +77,8 @@ private:
void AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem);
void PrepareClears();
void SetDeviceState();
void SetDepthTestMode(MLGDepthTestMode aMode);
void ExecutePass(RenderPassMLGPU* aPass);
@ -124,6 +131,9 @@ private:
size_t mCurrentLayerBufferIndex;
size_t mCurrentMaskRectBufferIndex;
// This state is saved locally so it can be restored in RestoreDeviceState.
MLGDepthTestMode mCurrentDepthMode;
// Depth-buffer tracking.
int32_t mNextSortIndex;
bool mUseDepthBuffer;