void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer, CCTextureUpdater& updater) { TRACE_EVENT("CCLayerTreeHost::updateLayers", this, 0); if (!rootLayer->renderSurface()) rootLayer->createRenderSurface(); rootLayer->renderSurface()->setContentRect(IntRect(IntPoint(0, 0), deviceViewportSize())); IntRect rootClipRect(IntPoint(), deviceViewportSize()); rootLayer->setClipRect(rootClipRect); LayerList updateList; updateList.append(rootLayer); RenderSurfaceChromium* rootRenderSurface = rootLayer->renderSurface(); rootRenderSurface->clearLayerList(); { TRACE_EVENT("CCLayerTreeHost::updateLayers::calcDrawEtc", this, 0); WebTransformationMatrix identityMatrix; WebTransformationMatrix deviceScaleTransform; deviceScaleTransform.scale(m_deviceScaleFactor); CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, deviceScaleTransform, identityMatrix, updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize); FloatRect rootScissorRect(FloatPoint(0, 0), viewportSize()); CCLayerTreeHostCommon::calculateVisibleAndScissorRects(updateList, rootScissorRect); } // Reset partial texture update requests. m_partialTextureUpdateRequests = 0; reserveTextures(updateList); paintLayerContents(updateList, PaintVisible, updater); if (!m_triggerIdlePaints) return; size_t preferredLimitBytes = m_contentsTextureManager->preferredMemoryLimitBytes(); size_t maxLimitBytes = m_contentsTextureManager->maxMemoryLimitBytes(); m_contentsTextureManager->reduceMemoryToLimit(preferredLimitBytes); if (m_contentsTextureManager->currentMemoryUseBytes() >= preferredLimitBytes) return; // Idle painting should fail when we hit the preferred memory limit, // otherwise it will always push us towards the maximum limit. m_contentsTextureManager->setMaxMemoryLimitBytes(preferredLimitBytes); // The second (idle) paint will be a no-op in layers where painting already occured above. paintLayerContents(updateList, PaintIdle, updater); m_contentsTextureManager->setMaxMemoryLimitBytes(maxLimitBytes); for (size_t i = 0; i < updateList.size(); ++i) updateList[i]->clearRenderSurface(); }
void CCLayerTreeHost::prioritizeTextures(const LayerList& updateList) { // Use BackToFront since it's cheap and this isn't order-dependent. typedef CCLayerIterator<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, CCLayerIteratorActions::BackToFront> CCLayerIteratorType; m_contentsTextureManager->clearPriorities(); CCPriorityCalculator calculator; CCLayerIteratorType end = CCLayerIteratorType::end(&updateList); for (CCLayerIteratorType it = CCLayerIteratorType::begin(&updateList); it != end; ++it) { if (it.representsItself()) it->setTexturePriorities(calculator); else if (it.representsTargetRenderSurface()) { if (it->maskLayer()) it->maskLayer()->setTexturePriorities(calculator); if (it->replicaLayer() && it->replicaLayer()->maskLayer()) it->replicaLayer()->maskLayer()->setTexturePriorities(calculator); } } size_t readbackBytes = 0; size_t maxBackgroundTextureBytes = 0; size_t contentsTextureBytes = 0; // Start iteration at 1 to skip the root surface as it does not have a texture cost. for (size_t i = 1; i < updateList.size(); ++i) { LayerChromium* renderSurfaceLayer = updateList[i].get(); RenderSurfaceChromium* renderSurface = renderSurfaceLayer->renderSurface(); size_t bytes = TextureManager::memoryUseBytes(renderSurface->contentRect().size(), GraphicsContext3D::RGBA); contentsTextureBytes += bytes; if (renderSurface->backgroundFilters().isEmpty()) continue; if (bytes > maxBackgroundTextureBytes) maxBackgroundTextureBytes = bytes; if (!readbackBytes) readbackBytes = TextureManager::memoryUseBytes(m_deviceViewportSize, GraphicsContext3D::RGBA); } size_t renderSurfacesBytes = readbackBytes + maxBackgroundTextureBytes + contentsTextureBytes; m_contentsTextureManager->prioritizeTextures(renderSurfacesBytes); }
void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer, CCTextureUpdater& updater) { TRACE_EVENT0("cc", "CCLayerTreeHost::updateLayers"); if (!rootLayer->renderSurface()) rootLayer->createRenderSurface(); rootLayer->renderSurface()->setContentRect(IntRect(IntPoint(0, 0), deviceViewportSize())); IntRect rootClipRect(IntPoint(), deviceViewportSize()); rootLayer->setClipRect(rootClipRect); LayerList updateList; updateList.append(rootLayer); RenderSurfaceChromium* rootRenderSurface = rootLayer->renderSurface(); rootRenderSurface->clearLayerList(); { TRACE_EVENT0("cc", "CCLayerTreeHost::updateLayers::calcDrawEtc"); WebTransformationMatrix identityMatrix; WebTransformationMatrix deviceScaleTransform; deviceScaleTransform.scale(m_deviceScaleFactor); CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, rootLayer, deviceScaleTransform, identityMatrix, updateList, rootRenderSurface->layerList(), layerRendererCapabilities().maxTextureSize); FloatRect rootScissorRect(FloatPoint(0, 0), viewportSize()); CCLayerTreeHostCommon::calculateVisibleAndScissorRects(updateList, rootScissorRect); } // Reset partial texture update requests. m_partialTextureUpdateRequests = 0; prioritizeTextures(updateList); bool needMoreUpdates = paintLayerContents(updateList, updater); if (m_triggerIdleUpdates && needMoreUpdates) setNeedsCommit(); for (size_t i = 0; i < updateList.size(); ++i) updateList[i]->clearRenderSurface(); }
size_t CCLayerTreeHost::calculateMemoryForRenderSurfaces(const LayerList& updateList) { size_t readbackBytes = 0; size_t maxBackgroundTextureBytes = 0; size_t contentsTextureBytes = 0; // Start iteration at 1 to skip the root surface as it does not have a texture cost. for (size_t i = 1; i < updateList.size(); ++i) { LayerChromium* renderSurfaceLayer = updateList[i].get(); RenderSurfaceChromium* renderSurface = renderSurfaceLayer->renderSurface(); size_t bytes = CCTexture::memorySizeBytes(renderSurface->contentRect().size(), GraphicsContext3D::RGBA); contentsTextureBytes += bytes; if (renderSurfaceLayer->backgroundFilters().isEmpty()) continue; if (bytes > maxBackgroundTextureBytes) maxBackgroundTextureBytes = bytes; if (!readbackBytes) readbackBytes = CCTexture::memorySizeBytes(m_deviceViewportSize, GraphicsContext3D::RGBA); } return readbackBytes + maxBackgroundTextureBytes + contentsTextureBytes; }
// Recursively walks the layer tree starting at the given node and computes all the // necessary transformations, scissor rectangles, render surfaces, etc. void LayerRendererChromium::updatePropertiesAndRenderSurfaces(CCLayerImpl* layer, const TransformationMatrix& parentMatrix, LayerList& renderSurfaceLayerList, LayerList& layerList) { // Compute the new matrix transformation that will be applied to this layer and // all its children. It's important to remember that the layer's position // is the position of the layer's anchor point. Also, the coordinate system used // assumes that the origin is at the lower left even though the coordinates the browser // gives us for the layers are for the upper left corner. The Y flip happens via // the orthographic projection applied at render time. // The transformation chain for the layer is (using the Matrix x Vector order): // M = M[p] * Tr[l] * M[l] * Tr[c] // Where M[p] is the parent matrix passed down to the function // Tr[l] is the translation matrix locating the layer's anchor point // Tr[c] is the translation offset between the anchor point and the center of the layer // M[l] is the layer's matrix (applied at the anchor point) // This transform creates a coordinate system whose origin is the center of the layer. // Note that the final matrix used by the shader for the layer is P * M * S . This final product // is computed in drawTexturedQuad(). // Where: P is the projection matrix // M is the layer's matrix computed above // S is the scale adjustment (to scale up to the layer size) IntSize bounds = layer->bounds(); FloatPoint anchorPoint = layer->anchorPoint(); FloatPoint position = layer->position(); // Offset between anchor point and the center of the quad. float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width(); float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height(); TransformationMatrix layerLocalTransform; // LT = Tr[l] layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ()); // LT = Tr[l] * M[l] layerLocalTransform.multiply(layer->transform()); // LT = Tr[l] * M[l] * Tr[c] layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ()); TransformationMatrix combinedTransform = parentMatrix; combinedTransform = combinedTransform.multiply(layerLocalTransform); FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height()); IntRect transformedLayerRect; // The layer and its descendants render on a new RenderSurface if any of // these conditions hold: // 1. The layer clips its descendants and its transform is not a simple translation. // 2. If the layer has opacity != 1 and does not have a preserves-3d transform style. // 3. The layer uses a mask // 4. The layer has a replica (used for reflections) // 5. The layer doesn't preserve-3d but is the child of a layer which does. // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening // out its children. The opacity value of the children layers is multiplied by the opacity // of their parent. bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform); bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D(); bool useSurfaceForMasking = layer->maskLayer(); bool useSurfaceForReflection = layer->replicaLayer(); bool useSurfaceForFlatDescendants = layer->parent() && layer->parent()->preserves3D() && !layer->preserves3D() && layer->descendantsDrawsContent(); if (useSurfaceForMasking || useSurfaceForReflection || useSurfaceForFlatDescendants || ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawsContent())) { RenderSurfaceChromium* renderSurface = layer->renderSurface(); if (!renderSurface) renderSurface = layer->createRenderSurface(); // The origin of the new surface is the upper left corner of the layer. TransformationMatrix drawTransform; drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0); layer->setDrawTransform(drawTransform); transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height()); // Layer's opacity will be applied when drawing the render surface. renderSurface->m_drawOpacity = layer->opacity(); if (layer->parent() && layer->parent()->preserves3D()) renderSurface->m_drawOpacity *= layer->parent()->drawOpacity(); layer->setDrawOpacity(1); TransformationMatrix layerOriginTransform = combinedTransform; layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0); renderSurface->m_originTransform = layerOriginTransform; layer->setScissorRect(IntRect()); // The render surface scissor rect is the scissor rect that needs to // be applied before drawing the render surface onto its containing // surface and is therefore expressed in the parent's coordinate system. renderSurface->m_scissorRect = layer->parent() ? layer->parent()->scissorRect() : layer->scissorRect(); renderSurface->m_layerList.clear(); if (layer->maskLayer()) { renderSurface->m_maskLayer = layer->maskLayer(); layer->maskLayer()->setTargetRenderSurface(renderSurface); } else renderSurface->m_maskLayer = 0; if (layer->replicaLayer() && layer->replicaLayer()->maskLayer()) layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface); renderSurfaceLayerList.append(layer); } else { // DT = M[p] * LT layer->setDrawTransform(combinedTransform); transformedLayerRect = enclosingIntRect(layer->drawTransform().mapRect(layerRect)); layer->setDrawOpacity(layer->opacity()); if (layer->parent()) { if (layer->parent()->preserves3D()) layer->setDrawOpacity(layer->drawOpacity() * layer->parent()->drawOpacity()); // Layers inherit the scissor rect from their parent. layer->setScissorRect(layer->parent()->scissorRect()); layer->setTargetRenderSurface(layer->parent()->targetRenderSurface()); } if (layer != m_rootCCLayerImpl.get()) layer->clearRenderSurface(); if (layer->masksToBounds()) { IntRect scissor = transformedLayerRect; if (!layer->scissorRect().isEmpty()) scissor.intersect(layer->scissorRect()); layer->setScissorRect(scissor); } } if (layer->renderSurface()) layer->setTargetRenderSurface(layer->renderSurface()); else { ASSERT(layer->parent()); layer->setTargetRenderSurface(layer->parent()->targetRenderSurface()); } // drawableContentRect() is always stored in the coordinate system of the // RenderSurface the layer draws into. if (layer->drawsContent()) layer->setDrawableContentRect(transformedLayerRect); else layer->setDrawableContentRect(IntRect()); TransformationMatrix sublayerMatrix = layer->drawTransform(); // Flatten to 2D if the layer doesn't preserve 3D. if (!layer->preserves3D()) { sublayerMatrix.setM13(0); sublayerMatrix.setM23(0); sublayerMatrix.setM31(0); sublayerMatrix.setM32(0); sublayerMatrix.setM33(1); sublayerMatrix.setM34(0); sublayerMatrix.setM43(0); } // Apply the sublayer transform at the center of the layer. sublayerMatrix.multiply(layer->sublayerTransform()); // The origin of the children is the top left corner of the layer, not the // center. The matrix passed down to the children is therefore: // M[s] = M * Tr[-center] sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0); LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->m_layerList : layerList); descendants.append(layer); unsigned thisLayerIndex = descendants.size() - 1; for (size_t i = 0; i < layer->children().size(); ++i) { CCLayerImpl* child = layer->children()[i].get(); updatePropertiesAndRenderSurfaces(child, sublayerMatrix, renderSurfaceLayerList, descendants); if (child->renderSurface()) { RenderSurfaceChromium* childRenderSurface = child->renderSurface(); IntRect drawableContentRect = layer->drawableContentRect(); drawableContentRect.unite(enclosingIntRect(childRenderSurface->drawableContentRect())); layer->setDrawableContentRect(drawableContentRect); descendants.append(child); } else { IntRect drawableContentRect = layer->drawableContentRect(); drawableContentRect.unite(child->drawableContentRect()); layer->setDrawableContentRect(drawableContentRect); } } if (layer->masksToBounds() || useSurfaceForMasking) { IntRect drawableContentRect = layer->drawableContentRect(); drawableContentRect.intersect(transformedLayerRect); layer->setDrawableContentRect(drawableContentRect); } if (layer->renderSurface() && layer != m_rootCCLayerImpl.get()) { RenderSurfaceChromium* renderSurface = layer->renderSurface(); renderSurface->m_contentRect = layer->drawableContentRect(); FloatPoint surfaceCenter = renderSurface->contentRectCenter(); // Restrict the RenderSurface size to the portion that's visible. FloatSize centerOffsetDueToClipping; // Don't clip if the layer is reflected as the reflection shouldn't be // clipped. if (!layer->replicaLayer()) { if (!layer->scissorRect().isEmpty()) renderSurface->m_contentRect.intersect(layer->scissorRect()); FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter(); centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter; } // The RenderSurface backing texture cannot exceed the maximum supported // texture size. renderSurface->m_contentRect.setWidth(std::min(renderSurface->m_contentRect.width(), m_maxTextureSize)); renderSurface->m_contentRect.setHeight(std::min(renderSurface->m_contentRect.height(), m_maxTextureSize)); if (renderSurface->m_contentRect.isEmpty()) renderSurface->m_layerList.clear(); // Since the layer starts a new render surface we need to adjust its // scissor rect to be expressed in the new surface's coordinate system. layer->setScissorRect(layer->drawableContentRect()); // Adjust the origin of the transform to be the center of the render surface. renderSurface->m_drawTransform = renderSurface->m_originTransform; renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0); // Compute the transformation matrix used to draw the replica of the render // surface. if (layer->replicaLayer()) { renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform; renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0); renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform()); renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0); } } // If preserves-3d then sort all the descendants in 3D so that they can be // drawn from back to front. If the preserves-3d property is also set on the parent then // skip the sorting as the parent will sort all the descendants anyway. if (layer->preserves3D() && (!layer->parent() || !layer->parent()->preserves3D())) m_layerSorter.sort(&descendants.at(thisLayerIndex), descendants.end()); }