void Canvas2DLayerChromium::paintContentsIfDirty(const CCOcclusionTracker* /* occlusion */) { TRACE_EVENT("Canvas2DLayerChromium::paintContentsIfDirty", this, 0); if (!drawsContent()) return; if (m_useDoubleBuffering && layerTreeHost()) { TextureManager* textureManager = layerTreeHost()->contentsTextureManager(); if (m_frontTexture) m_frontTexture->setTextureManager(textureManager); else m_frontTexture = ManagedTexture::create(textureManager); m_frontTexture->reserve(m_size, GraphicsContext3D::RGBA); } if (!needsDisplay()) return; m_needsDisplay = false; bool success = m_context->makeContextCurrent(); ASSERT_UNUSED(success, success); m_contextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR; if (m_contextLost) return; if (m_canvas) { TRACE_EVENT("SkCanvas::flush", m_canvas, 0); m_canvas->flush(); } TRACE_EVENT("GraphicsContext3D::flush", m_context, 0); m_context->flush(); }
bool VideoLayerChromium::reserveTextures(const VideoFrameChromium* frame, GC3Denum textureFormat) { ASSERT(layerTreeHost()); ASSERT(frame); ASSERT(textureFormat != GraphicsContext3D::INVALID_VALUE); int maxTextureSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize; for (unsigned plane = 0; plane < frame->planes(); plane++) { IntSize requiredTextureSize = frame->requiredTextureSize(plane); // If the renderer cannot handle this large of a texture, return false. // FIXME: Remove this test when tiled layers are implemented. if (requiredTextureSize.isZero() || requiredTextureSize.width() > maxTextureSize || requiredTextureSize.height() > maxTextureSize) return false; if (!m_textures[plane].m_texture) return false; if (m_textures[plane].m_texture->size() != requiredTextureSize) m_textures[plane].m_visibleSize = computeVisibleSize(frame, plane); m_textures[plane].m_texture->reserve(requiredTextureSize, textureFormat); } return true; }
void TextureLayerChromium::setRateLimitContext(bool rateLimit) { if (!rateLimit && m_rateLimitContext && m_client && layerTreeHost()) layerTreeHost()->stopRateLimiter(m_client->context()); m_rateLimitContext = rateLimit; }
void Canvas2DLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect) { LayerChromium::setNeedsDisplayRect(dirtyRect); if (layerTreeHost()) layerTreeHost()->startRateLimiter(m_context.get()); }
void WebGLLayerChromium::setDrawingBuffer(DrawingBuffer* drawingBuffer) { bool drawingBufferChanged = (m_drawingBuffer != drawingBuffer); // The GraphicsContext3D used by the layer is the context associated with // the drawing buffer. If the drawing buffer is changing, make sure // to stop the rate limiter on the old context, not the new context from the // new drawing buffer. GraphicsContext3D* context3D = context(); if (layerTreeHost() && drawingBufferChanged && context3D) layerTreeHost()->stopRateLimiter(context3D); m_drawingBuffer = drawingBuffer; if (!m_drawingBuffer) return; unsigned int textureId = m_drawingBuffer->platformColorBuffer(); if (textureId != m_textureId || drawingBufferChanged) { m_textureChanged = true; m_textureUpdated = true; } m_textureId = textureId; GraphicsContext3D::Attributes attributes = context()->getContextAttributes(); m_hasAlpha = attributes.alpha; m_premultipliedAlpha = attributes.premultipliedAlpha; m_contextLost = context()->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR; }
void TextureLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect) { LayerChromium::setNeedsDisplayRect(dirtyRect); if (m_rateLimitContext && m_client && layerTreeHost()) layerTreeHost()->startRateLimiter(m_client->context()); }
GraphicsContext3D* WebGLLayerChromium::layerRendererContext() { // FIXME: In the threaded case, paintRenderedResultsToCanvas must be // refactored to be asynchronous. Currently this is unimplemented. if (!layerTreeHost() || CCProxy::hasImplThread()) return 0; return layerTreeHost()->context(); }
void WebGLLayerChromium::contentChanged() { m_textureUpdated = true; // If WebGL commands are issued outside of a the animation callbacks, then use // call rateLimitOffscreenContextCHROMIUM() to keep the context from getting too far ahead. if (layerTreeHost()) layerTreeHost()->startRateLimiter(context()); }
TextureLayerChromium::~TextureLayerChromium() { if (layerTreeHost()) { if (m_textureId) layerTreeHost()->acquireLayerTextures(); if (m_rateLimitContext && m_client) layerTreeHost()->stopRateLimiter(m_client->context()); } }
void TextureLayerChromium::setTextureId(unsigned id) { if (m_textureId == id) return; if (m_textureId && layerTreeHost()) layerTreeHost()->acquireLayerTextures(); m_textureId = id; setNeedsCommit(); }
void WebGLLayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect) { LayerChromium::setNeedsDisplayRect(dirtyRect); // If WebGL commands are issued outside of a the animation callbacks, then use // call rateLimitOffscreenContextCHROMIUM() to keep the context from getting too far ahead. if (layerTreeHost()) layerTreeHost()->startRateLimiter(context()); }
void TiledLayerChromium::updateTileSizeAndTilingOption() { if (!m_tiler) return; const IntSize tileSize(min(defaultTileSize, contentBounds().width()), min(defaultTileSize, contentBounds().height())); // Tile if both dimensions large, or any one dimension large and the other // extends into a second tile. This heuristic allows for long skinny layers // (e.g. scrollbars) that are Nx1 tiles to minimize wasted texture space. const bool anyDimensionLarge = contentBounds().width() > maxUntiledSize || contentBounds().height() > maxUntiledSize; const bool anyDimensionOneTile = contentBounds().width() <= defaultTileSize || contentBounds().height() <= defaultTileSize; const bool autoTiled = anyDimensionLarge && !anyDimensionOneTile; bool isTiled; if (m_tilingOption == AlwaysTile) isTiled = true; else if (m_tilingOption == NeverTile) isTiled = false; else isTiled = autoTiled; IntSize requestedSize = isTiled ? tileSize : contentBounds(); const int maxSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize; IntSize clampedSize = requestedSize.shrunkTo(IntSize(maxSize, maxSize)); m_tiler->setTileSize(clampedSize); }
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::setLayerTreeHost(CCLayerTreeHost* host) { if (host && host != layerTreeHost()) { 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->managedTexture()->setTextureManager(host->contentsTextureManager()); } } LayerChromium::setLayerTreeHost(host); }
void VideoLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) { if (host && layerTreeHost() != host) { for (size_t i = 0; i < 3; ++i) { m_textures[i].m_visibleSize = IntSize(); m_textures[i].m_texture = ManagedTexture::create(host->contentsTextureManager()); } } LayerChromium::setLayerTreeHost(host); }
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); } } }
TextureManager* TiledLayerChromium::textureManager() const { if (!layerTreeHost()) return 0; return layerTreeHost()->contentsTextureManager(); }
WebGLLayerChromium::~WebGLLayerChromium() { if (context() && layerTreeHost()) layerTreeHost()->stopRateLimiter(context()); }
Canvas2DLayerChromium::~Canvas2DLayerChromium() { if (m_context && layerTreeHost()) layerTreeHost()->stopRateLimiter(m_context.get()); }
void TextureLayerChromium::setLayerTreeHost(CCLayerTreeHost* host) { if (m_textureId && layerTreeHost() && host != layerTreeHost()) layerTreeHost()->acquireLayerTextures(); LayerChromium::setLayerTreeHost(host); }
void TextureLayerChromium::willModifyTexture() { if (layerTreeHost()) layerTreeHost()->acquireLayerTextures(); }
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); } } }