Example #1
0
TemporaryRef<TextureClient>
CompositableClient::CreateTextureClientForDrawing(SurfaceFormat aFormat,
                                                  TextureFlags aTextureFlags)
{
  RefPtr<TextureClient> result;

#ifdef XP_WIN
  LayersBackend parentBackend = GetForwarder()->GetCompositorBackendType();
  if (parentBackend == LAYERS_D3D11 && gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
    result = new TextureClientD3D11(aFormat, aTextureFlags);
  }
  if (parentBackend == LAYERS_D3D9 &&
      !GetForwarder()->ForwardsToDifferentProcess() &&
      !(aTextureFlags & TEXTURE_ALLOC_FALLBACK)) {
    // non-DIB textures don't work with alpha, see notes in TextureD3D9.
    if (ContentForFormat(aFormat) != GFX_CONTENT_COLOR) {
      result = new DIBTextureClientD3D9(aFormat, aTextureFlags);
    } else {
      result = new CairoTextureClientD3D9(aFormat, aTextureFlags);
    }
  }
#endif
  // Can't do any better than a buffer texture client.
  if (!result) {
    result = CreateBufferTextureClient(aFormat, aTextureFlags);
  }

  MOZ_ASSERT(!result || result->AsTextureClientDrawTarget(),
             "Not a TextureClientDrawTarget?");
  return result;
}
Example #2
0
TemporaryRef<TextureClient>
SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle)
{
    // Try to fetch a client from the pool
    RefPtr<TextureClient> textureClient;
    if (mAvailableTextureClients.size()) {
        textureClient = mAvailableTextureClients.top();
        textureClient->WaitReleaseFence();
        mAvailableTextureClients.pop();
        RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size(), textureClient.get());

    } else {
        // No unused clients in the pool, create one
        if (gfxPrefs::ForceShmemTiles()) {
            textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator,
                            mFormat, TEXTURE_IMMEDIATE_UPLOAD | TEXTURE_RECYCLE, gfx::BackendType::NONE);
        } else {
            textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
                            mFormat, TEXTURE_FLAGS_DEFAULT | TEXTURE_RECYCLE, gfx::BackendType::NONE, mSize);
        }
        if (!textureClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize, ALLOC_DEFAULT)) {
            NS_WARNING("TextureClient::AllocateForSurface failed!");
        }
        RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get());
    }

    if (aAutoRecycle) {
        mOutstandingTextureClients.push_back(textureClient);
        textureClient->SetRecycleCallback(SimpleTextureClientPool::WaitForCompositorRecycleCallback, this);
    }

    return textureClient;
}
SimpleTiledLayerTile
SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
                                     const nsIntPoint& aTileOrigin,
                                     const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile");
  static gfx::IntSize kTileSize(TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

  gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());

  // if this is true, we're using a separate buffer to do our drawing first
  bool doBufferedDrawing = true;
  bool fullPaint = false;

  RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();

  if (!textureClient) {
    NS_WARNING("TextureClient allocation failed");
    return SimpleTiledLayerTile();
  }

  if (!textureClient->Lock(OPEN_WRITE)) {
    NS_WARNING("TextureClient lock failed");
    return SimpleTiledLayerTile();
  }

  TextureClientSurface *textureClientSurf = textureClient->AsTextureClientSurface();
  if (!textureClientSurf) {
    doBufferedDrawing = false;
  }

  RefPtr<DrawTarget> drawTarget;

  nsRefPtr<gfxImageSurface> clientAsImageSurface;
  unsigned char *bufferData = nullptr;

  // these are set/updated differently based on doBufferedDrawing
  nsIntRect drawBounds;
  nsIntRegion drawRegion;
  nsIntRegion invalidateRegion;

  if (doBufferedDrawing) {
    // try to obtain the TextureClient as an ImageSurface, so that we can
    // access the pixels directly
    nsRefPtr<gfxASurface> asurf = textureClientSurf->GetAsSurface();
    clientAsImageSurface = asurf ? asurf->GetAsImageSurface() : nullptr;
    if (clientAsImageSurface) {
      int32_t bufferStride = clientAsImageSurface->Stride();

      if (!aTile.mCachedBuffer) {
        aTile.mCachedBuffer = SharedBuffer::Create(clientAsImageSurface->GetDataSize());
        fullPaint = true;
      }
      bufferData = (unsigned char*) aTile.mCachedBuffer->Data();

      drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
                                                                       kTileSize,
                                                                       bufferStride,
                                                                       tileFormat);

      if (fullPaint) {
        drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
        drawRegion = nsIntRegion(drawBounds);
      } else {
        drawBounds = aDirtyRegion.GetBounds();
        drawRegion = nsIntRegion(drawBounds);
        if (GetContentType() == gfxContentType::COLOR_ALPHA)
          drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
                                     drawBounds.width, drawBounds.height));
      }
    } else {
      // failed to obtain the client as an ImageSurface
      doBufferedDrawing = false;
    }
  }

  // this might get set above if we couldn't extract out a buffer
  if (!doBufferedDrawing) {
    drawTarget = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget();

    fullPaint = true;
    drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
    drawRegion = nsIntRegion(drawBounds);

    if (GetContentType() == gfxContentType::COLOR_ALPHA)
      drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
  }

  // do the drawing
  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  ctxt->Scale(mResolution, mResolution);
  ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));

  mCallback(mThebesLayer, ctxt,
            drawRegion,
            fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED?
            invalidateRegion,
            mCallbackData);

  ctxt = nullptr;
  drawTarget = nullptr;

  if (doBufferedDrawing) {
    memcpy(clientAsImageSurface->Data(), bufferData, clientAsImageSurface->GetDataSize());
    clientAsImageSurface = nullptr;
    bufferData = nullptr;
  }

  textureClient->Unlock();

  if (!mCompositableClient->AddTextureClient(textureClient)) {
    NS_WARNING("Failed to add tile TextureClient [simple]");
    return SimpleTiledLayerTile();
  }

  // aTile.mCachedBuffer was set earlier
  aTile.mTileBuffer = textureClient;
  aTile.mManager = mManager;
  aTile.mLastUpdate = TimeStamp::Now();

  return aTile;
}
TileClient
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
                                    const nsIntPoint& aTileOrigin,
                                    const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");

#ifdef GFX_TILEDLAYER_PREF_WARNINGS
  if (aDirtyRegion.IsComplex()) {
    printf_stderr("Complex region\n");
  }
#endif

  if (aTile.IsPlaceholderTile()) {
    aTile.SetLayerManager(mManager);
  }

  // Discard our front and backbuffers if our contents changed. In this case
  // the calling code will already have taken care of invalidating the entire
  // layer.
  if (HasFormatChanged()) {
    aTile.DiscardBackBuffer();
    aTile.DiscardFrontBuffer();
  }

  bool createdTextureClient = false;
  nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
  bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
  RefPtr<TextureClient> backBuffer =
    aTile.GetBackBuffer(offsetDirtyRegion,
                        mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
                        &createdTextureClient, !usingSinglePaintBuffer);

  if (!backBuffer->Lock(OPEN_READ_WRITE)) {
    NS_WARNING("Failed to lock tile TextureClient for updating.");
    aTile.DiscardFrontBuffer();
    return aTile;
  }

  // We must not keep a reference to the DrawTarget after it has been unlocked,
  // make sure these are null'd before unlocking as destruction of the context
  // may cause the target to be flushed.
  RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
  drawTarget->SetTransform(Matrix());

  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  if (usingSinglePaintBuffer) {
    // XXX Perhaps we should just copy the bounding rectangle here?
    RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
    nsIntRegionRectIterator it(aDirtyRegion);
    for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
      printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
                    dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
#endif
      gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
                         dirtyRect->y - aTileOrigin.y,
                         dirtyRect->width,
                         dirtyRect->height);
      drawRect.Scale(mResolution);

      gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
                            NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
                            drawRect.width,
                            drawRect.height);
      gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
      drawTarget->CopySurface(source, copyRect, copyTarget);

      // Mark the newly updated area as invalid in the front buffer
      aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
    }

    // The new buffer is now validated, remove the dirty region from it.
    aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
                           offsetDirtyRegion);
  } else {
    // Area of the full tile...
    nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

    // Intersect this area with the portion that's dirty.
    tileRegion = tileRegion.Intersect(aDirtyRegion);

    // Move invalid areas into layer space.
    aTile.mInvalidFront.MoveBy(aTileOrigin);
    aTile.mInvalidBack.MoveBy(aTileOrigin);

    // Add the area that's going to be redrawn to the invalid area of the
    // front region.
    aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion);

    // Add invalid areas of the backbuffer to the area to redraw.
    tileRegion.Or(tileRegion, aTile.mInvalidBack);

    // Move invalid areas back into tile space.
    aTile.mInvalidFront.MoveBy(-aTileOrigin);

    // This will be validated now.
    aTile.mInvalidBack.SetEmpty();

    nsIntRect bounds = tileRegion.GetBounds();
    bounds.ScaleRoundOut(mResolution, mResolution);
    bounds.MoveBy(-aTileOrigin);

    if (GetContentType() != gfxContentType::COLOR) {
      drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
    }

    ctxt->NewPath();
    ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
    ctxt->Scale(mResolution, mResolution);
    ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
    mCallback(mThebesLayer, ctxt,
              tileRegion.GetBounds(),
              DrawRegionClip::CLIP_NONE,
              nsIntRegion(), mCallbackData);

  }

#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
  DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
                   aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
#endif

  ctxt = nullptr;
  drawTarget = nullptr;

  backBuffer->Unlock();

  aTile.Flip();

  if (createdTextureClient) {
    if (!mCompositableClient->AddTextureClient(backBuffer)) {
      NS_WARNING("Failed to add tile TextureClient.");
      aTile.DiscardFrontBuffer();
      aTile.DiscardBackBuffer();
      return aTile;
    }
  }

  // Note, we don't call UpdatedTexture. The Updated function is called manually
  // by the TiledContentHost before composition.

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

  return aTile;
}