void ClientCanvasLayer::RenderLayer() { PROFILER_LABEL("ClientCanvasLayer", "RenderLayer", js::ProfileEntry::Category::GRAPHICS); RenderMaskLayers(this); if (!mCanvasClient) { TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD; if (mOriginPos == gl::OriginPos::BottomLeft) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } if (!mGLContext) { // We don't support locking for buffer surfaces currently flags |= TextureFlags::IMMEDIATE_UPLOAD; } if (!mIsAlphaPremultiplied) { flags |= TextureFlags::NON_PREMULTIPLIED; } mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(), ClientManager()->AsShadowForwarder(), flags); if (!mCanvasClient) { return; } if (HasShadow()) { if (mAsyncRenderer) { static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(this); } else { mCanvasClient->Connect(); ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this); } } } if (mCanvasClient && mAsyncRenderer) { mCanvasClient->UpdateAsync(mAsyncRenderer); } if (!IsDirty()) { return; } Painted(); FirePreTransactionCallback(); if (mBufferProvider && mBufferProvider->GetTextureClient()) { mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient()); } else { mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this); } FireDidTransactionCallback(); ClientManager()->Hold(this); mCanvasClient->Updated(); }
void ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback) { RenderMaskLayers(this); if (!EnsureContentClient()) { return; } if (CanRecordLayer(aReadback)) { if (PaintOffMainThread()) { return; } } nsTArray<ReadbackProcessor::Update> readbackUpdates; nsIntRegion readbackRegion; if (aReadback && UsedForReadback()) { aReadback->GetPaintedLayerUpdates(this, &readbackUpdates); } PaintThebes(&readbackUpdates); }
void ClientTiledPaintedLayer::RenderLayer() { LayerManager::DrawPaintedLayerCallback callback = ClientManager()->GetPaintedLayerCallback(); void *data = ClientManager()->GetPaintedLayerCallbackData(); IntSize layerSize = mVisibleRegion.GetBounds().Size(); if (mContentClient && !mContentClient->SupportsLayerSize(layerSize, ClientManager())) { ClearCachedResources(); MOZ_ASSERT(!mContentClient); } if (!mContentClient) { if (mCreationHint == LayerManager::NONE && SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) && gfxPrefs::LayersSingleTileEnabled()) { mContentClient = new SingleTiledContentClient(this, ClientManager()); } else { mContentClient = new MultiTiledContentClient(this, ClientManager()); } mContentClient->Connect(); ClientManager()->AsShadowForwarder()->Attach(mContentClient, this); MOZ_ASSERT(mContentClient->GetForwarder()); } if (mContentClient->GetTiledBuffer()->HasFormatChanged()) { mValidRegion = nsIntRegion(); mContentClient->GetTiledBuffer()->ResetPaintedAndValidState(); } TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str()); TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(mValidRegion).c_str()); TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str()); nsIntRegion neededRegion = mVisibleRegion; #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE // This is handled by PadDrawTargetOutFromRegion in TiledContentClient for mobile if (MayResample()) { // If we're resampling then bilinear filtering can read up to 1 pixel // outside of our texture coords. Make the visible region a single rect, // and pad it out by 1 pixel (restricted to tile boundaries) so that // we always have valid content or transparent pixels to sample from. IntRect bounds = neededRegion.GetBounds(); IntRect wholeTiles = bounds; wholeTiles.InflateToMultiple(IntSize( gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight())); IntRect padded = bounds; padded.Inflate(1); padded.IntersectRect(padded, wholeTiles); neededRegion = padded; } #endif nsIntRegion invalidRegion; invalidRegion.Sub(neededRegion, mValidRegion); if (invalidRegion.IsEmpty()) { EndPaint(); return; } if (!callback) { ClientManager()->SetTransactionIncomplete(); return; } if (!ClientManager()->IsRepeatTransaction()) { // Only paint the mask layers on the first transaction. RenderMaskLayers(this); // For more complex cases we need to calculate a bunch of metrics before we // can do the paint. BeginPaint(); if (mPaintData.mPaintFinished) { return; } // Make sure that tiles that fall outside of the visible region or outside of the // critical displayport are discarded on the first update. Also make sure that we // only draw stuff inside the critical displayport on the first update. mValidRegion.And(mValidRegion, neededRegion); if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { mValidRegion.And(mValidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect()); invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect()); } TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(mValidRegion).c_str()); TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str()); } else { if (!mPaintData.mCriticalDisplayPort.IsEmpty()) { invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort.ToUnknownRect()); } TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str()); } nsIntRegion lowPrecisionInvalidRegion; if (mContentClient->GetLowPrecisionTiledBuffer()) { // Calculate the invalid region for the low precision buffer. Make sure // to remove the valid high-precision area so we don't double-paint it. lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion); lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion); } TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str()); bool updatedHighPrecision = RenderHighPrecision(invalidRegion, neededRegion, callback, data); if (updatedHighPrecision) { ClientManager()->Hold(this); mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER); if (!mPaintData.mPaintFinished) { // There is still more high-res stuff to paint, so we're not // done yet. A subsequent transaction will take care of this. ClientManager()->SetRepeatTransaction(); return; } } // If there is nothing to draw in low-precision, then we're done. if (lowPrecisionInvalidRegion.IsEmpty()) { EndPaint(); return; } if (updatedHighPrecision) { // If there are low precision updates, but we just did some high-precision // updates, then mark the paint as unfinished and request a repeat transaction. // This is so that we don't perform low-precision updates in the same transaction // as high-precision updates. TILING_LOG("TILING %p: Scheduling repeat transaction for low-precision painting\n", this); ClientManager()->SetRepeatTransaction(); mPaintData.mLowPrecisionPaintCount = 1; mPaintData.mPaintFinished = false; return; } bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion, neededRegion, callback, data); if (updatedLowPrecision) { ClientManager()->Hold(this); mContentClient->UpdatedBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER); if (!mPaintData.mPaintFinished) { // There is still more low-res stuff to paint, so we're not // done yet. A subsequent transaction will take care of this. ClientManager()->SetRepeatTransaction(); return; } } // If we get here, we've done all the high- and low-precision // paints we wanted to do, so we can finish the paint and chill. EndPaint(); }