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::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(); }
// 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()); }
void LayerRendererChromium::updateLayers(LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); if (!rootDrawLayer->renderSurface()) rootDrawLayer->createRenderSurface(); ASSERT(rootDrawLayer->renderSurface()); rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size()); IntRect rootScissorRect(m_viewportVisibleRect); // The scissorRect should not include the scroll offset. rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y()); rootDrawLayer->setScissorRect(rootScissorRect); m_defaultRenderSurface = rootDrawLayer->renderSurface(); renderSurfaceLayerList.append(rootDrawLayer); TransformationMatrix identityMatrix; m_defaultRenderSurface->m_layerList.clear(); // Unfortunately, updatePropertiesAndRenderSurfaces() currently both updates the layers and updates the draw state // (transforms, etc). It'd be nicer if operations on the presentation layers happened later, but the draw // transforms are needed by large layers to determine visibility. Tiling will fix this by eliminating the // concept of a large content layer. updatePropertiesAndRenderSurfaces(rootDrawLayer, identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList); #ifndef NDEBUG s_inPaintLayerContents = true; #endif paintLayerContents(renderSurfaceLayerList); #ifndef NDEBUG s_inPaintLayerContents = false; #endif // FIXME: Before updateCompositorResourcesRecursive, when the compositor runs in // its own thread, and when the copyTexImage2D bug is fixed, insert // a glWaitLatch(Compositor->Offscreen) on all child contexts here instead // of after updateCompositorResourcesRecursive. // Also uncomment the glSetLatch(Compositor->Offscreen) code in addChildContext. // if (hardwareCompositing() && m_contextSupportsLatch) { // // For each child context: // // glWaitLatch(Compositor->Offscreen); // ChildContextMap::iterator i = m_childContexts.begin(); // for (; i != m_childContexts.end(); ++i) { // Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); // GC3Duint childToParentLatchId, parentToChildLatchId; // ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); // ext->waitLatchCHROMIUM(parentToChildLatchId); // } // } updateCompositorResourcesRecursive(m_rootLayer.get()); // After updateCompositorResourcesRecursive, set/wait latches for all child // contexts. This will prevent the compositor from using any of the child // parent textures while WebGL commands are executing from javascript *and* // while the final parent texture is being blit'd. copyTexImage2D // uses the parent texture as a temporary resolve buffer, so that's why the // waitLatch is below, to block the compositor from using the parent texture // until the next WebGL SwapBuffers (or copyTextureToParentTexture for // Canvas2D). if (hardwareCompositing() && m_contextSupportsLatch) { m_childContextsWereCopied = true; // For each child context: // glSetLatch(Offscreen->Compositor); // glWaitLatch(Compositor->Offscreen); ChildContextMap::iterator i = m_childContexts.begin(); for (; i != m_childContexts.end(); ++i) { Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); GC3Duint childToParentLatchId, parentToChildLatchId; ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); ext->getChildToParentLatchCHROMIUM(&childToParentLatchId); ext->setLatchCHROMIUM(childToParentLatchId); ext->waitLatchCHROMIUM(parentToChildLatchId); } } }