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()) { UniquePtr<PaintTask> task(new PaintTask()); task->mCapture = backBuffer->mCapture; task->mTarget = backBuffer->mBackBuffer; task->mClients = std::move(backBuffer->mTextureClients); if (discardedFrontBuffer) { task->mClients.AppendElement(discardedFrontBuffer); } if (discardedFrontBufferOnWhite) { task->mClients.AppendElement(discardedFrontBufferOnWhite); } // The target is an alias for the capture, and the paint thread expects // to be the only one with a reference to the capture backBuffer->mTarget = nullptr; backBuffer->mCapture = nullptr; PaintThread::Get()->QueuePaintTask(std::move(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; }
void ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) { // Compare layer visible region size to current backbuffer size, discard if not matching. IntSize size = mPaintedLayer->GetVisibleRegion().GetBounds().Size(); IntPoint origin = mPaintedLayer->GetVisibleRegion().GetBounds().TopLeft(); nsIntRegion paintRegion = aPaintRegion; if (mSize != size || mTilingOrigin != origin) { ResetPaintedAndValidState(); mSize = size; mTilingOrigin = origin; paintRegion = aNewValidRegion; } SurfaceMode mode; gfxContentType content = GetContentType(&mode); mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); if (mTile.IsPlaceholderTile()) { mTile.SetLayerManager(mManager); mTile.SetTextureAllocator(this); } mTile.SetCompositableClient(mCompositableClient); // 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(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<DrawTarget> dt = backBuffer->BorrowDrawTarget(); RefPtr<DrawTarget> dtOnWhite; if (backBufferOnWhite) { dtOnWhite = backBufferOnWhite->BorrowDrawTarget(); } if (mode != SurfaceMode::SURFACE_OPAQUE) { nsIntRegionRectIterator iter(tileDirtyRegion); const IntRect *iterRect; while ((iterRect = iter.Next())) { if (dtOnWhite) { dt->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height), ColorPattern(Color(0.0, 0.0, 0.0, 1.0))); dtOnWhite->FillRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); } else { dt->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height)); } } } if (dtOnWhite) { dt = Factory::CreateDualDrawTarget(dt, dtOnWhite); dtOnWhite = nullptr; } { nsRefPtr<gfxContext> ctx = new gfxContext(dt); 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->HasInternalBuffer()) { // 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; }
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; }