Bug 1019856 - avoid double-buffering in BasicCompositor when window allows it. r=mattwoodrow

This commit is contained in:
Lee Salzman 2016-02-18 20:57:29 -05:00
parent acacadfda1
commit ba30bddd22
7 changed files with 73 additions and 37 deletions

View File

@ -153,6 +153,32 @@ BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect,
return nullptr;
}
already_AddRefed<CompositingRenderTarget>
BasicCompositor::CreateRenderTargetForWindow(const IntRect& aRect, SurfaceInitMode aInit, BufferMode aBufferMode)
{
if (aBufferMode != BufferMode::BUFFER_NONE) {
return CreateRenderTarget(aRect, aInit);
}
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;
}
MOZ_ASSERT(mDrawTarget);
// Adjust bounds rect to account for new origin at (0, 0).
IntRect rect(0, 0, aRect.XMost(), aRect.YMost());
RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(mDrawTarget, rect);
if (aInit == INIT_MODE_CLEAR) {
mDrawTarget->ClearRect(gfx::Rect(aRect));
}
return rt.forget();
}
already_AddRefed<DataTextureSource>
BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
{
@ -557,13 +583,14 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
*aRenderBoundsOut = Rect();
}
BufferMode bufferMode = BufferMode::BUFFERED;
if (mTarget) {
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy
// placeholder so that CreateRenderTarget() works.
mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
} else {
// StartRemoteDrawingInRegion can mutate mInvalidRegion.
mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion);
mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode);
if (!mDrawTarget) {
return;
}
@ -581,7 +608,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
// Setup an intermediate render target to buffer all compositing. We will
// copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
RefPtr<CompositingRenderTarget> target =
CreateRenderTarget(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR);
CreateRenderTargetForWindow(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR, bufferMode);
if (!target) {
if (!mTarget) {
mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
@ -592,8 +619,7 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
// We only allocate a surface sized to the invalidated region, so we need to
// translate future coordinates.
mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mInvalidRect.x,
-mInvalidRect.y));
mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mRenderTarget->GetOrigin()));
gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget,
mInvalidRegion.ToUnknownRegion());
@ -631,22 +657,25 @@ BasicCompositor::EndFrame()
// Pop aInvalidregion
mRenderTarget->mDrawTarget->PopClip();
// Note: Most platforms require us to buffer drawing to the widget surface.
// That's why we don't draw to mDrawTarget directly.
RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
RefPtr<DrawTarget> dest(mTarget ? mTarget : mDrawTarget);
if (mTarget || mRenderTarget->mDrawTarget != mDrawTarget) {
// Note: Most platforms require us to buffer drawing to the widget surface.
// That's why we don't draw to mDrawTarget directly.
RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
RefPtr<DrawTarget> dest(mTarget ? mTarget : mDrawTarget);
nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
// The source DrawTarget is clipped to the invalidation region, so we have
// to copy the individual rectangles in the region or else we'll draw blank
// pixels.
for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
const LayoutDeviceIntRect& r = iter.Get();
dest->CopySurface(source,
IntRect(r.x - mInvalidRect.x, r.y - mInvalidRect.y, r.width, r.height),
IntPoint(r.x - offset.x, r.y - offset.y));
// The source DrawTarget is clipped to the invalidation region, so we have
// to copy the individual rectangles in the region or else we'll draw blank
// pixels.
for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
const LayoutDeviceIntRect& r = iter.Get();
dest->CopySurface(source,
IntRect(r.x, r.y, r.width, r.height) - mRenderTarget->GetOrigin(),
IntPoint(r.x, r.y) - offset);
}
}
if (!mTarget) {
mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
}

View File

@ -62,6 +62,11 @@ public:
const CompositingRenderTarget *aSource,
const gfx::IntPoint &aSourcePoint) override;
virtual already_AddRefed<CompositingRenderTarget>
CreateRenderTargetForWindow(const gfx::IntRect& aRect,
SurfaceInitMode aInit,
BufferMode aBufferMode);
virtual already_AddRefed<DataTextureSource>
CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;

View File

@ -539,7 +539,9 @@ public:
return nsCocoaUtils::DevPixelsToCocoaPoints(aRect, BackingScaleFactor());
}
already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) override;
already_AddRefed<mozilla::gfx::DrawTarget>
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
mozilla::layers::BufferMode* aBufferMode) override;
void EndRemoteDrawing() override;
void CleanupRemoteDrawing() override;
bool InitCompositor(mozilla::layers::Compositor* aCompositor) override;

View File

@ -2635,7 +2635,8 @@ nsChildView::SwipeFinished()
}
already_AddRefed<gfx::DrawTarget>
nsChildView::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion)
nsChildView::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
BufferMode* aBufferMode)
{
// should have created the GLPresenter in InitCompositor.
MOZ_ASSERT(mGLPresenter);

View File

@ -2225,7 +2225,8 @@ nsWindow::OnExposeEvent(cairo_t *cr)
return TRUE;
}
RefPtr<DrawTarget> dt = GetDrawTarget(region);
BufferMode layerBuffering = BufferMode::BUFFERED;
RefPtr<DrawTarget> dt = GetDrawTarget(region, &layerBuffering);
if (!dt) {
return FALSE;
}
@ -2245,7 +2246,6 @@ nsWindow::OnExposeEvent(cairo_t *cr)
gfxUtils::ClipToRegion(dt, region.ToUnknownRegion());
}
BufferMode layerBuffering;
if (shaped) {
// The double buffering is done here to extract the shape mask.
// (The shape mask won't be necessary when a visual with an alpha
@ -2254,16 +2254,6 @@ nsWindow::OnExposeEvent(cairo_t *cr)
RefPtr<DrawTarget> destDT = dt->CreateSimilarDrawTarget(boundsRect.Size(), SurfaceFormat::B8G8R8A8);
ctx = new gfxContext(destDT, boundsRect.TopLeft());
} else {
#ifdef MOZ_HAVE_SHMIMAGE
if (nsShmImage::UseShm()) {
// We're using an xshm mapping as a back buffer.
layerBuffering = BufferMode::BUFFER_NONE;
} else
#endif // MOZ_HAVE_SHMIMAGE
{
// Get the layer manager to do double buffering (if necessary).
layerBuffering = BufferMode::BUFFERED;
}
ctx = new gfxContext(dt);
}
@ -6455,7 +6445,7 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
#endif
already_AddRefed<DrawTarget>
nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion)
nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion, BufferMode* aBufferMode)
{
if (!mGdkWindow) {
return nullptr;
@ -6474,12 +6464,14 @@ nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion)
if (nsShmImage::UseShm()) {
dt = nsShmImage::EnsureShmImage(size,
mXDisplay, mXVisual, mXDepth, mShmImage);
*aBufferMode = BufferMode::BUFFER_NONE;
}
# endif // MOZ_HAVE_SHMIMAGE
if (!dt) {
RefPtr<gfxXlibSurface> surf = new gfxXlibSurface(mXDisplay, mXWindow, mXVisual, size.ToUnknownSize());
if (!surf->CairoStatus()) {
dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf.get(), surf->GetSize());
*aBufferMode = BufferMode::BUFFERED;
}
}
#endif // MOZ_X11
@ -6488,9 +6480,9 @@ nsWindow::GetDrawTarget(const LayoutDeviceIntRegion& aRegion)
}
already_AddRefed<DrawTarget>
nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion)
nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode)
{
return GetDrawTarget(aInvalidRegion);
return GetDrawTarget(aInvalidRegion, aBufferMode);
}
void

View File

@ -216,7 +216,8 @@ public:
#endif
virtual already_AddRefed<mozilla::gfx::DrawTarget>
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) override;
StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
mozilla::layers::BufferMode* aBufferMode) override;
virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
LayoutDeviceIntRegion& aInvalidRegion) override;
@ -309,7 +310,9 @@ public:
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
uint8_t* aAlphas, int32_t aStride);
virtual already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget(const LayoutDeviceIntRegion& aRegion);
already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget(const LayoutDeviceIntRegion& aRegion,
mozilla::layers::BufferMode* aBufferMode);
#if (MOZ_WIDGET_GTK == 2)
static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,

View File

@ -1287,9 +1287,13 @@ class nsIWidget : public nsISupports {
*
* Called by BasicCompositor on the compositor thread for OMTC drawing
* before each composition.
*
* The window may specify its buffer mode. If unspecified, it is assumed
* to require double-buffering.
*/
virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0;
virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion) {
virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
mozilla::layers::BufferMode* aBufferMode) {
return StartRemoteDrawing();
}