Bug 1092360 - Avoid redundant framebuffer switches. r=jrmuizel

This commit is contained in:
Benoit Girard 2014-11-12 17:39:17 -05:00
parent 10872ba23d
commit 8d0678b3a9
13 changed files with 96 additions and 74 deletions

View File

@ -17,6 +17,18 @@ class Matrix4x4;
namespace layers {
Compositor::Compositor(PCompositorParent* aParent)
: mCompositorID(0)
, mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
, mParent(aParent)
, mScreenRotation(ROTATION_0)
{
}
Compositor::~Compositor()
{
}
/* static */ LayersBackend Compositor::sBackend = LayersBackend::LAYERS_NONE;
/* static */ LayersBackend
Compositor::GetBackend()

View File

@ -182,18 +182,12 @@ enum SurfaceInitMode
class Compositor
{
protected:
virtual ~Compositor() {}
virtual ~Compositor();
public:
NS_INLINE_DECL_REFCOUNTING(Compositor)
explicit Compositor(PCompositorParent* aParent = nullptr)
: mCompositorID(0)
, mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
, mParent(aParent)
, mScreenRotation(ROTATION_0)
{
}
explicit Compositor(PCompositorParent* aParent = nullptr);
virtual TemporaryRef<DataTextureSource> CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) = 0;
virtual bool Initialize() = 0;
@ -478,6 +472,12 @@ public:
mScreenRotation = aRotation;
}
/**
* This is called to set the composition target (the screen or an offscreen target)
* after we've ran the prepare phase. This must be called after BeginFrame.
*/
virtual void SetFinalDestinationTarget() = 0;
protected:
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
const gfx::Rect& aVisibleRect,
@ -510,6 +510,7 @@ protected:
RefPtr<gfx::DrawTarget> mTarget;
nsIntRect mTargetBounds;
RefPtr<CompositingRenderTarget> mFinalDestinationTarget;
private:
static LayersBackend sBackend;

View File

@ -85,13 +85,16 @@ void BasicCompositor::Destroy()
TemporaryRef<CompositingRenderTarget>
BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
{
MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
MOZ_ASSERT(aRect.width != 0 && aRect.height != 0,
"Trying to create a render target of invalid size");
if (aRect.width * aRect.height == 0) {
return nullptr;
}
RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
RefPtr<DrawTarget> target =
static_cast<BasicCompositingRenderTarget*>(mFinalDestinationTarget.get())->mDrawTarget->
CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
if (!target) {
return nullptr;
@ -440,7 +443,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
}
return;
}
SetRenderTarget(target);
mFinalDestinationTarget = target;
// We only allocate a surface sized to the invalidated region, so we need to
// translate future coordinates.
@ -454,9 +457,9 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
}
if (aClipRectIn) {
mRenderTarget->mDrawTarget->PushClipRect(*aClipRectIn);
mDrawTarget->PushClipRect(*aClipRectIn);
} else {
mRenderTarget->mDrawTarget->PushClipRect(rect);
mDrawTarget->PushClipRect(rect);
if (aClipRectOut) {
*aClipRectOut = rect;
}
@ -503,6 +506,7 @@ BasicCompositor::EndFrame()
mDrawTarget = nullptr;
mRenderTarget = nullptr;
mFinalDestinationTarget = nullptr;
}
void
@ -512,6 +516,7 @@ BasicCompositor::AbortFrame()
mRenderTarget->mDrawTarget->PopClip();
mDrawTarget = nullptr;
mRenderTarget = nullptr;
mFinalDestinationTarget = nullptr;
}
}

View File

@ -121,6 +121,10 @@ public:
gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; }
virtual void SetFinalDestinationTarget() MOZ_OVERRIDE {
MOZ_ASSERT(mFinalDestinationTarget);
SetRenderTarget(mFinalDestinationTarget);
}
private:
virtual gfx::IntSize GetWidgetSize() const MOZ_OVERRIDE { return mWidgetSize; }

View File

@ -138,6 +138,8 @@ ContainerPrepare(ContainerT* aContainer,
LayerManagerComposite* aManager,
const RenderTargetIntRect& aClipRect)
{
Compositor* compositor = aManager->GetCompositor();
aContainer->mPrepared = MakeUnique<PreparedData>();
aContainer->mPrepared->mNeedsSurfaceCopy = false;
@ -184,7 +186,12 @@ ContainerPrepare(ContainerT* aContainer,
// If we don't need a copy we can render to the intermediate now to avoid
// unecessary render target switching. This brings a big perf boost on mobile gpus.
RefPtr<CompositingRenderTarget> surface = CreateTemporaryTarget(aContainer, aManager);
RenderIntermediate(aContainer, aManager, RenderTargetPixel::ToUntyped(aClipRect), surface);
if (surface) {
compositor->SetRenderTarget(surface);
RenderLayers(aContainer, aManager, aClipRect);
}
aContainer->mPrepared->mTmpTarget = surface;
} else {
aContainer->mPrepared->mNeedsSurfaceCopy = true;
@ -304,40 +311,26 @@ CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget, sourcePoint);
}
template<class ContainerT> void
RenderIntermediate(ContainerT* aContainer,
LayerManagerComposite* aManager,
const nsIntRect& aClipRect,
RefPtr<CompositingRenderTarget> surface)
{
Compositor* compositor = aManager->GetCompositor();
RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
if (!surface) {
return;
}
compositor->SetRenderTarget(surface);
// pre-render all of the layers into our temporary
RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
// Unbind the current surface and rebind the previous one.
compositor->SetRenderTarget(previousTarget);
}
template<class ContainerT> void
ContainerRender(ContainerT* aContainer,
LayerManagerComposite* aManager,
const nsIntRect& aClipRect)
{
Compositor* compositor = aManager->GetCompositor();
MOZ_ASSERT(aContainer->mPrepared);
if (aContainer->UseIntermediateSurface()) {
RefPtr<CompositingRenderTarget> surface;
if (aContainer->mPrepared->mNeedsSurfaceCopy) {
RefPtr<CompositingRenderTarget> previousTarget = compositor->GetCurrentRenderTarget();
// we needed to copy the background so we waited until now to render the intermediate
surface = CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
RenderIntermediate(aContainer, aManager,
aClipRect, surface);
compositor->SetRenderTarget(surface);
if (surface) {
RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
}
compositor->SetRenderTarget(previousTarget);
} else {
surface = aContainer->mPrepared->mTmpTarget;
}
@ -352,7 +345,7 @@ ContainerRender(ContainerT* aContainer,
nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
if (surf) {
WriteSnapshotToDumpFile(aContainer, surf);
}

View File

@ -37,11 +37,6 @@ class ContainerLayerComposite : public ContainerLayer,
LayerManagerComposite* aManager,
const RenderTargetIntRect& aClipRect);
template<class ContainerT>
friend void RenderIntermediate(ContainerT* aContainer,
LayerManagerComposite* aManager,
const nsIntRect& aClipRect,
RefPtr<CompositingRenderTarget> surface);
template<class ContainerT>
friend RefPtr<CompositingRenderTarget>
CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
LayerManagerComposite* aManager,
@ -112,11 +107,6 @@ class RefLayerComposite : public RefLayer,
LayerManagerComposite* aManager,
const nsIntRect& aClipRect);
template<class ContainerT>
friend void RenderIntermediate(ContainerT* aContainer,
LayerManagerComposite* aManager,
const nsIntRect& aClipRect,
RefPtr<CompositingRenderTarget> surface);
template<class ContainerT>
friend RefPtr<CompositingRenderTarget>
CreateTemporaryTargetAndCopyFromBackground(ContainerT* aContainer,
LayerManagerComposite* aManager,

View File

@ -704,10 +704,16 @@ LayerManagerComposite::Render()
}
if (actualBounds.IsEmpty()) {
mCompositor->SetFinalDestinationTarget();
mCompositor->GetWidget()->PostRender(this);
return;
}
// Prepare our intermediate surface to minimize render target switches.
RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
mCompositor->SetFinalDestinationTarget();
// Allow widget to render a custom background.
mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x,
actualBounds.y,
@ -722,7 +728,6 @@ LayerManagerComposite::Render()
}
// Render our layers.
RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
RootLayer()->RenderLayer(clipRect);
if (!mRegionToClear.IsEmpty()) {

View File

@ -869,7 +869,7 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
mContext->RSSetState(mAttachments->mRasterizerState);
SetRenderTarget(mDefaultRT);
mFinalDestinationTarget = mDefaultRT;
}
void
@ -888,6 +888,7 @@ CompositorD3D11::EndFrame()
}
mCurrentRT = nullptr;
mFinalDestinationTarget = nullptr;
}
void

View File

@ -142,6 +142,10 @@ public:
ID3D11DeviceContext* GetDC() { return mContext; }
virtual void SetFinalDestinationTarget() MOZ_OVERRIDE {
MOZ_ASSERT(mFinalDestinationTarget);
SetRenderTarget(mFinalDestinationTarget);
}
private:
enum Severity {
Recoverable,

View File

@ -592,7 +592,7 @@ CompositorD3D9::Ready()
return false;
}
NS_ASSERTION(!mCurrentRT && !mDefaultRT,
NS_ASSERTION(!mCurrentRT && !mFinalDestinationTarget,
"Shouldn't have any render targets around, they must be released before our device");
mSwapChain = nullptr;
@ -645,10 +645,9 @@ CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
device()->SetScissorRect(&r);
nsRefPtr<IDirect3DSurface9> backBuffer = mSwapChain->GetBackBuffer();
mDefaultRT = new CompositingRenderTargetD3D9(backBuffer,
INIT_MODE_CLEAR,
IntRect(0, 0, mSize.width, mSize.height));
SetRenderTarget(mDefaultRT);
mFinalDestinationTarget = new CompositingRenderTargetD3D9(backBuffer,
INIT_MODE_CLEAR,
IntRect(0, 0, mSize.width, mSize.height));
}
void
@ -669,7 +668,7 @@ CompositorD3D9::EndFrame()
}
mCurrentRT = nullptr;
mDefaultRT = nullptr;
mFinalDestinationTarget = nullptr;
}
void

View File

@ -120,6 +120,11 @@ public:
virtual TemporaryRef<DataTextureSource>
CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) MOZ_OVERRIDE;
virtual void SetFinalDestinationTarget() MOZ_OVERRIDE {
MOZ_ASSERT(mFinalDestinationTarget);
SetRenderTarget(mFinalDestinationTarget);
}
private:
// ensure mSize is up to date with respect to mWidget
void EnsureSize();
@ -164,7 +169,6 @@ private:
/* Widget associated with this layer manager */
nsIWidget *mWidget;
RefPtr<CompositingRenderTargetD3D9> mDefaultRT;
RefPtr<CompositingRenderTargetD3D9> mCurrentRT;
nsIntSize mSize;

View File

@ -448,6 +448,21 @@ CompositorOGL::PrepareViewport(const gfx::IntSize& aSize)
mProjMatrix = matrix3d;
}
void
CompositorOGL::SetFinalDestinationTarget() {
MOZ_ASSERT(mFinalDestinationTarget);
SetRenderTarget(mFinalDestinationTarget);
// If the Android compositor is being used, this clear will be done in
// DrawWindowUnderlay. Make sure the bits used here match up with those used
// in mobile/android/base/gfx/LayerRenderer.java
#ifndef MOZ_WIDGET_ANDROID
mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
#endif
}
TemporaryRef<CompositingRenderTarget>
CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
{
@ -608,15 +623,10 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
TexturePoolOGL::Fill(gl());
#endif
mCurrentRenderTarget =
mFinalDestinationTarget =
CompositingRenderTargetOGL::RenderTargetForWindow(this,
IntSize(width, height));
mCurrentRenderTarget->BindRenderTarget();
mContextStateTracker.PushOGLSection(gl(), "Frame");
#ifdef DEBUG
mWindowRenderTarget = mCurrentRenderTarget;
#endif
// Default blend function implements "OVER"
mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
@ -628,14 +638,6 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
if (aClipRectOut && !aClipRectIn) {
aClipRectOut->SetRect(0, 0, width, height);
}
// If the Android compositor is being used, this clear will be done in
// DrawWindowUnderlay. Make sure the bits used here match up with those used
// in mobile/android/base/gfx/LayerRenderer.java
#ifndef MOZ_WIDGET_ANDROID
mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
#endif
}
void
@ -1175,7 +1177,8 @@ CompositorOGL::EndFrame()
PROFILER_LABEL("CompositorOGL", "EndFrame",
js::ProfileEntry::Category::GRAPHICS);
MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
MOZ_ASSERT(mCurrentRenderTarget == mFinalDestinationTarget,
"Rendering target not properly restored");
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
@ -1204,6 +1207,7 @@ CompositorOGL::EndFrame()
}
mCurrentRenderTarget = nullptr;
mFinalDestinationTarget = nullptr;
if (mTexturePool) {
mTexturePool->EndFrame();
@ -1296,6 +1300,7 @@ CompositorOGL::AbortFrame()
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
mFrameInProgress = false;
mCurrentRenderTarget = nullptr;
mFinalDestinationTarget = nullptr;
if (mTexturePool) {
mTexturePool->EndFrame();

View File

@ -272,6 +272,8 @@ public:
const gfx::Matrix4x4& GetProjMatrix() const {
return mProjMatrix;
}
virtual void SetFinalDestinationTarget() MOZ_OVERRIDE;
private:
virtual gfx::IntSize GetWidgetSize() const MOZ_OVERRIDE
{
@ -297,9 +299,6 @@ private:
/** Currently bound render target */
RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
#ifdef DEBUG
CompositingRenderTargetOGL* mWindowRenderTarget;
#endif
/**
* VBO that has some basics in it for a textured quad, including vertex