fune/gfx/layers/client/SingleTiledContentClient.cpp
Ryan Hunt 8091824d19 Bug 1478815 part 10 - Don't submit PaintTask's if the DrawTargetCapture is empty. r=bas
This commit exposes a method on DrawTargetCapture to see if it has
captured any drawing commands. This allows us to not dispatch
paint tasks if they will do nothing.

Ideally these tasks would execute instantly on the PaintThread, and
we would never delay sending the layer transaction or block on the
next paint, but with thread starvation and context switches it's
best to just not send them.

MozReview-Commit-ID: 7ywkEDBw6EX

--HG--
extra : rebase_source : c60c1c25d551e4a7c14c529137f8e0babc888466
extra : source : 7ae4c893867a5f7df81e0757d4b4a6a21cbc6986
2018-07-31 17:47:51 -05:00

265 lines
9.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/SingleTiledContentClient.h"
#include "ClientTiledPaintedLayer.h"
#include "mozilla/Maybe.h"
namespace mozilla {
namespace layers {
SingleTiledContentClient::SingleTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer,
ClientLayerManager* aManager)
: TiledContentClient(aManager, "Single")
{
MOZ_COUNT_CTOR(SingleTiledContentClient);
mTiledBuffer = new ClientSingleTiledLayerBuffer(aPaintedLayer, *this, aManager);
}
void
SingleTiledContentClient::ClearCachedResources()
{
CompositableClient::ClearCachedResources();
mTiledBuffer->DiscardBuffers();
}
void
SingleTiledContentClient::UpdatedBuffer(TiledBufferType aType)
{
mForwarder->UseTiledLayerBuffer(this, mTiledBuffer->GetSurfaceDescriptorTiles());
}
/* static */ bool
SingleTiledContentClient::ClientSupportsLayerSize(const gfx::IntSize& aSize, ClientLayerManager* aManager)
{
int32_t maxTextureSize = aManager->GetMaxTextureSize();
return aSize.width <= maxTextureSize && aSize.height <= maxTextureSize;
}
ClientSingleTiledLayerBuffer::ClientSingleTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer,
CompositableClient& aCompositableClient,
ClientLayerManager* aManager)
: ClientTiledLayerBuffer(aPaintedLayer, aCompositableClient)
, mManager(aManager)
, mWasLastPaintProgressive(false)
, mFormat(gfx::SurfaceFormat::UNKNOWN)
{
}
void
ClientSingleTiledLayerBuffer::ReleaseTiles()
{
if (!mTile.IsPlaceholderTile()) {
mTile.DiscardBuffers();
}
mTile.SetTextureAllocator(nullptr);
}
void
ClientSingleTiledLayerBuffer::DiscardBuffers()
{
if (!mTile.IsPlaceholderTile()) {
mTile.DiscardFrontBuffer();
mTile.DiscardBackBuffer();
}
}
SurfaceDescriptorTiles
ClientSingleTiledLayerBuffer::GetSurfaceDescriptorTiles()
{
InfallibleTArray<TileDescriptor> tiles;
TileDescriptor tileDesc = mTile.GetTileDescriptor();
tiles.AppendElement(tileDesc);
mTile.mUpdateRect = gfx::IntRect();
return SurfaceDescriptorTiles(mValidRegion,
tiles,
mTilingOrigin,
mSize,
0, 0, 1, 1,
1.0,
mFrameResolution.xScale,
mFrameResolution.yScale,
mWasLastPaintProgressive);
}
already_AddRefed<TextureClient>
ClientSingleTiledLayerBuffer::GetTextureClient()
{
MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN);
return mCompositableClient.CreateTextureClientForDrawing(
gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content,
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::NON_BLOCKING_READ_LOCK);
}
void
ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
const nsIntRegion& aDirtyRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData,
TilePaintFlags aFlags)
{
mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive);
bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
// Compare layer valid region size to current backbuffer size, discard if not matching.
gfx::IntSize size = aNewValidRegion.GetBounds().Size();
gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft();
nsIntRegion paintRegion = aPaintRegion;
RefPtr<TextureClient> discardedFrontBuffer = nullptr;
RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr;
nsIntRegion discardedValidRegion;
if (mSize != size ||
mTilingOrigin != origin) {
discardedFrontBuffer = mTile.mFrontBuffer;
discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite;
discardedValidRegion = mValidRegion;
TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer);
ResetPaintedAndValidState();
mSize = size;
mTilingOrigin = origin;
paintRegion = aNewValidRegion;
}
SurfaceMode mode;
gfxContentType content = GetContentType(&mode);
mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content);
if (mTile.IsPlaceholderTile()) {
mTile.SetTextureAllocator(this);
}
if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) {
AutoTArray<uint64_t, 2> syncTextureSerials;
mTile.GetSyncTextureSerials(mode, syncTextureSerials);
if (syncTextureSerials.Length() > 0) {
mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials);
}
}
// The dirty region relative to the top-left of the tile.
nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin);
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
Maybe<AcquiredBackBuffer> backBuffer =
mTile.AcquireBackBuffer(mCompositableClient,
tileDirtyRegion,
tileVisibleRegion,
content,
mode,
aFlags);
if (!backBuffer) {
return;
}
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
mTile.mInvalidFront.OrWith(tileDirtyRegion);
// Add backbuffer's invalid region to the dirty region to be painted.
// This will be empty if we were able to copy from the front in to the back.
nsIntRegion tileInvalidRegion = mTile.mInvalidBack;
tileInvalidRegion.AndWith(tileVisibleRegion);
paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin));
tileDirtyRegion.OrWith(tileInvalidRegion);
// Mark the region we will be painting and the region we copied from the front buffer as
// needing to be uploaded to the compositor
mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect);
// If the old frontbuffer was discarded then attempt to copy what we
// can from it to the new backbuffer.
if (discardedFrontBuffer) {
nsIntRegion copyableRegion;
copyableRegion.And(aNewValidRegion, discardedValidRegion);
copyableRegion.SubOut(aDirtyRegion);
OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC
: OpenMode::OPEN_READ;
DualTextureClientAutoLock discardedBuffer(discardedFrontBuffer, discardedFrontBufferOnWhite, readMode);
if (discardedBuffer.Succeeded()) {
RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot();
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect src = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
backBuffer->mTarget->CopySurface(discardedSurface, src, dest);
}
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
// We don't need to repaint valid content that was just copied.
paintRegion.SubOut(copyableRegion);
copyableRegion.MoveBy(-mTilingOrigin);
tileDirtyRegion.SubOut(copyableRegion);
} else {
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
}
}
if (mode != SurfaceMode::SURFACE_OPAQUE) {
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
backBuffer->mTarget->ClearRect(drawRect);
}
}
// Paint into the target
{
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget);
if (!ctx) {
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(backBuffer->mTarget);
return;
}
ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
}
if (asyncPaint) {
if (!backBuffer->mCapture->IsEmpty()) {
RefPtr<PaintTask> task = new PaintTask();
task->mCapture = backBuffer->mCapture;
task->mTarget = backBuffer->mBackBuffer;
task->mClients = std::move(backBuffer->mTextureClients);
PaintThread::Get()->QueuePaintTask(task);
mManager->SetQueuedAsyncPaints();
}
} else {
MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
MOZ_ASSERT(!backBuffer->mCapture);
}
// The new buffer is now validated, remove the dirty region from it.
mTile.mInvalidBack.SubOut(tileDirtyRegion);
backBuffer = Nothing();
mTile.Flip();
UnlockTile(mTile);
mValidRegion = aNewValidRegion;
mLastPaintSurfaceMode = mode;
mLastPaintContentType = content;
}
} // namespace layers
} // namespace mozilla