diff options
Diffstat (limited to 'gfx/layers/client/SingleTiledContentClient.cpp')
-rw-r--r-- | gfx/layers/client/SingleTiledContentClient.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/gfx/layers/client/SingleTiledContentClient.cpp b/gfx/layers/client/SingleTiledContentClient.cpp new file mode 100644 index 000000000..bcc8691cf --- /dev/null +++ b/gfx/layers/client/SingleTiledContentClient.cpp @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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" + +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()); + mTiledBuffer->ClearPaintedRegion(); +} + +/* 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) + , 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); +} + +void +ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion, + LayerManager::DrawPaintedLayerCallback aCallback, + void* aCallbackData, + bool aIsProgressive) +{ + mWasLastPaintProgressive = aIsProgressive; + + // 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); + } + + // The dirty region relative to the top-left of the tile. + nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); + + nsIntRegion extraPainted; + RefPtr<TextureClient> backBufferOnWhite; + RefPtr<TextureClient> backBuffer = + mTile.GetBackBuffer(mCompositableClient, + tileDirtyRegion, + content, mode, + extraPainted, + &backBufferOnWhite); + + mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds()); + + extraPainted.MoveBy(mTilingOrigin); + extraPainted.And(extraPainted, aNewValidRegion); + mPaintedRegion.OrWith(paintRegion); + mPaintedRegion.OrWith(extraPainted); + + if (!backBuffer) { + return; + } + + RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget(); + RefPtr<gfx::DrawTarget> dtOnWhite; + if (backBufferOnWhite) { + dtOnWhite = backBufferOnWhite->BorrowDrawTarget(); + } + + if (mode != SurfaceMode::SURFACE_OPAQUE) { + for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { + const gfx::IntRect& rect = iter.Get(); + if (dtOnWhite) { + dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), + gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0))); + dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), + gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0))); + } else { + dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height)); + } + } + } + + // 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); + + if (!copyableRegion.IsEmpty()) { + TextureClientAutoLock frontLock(discardedFrontBuffer, + OpenMode::OPEN_READ); + if (frontLock.Succeeded()) { + for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { + const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); + const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; + discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest); + } + } + + if (discardedFrontBufferOnWhite && backBufferOnWhite) { + TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite, + OpenMode::OPEN_READ); + if (frontOnWhiteLock.Succeeded()) { + for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { + const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); + const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; + + discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite, + &rect, &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); + } + } + + if (dtOnWhite) { + dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite); + dtOnWhite = nullptr; + } + + { + RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt); + if (!ctx) { + gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt); + return; + } + ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y)); + + aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); + } + + // Mark the area we just drew into the back buffer as invalid in the front buffer as they're + // now out of sync. + mTile.mInvalidFront.OrWith(tileDirtyRegion); + + // The new buffer is now validated, remove the dirty region from it. + mTile.mInvalidBack.SubOut(tileDirtyRegion); + + dt = nullptr; + + mTile.Flip(); + UnlockTile(mTile); + + if (backBuffer->HasIntermediateBuffer()) { + // If our new buffer has an internal buffer, we don't want to keep another + // TextureClient around unnecessarily, so discard the back-buffer. + mTile.DiscardBackBuffer(); + } + + mValidRegion = aNewValidRegion; + mLastPaintSurfaceMode = mode; + mLastPaintContentType = content; +} + +} // namespace layers +} // namespace mozilla |