void BitmapSkPictureCanvasLayerTextureUpdater::Texture::updateRect(GraphicsContext3D* context, TextureAllocator* allocator, const IntRect& sourceRect, const IntRect& destRect) { texture()->bindTexture(context, allocator); ASSERT(m_pixelData.get()); textureUpdater()->updateTextureRect(context, texture()->format(), destRect, m_pixelData.get()); m_pixelData.clear(); }
void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) { LayerChromium::setLayerTreeHost(host); if (m_tiler || !host) return; createTextureUpdater(host); m_textureFormat = host->layerRendererCapabilities().bestTextureFormat; m_textureOrientation = textureUpdater()->orientation(); m_sampledTexelFormat = textureUpdater()->sampledTexelFormat(m_textureFormat); m_tiler = CCLayerTilingData::create( IntSize(defaultTileSize, defaultTileSize), isRootLayer() ? CCLayerTilingData::NoBorderTexels : CCLayerTilingData::HasBorderTexels); }
void BitmapSkPictureCanvasLayerTextureUpdater::Texture::prepareRect(const IntRect& sourceRect) { size_t bufferSize = TextureManager::memoryUseBytes(sourceRect.size(), texture()->format()); m_pixelData = adoptArrayPtr(new uint8_t[bufferSize]); OwnPtr<SkCanvas> canvas = adoptPtr(new skia::PlatformCanvas(sourceRect.width(), sourceRect.height(), false, m_pixelData.get())); textureUpdater()->paintContentsRect(canvas.get(), sourceRect); }
UpdatableTile* TiledLayerChromium::createTile(int i, int j) { RefPtr<UpdatableTile> tile = adoptRef(new UpdatableTile(textureUpdater()->createTexture(textureManager()))); m_tiler->addTile(tile, i, j); tile->m_dirtyRect = m_tiler->tileRect(tile.get()); return tile.get(); }
UpdatableTile* TiledLayerChromium::createTile(int i, int j) { OwnPtr<UpdatableTile> tile(UpdatableTile::create(textureUpdater()->createTexture(textureManager()))); UpdatableTile* addedTile = tile.get(); m_tiler->addTile(tile.release(), i, j); addedTile->m_dirtyRect = m_tiler->tileRect(addedTile); return addedTile; }
void TiledLayerChromium::updateCompositorResources(GraphicsContext3D* context) { // Painting could cause compositing to get turned off, which may cause the tiler to become invalidated mid-update. if (m_skipsDraw || m_updateRect.isEmpty() || !m_tiler->numTiles()) return; int left, top, right, bottom; m_tiler->contentRectToTileIndices(m_updateRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); else if (!tile->dirty()) continue; // Calculate page-space rectangle to copy from. IntRect sourceRect = m_tiler->tileContentRect(tile); const IntPoint anchor = sourceRect.location(); sourceRect.intersect(m_tiler->layerRectToContentRect(tile->m_dirtyLayerRect)); // Paint rect not guaranteed to line up on tile boundaries, so // make sure that sourceRect doesn't extend outside of it. sourceRect.intersect(m_paintRect); if (sourceRect.isEmpty()) continue; ASSERT(tile->texture()->isReserved()); // Calculate tile-space rectangle to upload into. IntRect destRect(IntPoint(sourceRect.x() - anchor.x(), sourceRect.y() - anchor.y()), sourceRect.size()); if (destRect.x() < 0) CRASH(); if (destRect.y() < 0) CRASH(); // Offset from paint rectangle to this tile's dirty rectangle. IntPoint paintOffset(sourceRect.x() - m_paintRect.x(), sourceRect.y() - m_paintRect.y()); if (paintOffset.x() < 0) CRASH(); if (paintOffset.y() < 0) CRASH(); if (paintOffset.x() + destRect.width() > m_paintRect.width()) CRASH(); if (paintOffset.y() + destRect.height() > m_paintRect.height()) CRASH(); tile->texture()->bindTexture(context); const GC3Dint filter = m_tiler->hasBorderTexels() ? GraphicsContext3D::LINEAR : GraphicsContext3D::NEAREST; GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, filter)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, filter)); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0)); textureUpdater()->updateTextureRect(context, tile->texture(), sourceRect, destRect); tile->clearDirty(); } } }
void TiledLayerChromium::prepareToUpdate(const IntRect& contentRect) { ASSERT(m_tiler); m_skipsDraw = false; if (contentRect.isEmpty()) { m_updateRect = IntRect(); return; } // Invalidate old tiles that were previously used but aren't in use this // frame so that they can get reused for new tiles. invalidateTiles(contentRect); m_tiler->growLayerToContain(contentRect); if (!m_tiler->numTiles()) { m_updateRect = IntRect(); return; } // Create tiles as needed, expanding a dirty rect to contain all // the dirty regions currently being drawn. IntRect dirtyLayerRect; int left, top, right, bottom; m_tiler->contentRectToTileIndices(contentRect, left, top, right, bottom); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); if (!tile->texture()->isValid(m_tiler->tileSize(), m_textureFormat)) tile->m_dirtyLayerRect = m_tiler->tileLayerRect(tile); if (!tile->texture()->reserve(m_tiler->tileSize(), m_textureFormat)) { m_skipsDraw = true; cleanupResources(); return; } dirtyLayerRect.unite(tile->m_dirtyLayerRect); } } // Due to borders, when the paint rect is extended to tile boundaries, it // may end up overlapping more tiles than the original content rect. Record // that original rect so we don't upload more tiles than necessary. m_updateRect = contentRect; m_paintRect = m_tiler->layerRectToContentRect(dirtyLayerRect); if (dirtyLayerRect.isEmpty()) return; textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels()); }
void BitmapSkPictureCanvasLayerTextureUpdater::Texture::prepareRect(const IntRect& sourceRect, CCRenderingStats& stats) { m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, sourceRect.width(), sourceRect.height()); m_bitmap.allocPixels(); m_bitmap.setIsOpaque(m_textureUpdater->layerIsOpaque()); SkDevice device(m_bitmap); SkCanvas canvas(&device); double paintBeginTime = monotonicallyIncreasingTime(); textureUpdater()->paintContentsRect(&canvas, sourceRect, stats); stats.totalPaintTimeInSeconds += monotonicallyIncreasingTime() - paintBeginTime; }
void ContentLayerChromium::createTextureUpdaterIfNeeded() { if (m_textureUpdater) return; if (layerTreeHost()->settings().acceleratePainting) m_textureUpdater = FrameBufferSkPictureCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_client)); else if (CCSettings::perTilePaintingEnabled()) m_textureUpdater = BitmapSkPictureCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_client)); else m_textureUpdater = BitmapCanvasLayerTextureUpdater::create(ContentLayerPainter::create(m_client)); m_textureUpdater->setOpaque(opaque()); GC3Denum textureFormat = layerTreeHost()->rendererCapabilities().bestTextureFormat; setTextureFormat(textureFormat); setSampledTexelFormat(textureUpdater()->sampledTexelFormat(textureFormat)); }
void TiledLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) { if (host == layerTreeHost()) return; if (layerTreeHost()) cleanupResources(); LayerChromium::setLayerTreeHost(host); if (!host) return; createTextureUpdater(host); setTextureFormat(host->layerRendererCapabilities().bestTextureFormat); m_sampledTexelFormat = textureUpdater()->sampledTexelFormat(m_textureFormat); }
void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom, const CCOcclusionTracker* occlusion) { createTextureUpdaterIfNeeded(); // Create tiles as needed, expanding a dirty rect to contain all // the dirty regions currently being drawn. All dirty tiles that are to be painted // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if // invalidateRect is invoked during prepareToUpdate we don't lose the request. IntRect dirtyLayerRect; for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); // When not idle painting, if the visible region of the tile is occluded, don't reserve a texture or mark it for update. // If any part of the tile is visible, then we need to paint it so the tile is pushed to the impl thread. // This will also avoid painting the tile in the next loop, below. if (!idle && occlusion) { IntRect visibleTileRect = intersection(m_tiler->tileBounds(i, j), visibleLayerRect()); if (occlusion->occluded(this, visibleTileRect)) continue; } // FIXME: Decide if partial update should be allowed based on cost // of update. https://bugs.webkit.org/show_bug.cgi?id=77376 if (tileOnlyNeedsPartialUpdate(tile) && layerTreeHost() && layerTreeHost()->requestPartialTextureUpdate()) tile->m_partialUpdate = true; else if (tileNeedsBufferedUpdate(tile) && layerTreeHost()) layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal()); if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) { // Sets the dirty rect to a full-sized tile with border texels. tile->m_dirtyRect = m_tiler->tileRect(tile); } if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) { m_skipsIdlePaint = true; if (!idle) { // If the background covers the viewport, always draw this // layer so that checkerboarded tiles will still draw. if (!backgroundCoversViewport()) m_skipsDraw = true; m_tiler->reset(); m_paintRect = IntRect(); m_requestedUpdateTilesRect = IntRect(); } return; } dirtyLayerRect.unite(tile->m_dirtyRect); tile->copyAndClearDirty(); } } m_paintRect = dirtyLayerRect; if (dirtyLayerRect.isEmpty()) return; // Due to borders, when the paint rect is extended to tile boundaries, it // may end up overlapping more tiles than the original content rect. Record // the original tiles so we don't upload more tiles than necessary. if (!m_paintRect.isEmpty()) m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1); // Calling prepareToUpdate() calls into WebKit to paint, which may have the side // effect of disabling compositing, which causes our reference to the texture updater to be deleted. // However, we can't free the memory backing the GraphicsContext until the paint finishes, // so we grab a local reference here to hold the updater alive until the paint completes. RefPtr<LayerTextureUpdater> protector(textureUpdater()); IntRect paintedOpaqueRect; textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &paintedOpaqueRect); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); // Tiles are created before prepareToUpdate() is called. if (!tile) CRASH(); IntRect tileRect = m_tiler->tileBounds(i, j); // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect if the tile isn't culled. const IntRect& dirtyRect = tile->m_updateRect; if (dirtyRect.isEmpty()) continue; // Save what was painted opaque in the tile. Keep the old area if the paint didn't touch it, and didn't paint some // other part of the tile opaque. IntRect tilePaintedRect = intersection(tileRect, m_paintRect); IntRect tilePaintedOpaqueRect = intersection(tileRect, paintedOpaqueRect); if (!tilePaintedRect.isEmpty()) { IntRect paintInsideTileOpaqueRect = intersection(tile->opaqueRect(), tilePaintedRect); bool paintInsideTileOpaqueRectIsNonOpaque = !tilePaintedOpaqueRect.contains(paintInsideTileOpaqueRect); bool opaquePaintNotInsideTileOpaqueRect = !tilePaintedOpaqueRect.isEmpty() && !tile->opaqueRect().contains(tilePaintedOpaqueRect); if (paintInsideTileOpaqueRectIsNonOpaque || opaquePaintNotInsideTileOpaqueRect) tile->setOpaqueRect(tilePaintedOpaqueRect); } // sourceRect starts as a full-sized tile with border texels included. IntRect sourceRect = m_tiler->tileRect(tile); sourceRect.intersect(dirtyRect); // Paint rect not guaranteed to line up on tile boundaries, so // make sure that sourceRect doesn't extend outside of it. sourceRect.intersect(m_paintRect); tile->m_updateRect = sourceRect; if (sourceRect.isEmpty()) continue; tile->texture()->prepareRect(sourceRect); } } }
void BitmapCanvasLayerTextureUpdater::Texture::updateRect(CCResourceProvider* resourceProvider, const IntRect& sourceRect, const IntRect& destRect) { textureUpdater()->updateTextureRect(resourceProvider, texture(), sourceRect, destRect); }
void FrameBufferSkPictureCanvasLayerTextureUpdater::Texture::updateRect(CCGraphicsContext* context, TextureAllocator* allocator, const IntRect& sourceRect, const IntRect& destRect) { textureUpdater()->updateTextureRect(context, allocator, texture(), sourceRect, destRect); }
void BitmapCanvasLayerTextureUpdater::Texture::updateRect(GraphicsContext3D* context, TextureAllocator* allocator, const IntRect& sourceRect, const IntRect& destRect) { textureUpdater()->updateTextureRect(context, allocator, texture(), sourceRect, destRect); }
void TiledLayerChromium::prepareToUpdateTiles(bool idle, int left, int top, int right, int bottom) { // Reset m_updateRect for all tiles. for (CCLayerTilingData::TileMap::const_iterator iter = m_tiler->tiles().begin(); iter != m_tiler->tiles().end(); ++iter) { UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second.get()); tile->m_updateRect = IntRect(); } // Create tiles as needed, expanding a dirty rect to contain all // the dirty regions currently being drawn. All dirty tiles that are to be painted // get their m_updateRect set to m_dirtyRect and m_dirtyRect cleared. This way if // invalidateRect is invoked during prepareToUpdate we don't lose the request. IntRect dirtyLayerRect; for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); if (!tile) tile = createTile(i, j); // Do post commit deletion of current texture when partial texture // updates are not used. if (tile->isDirty() && layerTreeHost() && !layerTreeHost()->settings().partialTextureUpdates) layerTreeHost()->deleteTextureAfterCommit(tile->managedTexture()->steal()); if (!tile->managedTexture()->isValid(m_tiler->tileSize(), m_textureFormat)) tile->m_dirtyRect = m_tiler->tileRect(tile); if (!tile->managedTexture()->reserve(m_tiler->tileSize(), m_textureFormat)) { m_skipsIdlePaint = true; if (!idle) { m_skipsDraw = true; cleanupResources(); } return; } dirtyLayerRect.unite(tile->m_dirtyRect); tile->copyAndClearDirty(); } } m_paintRect = dirtyLayerRect; if (dirtyLayerRect.isEmpty()) return; // Due to borders, when the paint rect is extended to tile boundaries, it // may end up overlapping more tiles than the original content rect. Record // the original tiles so we don't upload more tiles than necessary. if (!m_paintRect.isEmpty()) m_requestedUpdateTilesRect = IntRect(left, top, right - left + 1, bottom - top + 1); // Calling prepareToUpdate() calls into WebKit to paint, which may have the side // effect of disabling compositing, which causes our reference to the texture updater to be deleted. // However, we can't free the memory backing the GraphicsContext until the paint finishes, // so we grab a local reference here to hold the updater alive until the paint completes. RefPtr<LayerTextureUpdater> protector(textureUpdater()); IntRect opaqueRect; // FIXME: unused. remove this and store in the layer to pass to impl for draw culling textureUpdater()->prepareToUpdate(m_paintRect, m_tiler->tileSize(), m_tiler->hasBorderTexels(), contentsScale(), &opaqueRect); for (int j = top; j <= bottom; ++j) { for (int i = left; i <= right; ++i) { UpdatableTile* tile = tileAt(i, j); // Tiles are created before prepareToUpdate() is called. if (!tile) CRASH(); // Use m_updateRect as copyAndClearDirty above moved the existing dirty rect to m_updateRect. const IntRect& dirtyRect = tile->m_updateRect; if (dirtyRect.isEmpty()) continue; IntRect sourceRect = m_tiler->tileRect(tile); sourceRect.intersect(dirtyRect); // Paint rect not guaranteed to line up on tile boundaries, so // make sure that sourceRect doesn't extend outside of it. sourceRect.intersect(m_paintRect); tile->m_updateRect = sourceRect; if (sourceRect.isEmpty()) continue; tile->texture()->prepareRect(sourceRect); } } }