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();
}