TEST(TiledLayerBuffer, TilesPlacement) {
    for (int firstY = -10; firstY < 10; ++firstY) {
        for (int firstX = -10; firstX < 10; ++firstX) {
            for (int height = 1; height < 10; ++height) {
                for (int width = 1; width < 10; ++width) {

                    const TilesPlacement p1 = TilesPlacement(firstX, firstY, width, height);
                    // Check that HasTile returns false with some positions that we know
                    // not to be in the rectangle of the TilesPlacement.
                    ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX - 1, 0)));
                    ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY - 1)));
                    ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX + width + 1,  0)));
                    ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY + height + 1)));

                    // Verify that all positions within the rect that defines the
                    // TilesPlacement map to indices between 0 and width*height.
                    for (int y = firstY; y < (firstY+height); ++y) {
                        for (int x = firstX; x < (firstX+width); ++x) {
                            ASSERT_TRUE(p1.HasTile(TileIntPoint(x,y)));
                            ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) >= 0);
                            ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) < width * height);
                        }
                    }

                    // XXX - This causes some versions of gcc to warn that it optimizes
                    // away the test, which gets caught in -WError in PGO builds.
                    // The lazy thing to do is to just comment this out since this specific
                    // test isn't critically important, but we should remove the warning instead.
                    // cf. bug 1179287
                    //
                    // Verify that indices map to positions that are within the rect that
                    // defines the TilesPlacement.
                    // for (int i = 0; i < width * height; ++i) {
                    //   ASSERT_TRUE(p1.TilePosition(i).x >= firstX);
                    //   ASSERT_TRUE(p1.TilePosition(i).x < firstX + width);
                    //   ASSERT_TRUE(p1.TilePosition(i).y >= firstY);
                    //   ASSERT_TRUE(p1.TilePosition(i).y < firstY + height);
                    // }

                }
            }
        }
    }
}
Example #2
0
bool
TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
                                    Compositor* aCompositor,
                                    ISurfaceAllocator* aAllocator)
{
  if (mResolution != aTiles.resolution()) {
    Clear();
  }
  MOZ_ASSERT(aAllocator);
  MOZ_ASSERT(aCompositor);
  if (!aAllocator || !aCompositor) {
    return false;
  }

  if (aTiles.resolution() == 0 || IsNaN(aTiles.resolution())) {
    // There are divisions by mResolution so this protects the compositor process
    // against malicious content processes and fuzzing.
    return false;
  }

  TilesPlacement oldTiles = mTiles;
  TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
                          aTiles.retainedWidth(), aTiles.retainedHeight());

  const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();

  nsTArray<TileHost> oldRetainedTiles;
  mRetainedTiles.SwapElements(oldRetainedTiles);
  mRetainedTiles.SetLength(tileDescriptors.Length());

  // Step 1, we need to unlock tiles that don't have an internal buffer after the
  // next frame where they are replaced.
  // Since we are about to replace the tiles' textures, we need to keep their locks
  // somewhere (in mPreviousSharedLock) until we composite the layer.
  for (size_t i = 0; i < oldRetainedTiles.Length(); ++i) {
    TileHost& tile = oldRetainedTiles[i];
    // It can happen that we still have a previous lock at this point,
    // if we changed a tile's front buffer (causing mSharedLock to
    // go into mPreviousSharedLock, and then did not composite that tile until
    // the next transaction, either because the tile is offscreen or because the
    // two transactions happened with no composition in between (over-production).
    tile.ReadUnlockPrevious();

    if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
      MOZ_ASSERT(tile.mSharedLock);
      const TileIntPoint tilePosition = oldTiles.TilePosition(i);
      if (newTiles.HasTile(tilePosition)) {
        // This tile still exist in the new buffer
        tile.mPreviousSharedLock = tile.mSharedLock;
        tile.mSharedLock = nullptr;
      } else {
        // This tile does not exist anymore in the new buffer because the size
        // changed.
        tile.ReadUnlock();
      }
    }

    // By now we should not have anything in mSharedLock.
    MOZ_ASSERT(!tile.mSharedLock);
  }

  // Step 2, move the tiles in mRetainedTiles at places that correspond to where
  // they should be with the new retained with and height rather than the
  // old one.
  for (size_t i = 0; i < tileDescriptors.Length(); i++) {
    const TileIntPoint tilePosition = newTiles.TilePosition(i);
    // First, get the already existing tiles to the right place in the array,
    // and use placeholders where there was no tiles.
    if (!oldTiles.HasTile(tilePosition)) {
      mRetainedTiles[i] = GetPlaceholderTile();
    } else {
      mRetainedTiles[i] = oldRetainedTiles[oldTiles.TileIndex(tilePosition)];
      // If we hit this assertion it means we probably mixed something up in the
      // logic that tries to reuse tiles on the compositor side. It is most likely
      // benign, but we are missing some fast paths so let's try to make it not happen.
      MOZ_ASSERT(tilePosition.x == mRetainedTiles[i].x &&
                 tilePosition.y == mRetainedTiles[i].y);
    }
  }

  // It is important to remove the duplicated reference to tiles before calling
  // TextureHost::PrepareTextureSource, etc. because depending on the textures
  // ref counts we may or may not get some of the fast paths.
  oldRetainedTiles.Clear();

  // Step 3, handle the texture updates and release the copy-on-write locks.
  for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
    const TileDescriptor& tileDesc = tileDescriptors[i];

    TileHost& tile = mRetainedTiles[i];

    switch (tileDesc.type()) {
      case TileDescriptor::TTexturedTileDescriptor: {
        const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();

        const TileLock& ipcLock = texturedDesc.sharedLock();
        if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
          return false;
        }

        RefPtr<TextureHost> textureHost = TextureHost::AsTextureHost(
          texturedDesc.textureParent()
        );

        RefPtr<TextureHost> textureOnWhite = nullptr;
        if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
          textureOnWhite = TextureHost::AsTextureHost(
            texturedDesc.textureOnWhite().get_PTextureParent()
          );
        }

        UseTileTexture(tile.mTextureHost,
                       tile.mTextureSource,
                       texturedDesc.updateRect(),
                       textureHost,
                       aCompositor);

        if (textureOnWhite) {
          UseTileTexture(tile.mTextureHostOnWhite,
                         tile.mTextureSourceOnWhite,
                         texturedDesc.updateRect(),
                         textureOnWhite,
                         aCompositor);
        } else {
          // We could still have component alpha textures from a previous frame.
          tile.mTextureSourceOnWhite = nullptr;
          tile.mTextureHostOnWhite = nullptr;
        }

        if (textureHost->HasInternalBuffer()) {
          // Now that we did the texture upload (in UseTileTexture), we can release
          // the lock.
          tile.ReadUnlock();
        }

        break;
      }
      default:
        NS_WARNING("Unrecognised tile descriptor type");
      case TileDescriptor::TPlaceholderTileDescriptor: {

        if (tile.mTextureHost) {
          tile.mTextureHost->UnbindTextureSource();
          tile.mTextureSource = nullptr;
        }
        if (tile.mTextureHostOnWhite) {
          tile.mTextureHostOnWhite->UnbindTextureSource();
          tile.mTextureSourceOnWhite = nullptr;
        }
        // we may have a previous lock, and are about to loose our reference to it.
        // It is okay to unlock it because we just destroyed the texture source.
        tile.ReadUnlockPrevious();
        tile = GetPlaceholderTile();

        break;
      }
    }
    TileIntPoint tilePosition = newTiles.TilePosition(i);
    tile.x = tilePosition.x;
    tile.y = tilePosition.y;
  }

  mTiles = newTiles;
  mValidRegion = aTiles.validRegion();
  mResolution = aTiles.resolution();
  mFrameResolution = CSSToParentLayerScale2D(aTiles.frameXResolution(),
                                             aTiles.frameYResolution());

  return true;
}