FrameBuilder.cpp revision fc29f7acd1352efa97269b5f3856eb879d5cfd53
122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/* 25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Copyright (C) 2016 The Android Open Source Project 35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * 45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Licensed under the Apache License, Version 2.0 (the "License"); 55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * you may not use this file except in compliance with the License. 65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * You may obtain a copy of the License at 75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * 85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * http://www.apache.org/licenses/LICENSE-2.0 937b74a387bb3993387029859c2d9d051c41c724eStephen Hines * 1037b74a387bb3993387029859c2d9d051c41c724eStephen Hines * Unless required by applicable law or agreed to in writing, software 1137b74a387bb3993387029859c2d9d051c41c724eStephen Hines * distributed under the License is distributed on an "AS IS" BASIS, 1237b74a387bb3993387029859c2d9d051c41c724eStephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines * See the License for the specific language governing permissions and 140dea6bc96bb52346737966839ac68644f7939f58Stephen Hines * limitations under the License. 150dea6bc96bb52346737966839ac68644f7939f58Stephen Hines */ 160dea6bc96bb52346737966839ac68644f7939f58Stephen Hines 175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "FrameBuilder.h" 1822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "DeferredLayerUpdater.h" 2022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include "LayerUpdateQueue.h" 2187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines#include "RenderNode.h" 225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "VectorDrawable.h" 235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "renderstate/OffscreenBufferPool.h" 245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "hwui/Canvas.h" 255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "utils/FatVector.h" 265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "utils/PaintUtils.h" 275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "utils/TraceUtils.h" 2837b74a387bb3993387029859c2d9d051c41c724eStephen Hines 2937b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <SkPathOps.h> 302bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar#include <utils/TypeHelpers.h> 316f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 326f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesnamespace android { 336f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesnamespace uirenderer { 346f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 356f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen HinesFrameBuilder::FrameBuilder(const SkRect& clip, 366f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines uint32_t viewportWidth, uint32_t viewportHeight, 372bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar const LightGeometry& lightGeometry, Caches& caches) 382bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar : mStdAllocator(mAllocator) 392bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar , mLayerBuilders(mStdAllocator) 402bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar , mLayerStack(mStdAllocator) 412bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar , mCanvasState(*this) 422bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar , mCaches(caches) 436f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines , mLightRadius(lightGeometry.radius) 442bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar , mDrawFbo0(true) { 452bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar 462bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar // Prepare to defer Fbo0 472bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip)); 482bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar mLayerBuilders.push_back(fbo0); 492bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar mLayerStack.push_back(0); 500dea6bc96bb52346737966839ac68644f7939f58Stephen Hines mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 516f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, 526f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines lightGeometry.center); 536f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines} 546f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 5587f34658dec9097d987d254a990ea7f311bfc95fStephen HinesFrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, 5687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines const LightGeometry& lightGeometry, Caches& caches) 5787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines : mStdAllocator(mAllocator) 5887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines , mLayerBuilders(mStdAllocator) 596f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines , mLayerStack(mStdAllocator) 606f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines , mCanvasState(*this) 616f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines , mCaches(caches) 626f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines , mLightRadius(lightGeometry.radius) 630dea6bc96bb52346737966839ac68644f7939f58Stephen Hines , mDrawFbo0(false) { 640dea6bc96bb52346737966839ac68644f7939f58Stephen Hines // TODO: remove, with each layer on its own save stack 650dea6bc96bb52346737966839ac68644f7939f58Stephen Hines 660dea6bc96bb52346737966839ac68644f7939f58Stephen Hines // Prepare to defer Fbo0 (which will be empty) 670dea6bc96bb52346737966839ac68644f7939f58Stephen Hines auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1)); 680dea6bc96bb52346737966839ac68644f7939f58Stephen Hines mLayerBuilders.push_back(fbo0); 6937b74a387bb3993387029859c2d9d051c41c724eStephen Hines mLayerStack.push_back(0); 70affc150dc44fab1911775a49636d0ce85333b634Zonr Chang mCanvasState.initializeSaveStack(1, 1, 71affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 0, 0, 1, 1, 72affc150dc44fab1911775a49636d0ce85333b634Zonr Chang lightGeometry.center); 735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 7437b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferLayers(layers); 755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 7637b74a387bb3993387029859c2d9d051c41c724eStephen Hines 775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid FrameBuilder::deferLayers(const LayerUpdateQueue& layers) { 7837b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Render all layers to be updated, in order. Defer in reverse order, so that they'll be 795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse) 8037b74a387bb3993387029859c2d9d051c41c724eStephen Hines for (int i = layers.entries().size() - 1; i >= 0; i--) { 815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao RenderNode* layerNode = layers.entries()[i].renderNode.get(); 8237b74a387bb3993387029859c2d9d051c41c724eStephen Hines // only schedule repaint if node still on layer - possible it may have been 83affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // removed during a dropped frame, but layers may still remain scheduled so 8437b74a387bb3993387029859c2d9d051c41c724eStephen Hines // as not to lose info on what portion is damaged 85affc150dc44fab1911775a49636d0ce85333b634Zonr Chang OffscreenBuffer* layer = layerNode->getLayer(); 8637b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (CC_LIKELY(layer)) { 87affc150dc44fab1911775a49636d0ce85333b634Zonr Chang ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", 8837b74a387bb3993387029859c2d9d051c41c724eStephen Hines layerNode->getName(), layerNode->getWidth(), layerNode->getHeight()); 89affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 9037b74a387bb3993387029859c2d9d051c41c724eStephen Hines Rect layerDamage = layers.entries()[i].damage; 91affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // TODO: ensure layer damage can't be larger than layer 9237b74a387bb3993387029859c2d9d051c41c724eStephen Hines layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight); 93affc150dc44fab1911775a49636d0ce85333b634Zonr Chang layerNode->computeOrdering(); 9437b74a387bb3993387029859c2d9d051c41c724eStephen Hines 95affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // map current light center into RenderNode's coordinate space 9622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); 9722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao layer->inverseTransformInWindow.mapPoint3d(lightCenter); 9837b74a387bb3993387029859c2d9d051c41c724eStephen Hines 9922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, 10037b74a387bb3993387029859c2d9d051c41c724eStephen Hines layerDamage, lightCenter, nullptr, layerNode); 101affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 10237b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (layerNode->getDisplayList()) { 103affc150dc44fab1911775a49636d0ce85333b634Zonr Chang deferNodeOps(*layerNode); 10437b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 105affc150dc44fab1911775a49636d0ce85333b634Zonr Chang restoreForLayer(); 10637b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 107affc150dc44fab1911775a49636d0ce85333b634Zonr Chang } 10837b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 109affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 11037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::deferRenderNode(RenderNode& renderNode) { 111affc150dc44fab1911775a49636d0ce85333b634Zonr Chang renderNode.computeOrdering(); 11237b74a387bb3993387029859c2d9d051c41c724eStephen Hines 113affc150dc44fab1911775a49636d0ce85333b634Zonr Chang mCanvasState.save(SaveFlags::MatrixClip); 11437b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferNodePropsAndOps(renderNode); 115affc150dc44fab1911775a49636d0ce85333b634Zonr Chang mCanvasState.restore(); 11637b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 11737b74a387bb3993387029859c2d9d051c41c724eStephen Hines 11837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode) { 119affc150dc44fab1911775a49636d0ce85333b634Zonr Chang renderNode.computeOrdering(); 12004c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines 12104c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines mCanvasState.save(SaveFlags::MatrixClip); 12204c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines mCanvasState.translate(tx, ty); 12304c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, 12404c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines SkClipOp::kIntersect); 12504c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hines deferNodePropsAndOps(renderNode); 12637b74a387bb3993387029859c2d9d051c41c724eStephen Hines mCanvasState.restore(); 127affc150dc44fab1911775a49636d0ce85333b634Zonr Chang} 12837b74a387bb3993387029859c2d9d051c41c724eStephen Hines 129affc150dc44fab1911775a49636d0ce85333b634Zonr Changstatic Rect nodeBounds(RenderNode& node) { 130affc150dc44fab1911775a49636d0ce85333b634Zonr Chang auto& props = node.properties(); 131affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return Rect(props.getLeft(), props.getTop(), 132affc150dc44fab1911775a49636d0ce85333b634Zonr Chang props.getRight(), props.getBottom()); 13337b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 134affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 13537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes, 13687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines const Rect& contentDrawBounds) { 13737b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (nodes.size() < 1) return; 138affc150dc44fab1911775a49636d0ce85333b634Zonr Chang if (nodes.size() == 1) { 13937b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (!nodes[0]->nothingToDraw()) { 140affc150dc44fab1911775a49636d0ce85333b634Zonr Chang deferRenderNode(*nodes[0]); 14137b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 142affc150dc44fab1911775a49636d0ce85333b634Zonr Chang return; 14337b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 144affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // It there are multiple render nodes, they are laid out as follows: 14537b74a387bb3993387029859c2d9d051c41c724eStephen Hines // #0 - backdrop (content + caption) 146affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop) 14737b74a387bb3993387029859c2d9d051c41c724eStephen Hines // #2 - additional overlay nodes 148affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Usually the backdrop cannot be seen since it will be entirely covered by the content. While 14937b74a387bb3993387029859c2d9d051c41c724eStephen Hines // resizing however it might become partially visible. The following render loop will crop the 15087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines // backdrop against the content and draw the remaining part of it. It will then draw the content 15137b74a387bb3993387029859c2d9d051c41c724eStephen Hines // cropped to the backdrop (since that indicates a shrinking of the window). 152affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // 15337b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Additional nodes will be drawn on top with no particular clipping semantics. 154affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 15537b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Usually the contents bounds should be mContentDrawBounds - however - we will 156affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // move it towards the fixed edge to give it a more stable appearance (for the moment). 15737b74a387bb3993387029859c2d9d051c41c724eStephen Hines // If there is no content bounds we ignore the layering as stated above and start with 2. 158affc150dc44fab1911775a49636d0ce85333b634Zonr Chang 15937b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Backdrop bounds in render target space 160affc150dc44fab1911775a49636d0ce85333b634Zonr Chang const Rect backdrop = nodeBounds(*nodes[0]); 16137b74a387bb3993387029859c2d9d051c41c724eStephen Hines 162affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Bounds that content will fill in render target space (note content node bounds may be bigger) 16337b74a387bb3993387029859c2d9d051c41c724eStephen Hines Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight()); 164affc150dc44fab1911775a49636d0ce85333b634Zonr Chang content.translate(backdrop.left, backdrop.top); 16537b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) { 166affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Content doesn't entirely overlap backdrop, so fill around content (right/bottom) 16737b74a387bb3993387029859c2d9d051c41c724eStephen Hines 168affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to 16937b74a387bb3993387029859c2d9d051c41c724eStephen Hines // also fill left/top. Currently, both 2up and freeform position content at the top/left of 170affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // the backdrop, so this isn't necessary. 17137b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (content.right < backdrop.right) { 172affc150dc44fab1911775a49636d0ce85333b634Zonr Chang // draw backdrop to right side of content 17337b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferRenderNode(0, 0, Rect(content.right, backdrop.top, 174affc150dc44fab1911775a49636d0ce85333b634Zonr Chang backdrop.right, backdrop.bottom), *nodes[0]); 17522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao } 17637b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (content.bottom < backdrop.bottom) { 17722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao // draw backdrop to bottom of content 17837b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill 17922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao deferRenderNode(0, 0, Rect(content.left, content.bottom, 18022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao content.right, backdrop.bottom), *nodes[0]); 18137b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 18222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao } 18337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 18422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao if (!nodes[1]->nothingToDraw()) { 18522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao if (!backdrop.isEmpty()) { 18637b74a387bb3993387029859c2d9d051c41c724eStephen Hines // content node translation to catch up with backdrop 18722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao float dx = contentDrawBounds.left - backdrop.left; 18837b74a387bb3993387029859c2d9d051c41c724eStephen Hines float dy = contentDrawBounds.top - backdrop.top; 18922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 19022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao Rect contentLocalClip = backdrop; 19137b74a387bb3993387029859c2d9d051c41c724eStephen Hines contentLocalClip.translate(dx, dy); 19237b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]); 19337b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 19422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao deferRenderNode(*nodes[1]); 19537b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 19622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao } 19722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 19837b74a387bb3993387029859c2d9d051c41c724eStephen Hines // remaining overlay nodes, simply defer 19937b74a387bb3993387029859c2d9d051c41c724eStephen Hines for (size_t index = 2; index < nodes.size(); index++) { 20037b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (!nodes[index]->nothingToDraw()) { 20122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao deferRenderNode(*nodes[index]); 20237b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 203d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao } 20437b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 20537b74a387bb3993387029859c2d9d051c41c724eStephen Hines 20637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::onViewportInitialized() {} 207d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao 20837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} 209d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao 21037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::deferNodePropsAndOps(RenderNode& node) { 211d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao const RenderProperties& properties = node.properties(); 21237b74a387bb3993387029859c2d9d051c41c724eStephen Hines const Outline& outline = properties.getOutline(); 213d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao if (properties.getAlpha() <= 0 21437b74a387bb3993387029859c2d9d051c41c724eStephen Hines || (outline.getShouldClip() && outline.isEmpty()) 215d0fbbb227051be16931a1aa9b4a7722ac039c698Shih-wei Liao || properties.getScaleX() == 0 21637b74a387bb3993387029859c2d9d051c41c724eStephen Hines || properties.getScaleY() == 0) { 21722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao return; // rejected 21837b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 2196f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 22037b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (properties.getLeft() != 0 || properties.getTop() != 0) { 2216f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines mCanvasState.translate(properties.getLeft(), properties.getTop()); 22237b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 2236f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines if (properties.getStaticMatrix()) { 22437b74a387bb3993387029859c2d9d051c41c724eStephen Hines mCanvasState.concatMatrix(*properties.getStaticMatrix()); 2256f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } else if (properties.getAnimationMatrix()) { 22637b74a387bb3993387029859c2d9d051c41c724eStephen Hines mCanvasState.concatMatrix(*properties.getAnimationMatrix()); 2276f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } 22837b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (properties.hasTransformMatrix()) { 2296f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines if (properties.isTransformTranslateOnly()) { 230f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY()); 23137b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 232f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines mCanvasState.concatMatrix(*properties.getTransformMatrix()); 23337b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 234f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines } 23537b74a387bb3993387029859c2d9d051c41c724eStephen Hines 23687f34658dec9097d987d254a990ea7f311bfc95fStephen Hines const int width = properties.getWidth(); 23737b74a387bb3993387029859c2d9d051c41c724eStephen Hines const int height = properties.getHeight(); 23887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines 23987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines Rect saveLayerBounds; // will be set to non-empty if saveLayer needed 24037b74a387bb3993387029859c2d9d051c41c724eStephen Hines const bool isLayer = properties.effectiveLayerType() != LayerType::None; 24187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines int clipFlags = properties.getClippingFlags(); 24237b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (properties.getAlpha() < 1) { 24387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (isLayer) { 2440dea6bc96bb52346737966839ac68644f7939f58Stephen Hines clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer 24537b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 2460dea6bc96bb52346737966839ac68644f7939f58Stephen Hines if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { 24737b74a387bb3993387029859c2d9d051c41c724eStephen Hines // simply scale rendering content's alpha 2480dea6bc96bb52346737966839ac68644f7939f58Stephen Hines mCanvasState.scaleAlpha(properties.getAlpha()); 24987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } else { 25037b74a387bb3993387029859c2d9d051c41c724eStephen Hines // schedule saveLayer by initializing saveLayerBounds 25187f34658dec9097d987d254a990ea7f311bfc95fStephen Hines saveLayerBounds.set(0, 0, width, height); 25237b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (clipFlags) { 25387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines properties.getClippingRectForFlags(clipFlags, &saveLayerBounds); 2542bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar clipFlags = 0; // all clipping done by savelayer 2552bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar } 2562bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar } 2572bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar 2582bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { 2592bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar // pretend alpha always causes savelayer to warn about 2602bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar // performance problem affecting old versions 2612bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height); 2622bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar } 2636f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } 2642bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar if (clipFlags) { 2656f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines Rect clipRect; 2660dea6bc96bb52346737966839ac68644f7939f58Stephen Hines properties.getClippingRectForFlags(clipFlags, &clipRect); 2670dea6bc96bb52346737966839ac68644f7939f58Stephen Hines mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, 26837b74a387bb3993387029859c2d9d051c41c724eStephen Hines SkClipOp::kIntersect); 2690dea6bc96bb52346737966839ac68644f7939f58Stephen Hines } 2700dea6bc96bb52346737966839ac68644f7939f58Stephen Hines 2710dea6bc96bb52346737966839ac68644f7939f58Stephen Hines if (properties.getRevealClip().willClip()) { 27237b74a387bb3993387029859c2d9d051c41c724eStephen Hines Rect bounds; 2730dea6bc96bb52346737966839ac68644f7939f58Stephen Hines properties.getRevealClip().getBounds(&bounds); 2740dea6bc96bb52346737966839ac68644f7939f58Stephen Hines mCanvasState.setClippingRoundRect(mAllocator, 2750dea6bc96bb52346737966839ac68644f7939f58Stephen Hines bounds, properties.getRevealClip().getRadius()); 2762bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar } else if (properties.getOutline().willClip()) { 27737b74a387bb3993387029859c2d9d051c41c724eStephen Hines mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); 27837b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 2790dea6bc96bb52346737966839ac68644f7939f58Stephen Hines 2806f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() 2816f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines || (properties.getClipToBounds() 28237b74a387bb3993387029859c2d9d051c41c724eStephen Hines && mCanvasState.quickRejectConservative(0, 0, width, height)); 2836f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines if (!quickRejected) { 2846f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) 28537b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (node.getLayer()) { 28637b74a387bb3993387029859c2d9d051c41c724eStephen Hines // HW layer 28737b74a387bb3993387029859c2d9d051c41c724eStephen Hines LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(node); 2886f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); 28987f34658dec9097d987d254a990ea7f311bfc95fStephen Hines if (bakedOpState) { 29087f34658dec9097d987d254a990ea7f311bfc95fStephen Hines // Node's layer already deferred, schedule it to render into parent layer 29137b74a387bb3993387029859c2d9d051c41c724eStephen Hines currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); 29287f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 29387f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) { 29437b74a387bb3993387029859c2d9d051c41c724eStephen Hines // draw DisplayList contents within temporary, since persisted layer could not be used. 29537b74a387bb3993387029859c2d9d051c41c724eStephen Hines // (temp layers are clipped to viewport, since they don't persist offscreen content) 29637b74a387bb3993387029859c2d9d051c41c724eStephen Hines SkPaint saveLayerPaint; 29787f34658dec9097d987d254a990ea7f311bfc95fStephen Hines saveLayerPaint.setAlpha(properties.getAlpha()); 2980dea6bc96bb52346737966839ac68644f7939f58Stephen Hines deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>( 2990dea6bc96bb52346737966839ac68644f7939f58Stephen Hines saveLayerBounds, 30037b74a387bb3993387029859c2d9d051c41c724eStephen Hines Matrix4::identity(), 3010dea6bc96bb52346737966839ac68644f7939f58Stephen Hines nullptr, // no record-time clip - need only respect defer-time one 30237b74a387bb3993387029859c2d9d051c41c724eStephen Hines &saveLayerPaint)); 30337b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferNodeOps(node); 30437b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>()); 30537b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 3060dea6bc96bb52346737966839ac68644f7939f58Stephen Hines deferNodeOps(node); 30737b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 30837b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 30937b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 31037b74a387bb3993387029859c2d9d051c41c724eStephen Hines 3110dea6bc96bb52346737966839ac68644f7939f58Stephen Hinestypedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair; 3126f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 31337b74a387bb3993387029859c2d9d051c41c724eStephen Hinestemplate <typename V> 3146f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hinesstatic void buildZSortedChildList(V* zTranslatedNodes, 31537b74a387bb3993387029859c2d9d051c41c724eStephen Hines const DisplayList& displayList, const DisplayList::Chunk& chunk) { 3166f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines if (chunk.beginChildIndex == chunk.endChildIndex) return; 31737b74a387bb3993387029859c2d9d051c41c724eStephen Hines 3186f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { 3196f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines RenderNodeOp* childOp = displayList.getChildren()[i]; 32037b74a387bb3993387029859c2d9d051c41c724eStephen Hines RenderNode* child = childOp->renderNode; 3216f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines float childZ = child->properties().getZ(); 3226f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines 32337b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { 32437b74a387bb3993387029859c2d9d051c41c724eStephen Hines zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); 32537b74a387bb3993387029859c2d9d051c41c724eStephen Hines childOp->skipInOrderDraw = true; 3266f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } else if (!child->properties().getProjectBackwards()) { 3270dea6bc96bb52346737966839ac68644f7939f58Stephen Hines // regular, in order drawing DisplayList 32837b74a387bb3993387029859c2d9d051c41c724eStephen Hines childOp->skipInOrderDraw = false; 3290dea6bc96bb52346737966839ac68644f7939f58Stephen Hines } 3300dea6bc96bb52346737966839ac68644f7939f58Stephen Hines } 3310dea6bc96bb52346737966839ac68644f7939f58Stephen Hines 33237b74a387bb3993387029859c2d9d051c41c724eStephen Hines // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) 3330dea6bc96bb52346737966839ac68644f7939f58Stephen Hines std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); 33437b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 33537b74a387bb3993387029859c2d9d051c41c724eStephen Hines 336affc150dc44fab1911775a49636d0ce85333b634Zonr Changtemplate <typename V> 33737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesstatic size_t findNonNegativeIndex(const V& zTranslatedNodes) { 3385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao for (size_t i = 0; i < zTranslatedNodes.size(); i++) { 339affc150dc44fab1911775a49636d0ce85333b634Zonr Chang if (zTranslatedNodes[i].key >= 0.0f) return i; 34022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao } 34137b74a387bb3993387029859c2d9d051c41c724eStephen Hines return zTranslatedNodes.size(); 34237b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 34337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 34404c59f3b00def22b7c75f5a490c323cec58a7c71Stephen Hinestemplate <typename V> 34537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, 34637b74a387bb3993387029859c2d9d051c41c724eStephen Hines const V& zTranslatedNodes) { 34737b74a387bb3993387029859c2d9d051c41c724eStephen Hines const int size = zTranslatedNodes.size(); 34837b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (size == 0 34937b74a387bb3993387029859c2d9d051c41c724eStephen Hines || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) 35037b74a387bb3993387029859c2d9d051c41c724eStephen Hines || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { 35137b74a387bb3993387029859c2d9d051c41c724eStephen Hines // no 3d children to draw 35237b74a387bb3993387029859c2d9d051c41c724eStephen Hines return; 35337b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 35437b74a387bb3993387029859c2d9d051c41c724eStephen Hines 35537b74a387bb3993387029859c2d9d051c41c724eStephen Hines /** 35637b74a387bb3993387029859c2d9d051c41c724eStephen Hines * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters 35737b74a387bb3993387029859c2d9d051c41c724eStephen Hines * with very similar Z heights to draw together. 35837b74a387bb3993387029859c2d9d051c41c724eStephen Hines * 35937b74a387bb3993387029859c2d9d051c41c724eStephen Hines * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are 36037b74a387bb3993387029859c2d9d051c41c724eStephen Hines * underneath both, and neither's shadow is drawn on top of the other. 36137b74a387bb3993387029859c2d9d051c41c724eStephen Hines */ 36237b74a387bb3993387029859c2d9d051c41c724eStephen Hines const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); 36337b74a387bb3993387029859c2d9d051c41c724eStephen Hines size_t drawIndex, shadowIndex, endIndex; 36437b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (mode == ChildrenSelectMode::Negative) { 36537b74a387bb3993387029859c2d9d051c41c724eStephen Hines drawIndex = 0; 36637b74a387bb3993387029859c2d9d051c41c724eStephen Hines endIndex = nonNegativeIndex; 36737b74a387bb3993387029859c2d9d051c41c724eStephen Hines shadowIndex = endIndex; // draw no shadows 36837b74a387bb3993387029859c2d9d051c41c724eStephen Hines } else { 36937b74a387bb3993387029859c2d9d051c41c724eStephen Hines drawIndex = nonNegativeIndex; 37037b74a387bb3993387029859c2d9d051c41c724eStephen Hines endIndex = size; 37137b74a387bb3993387029859c2d9d051c41c724eStephen Hines shadowIndex = drawIndex; // potentially draw shadow for each pos Z child 37237b74a387bb3993387029859c2d9d051c41c724eStephen Hines } 37337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 37437b74a387bb3993387029859c2d9d051c41c724eStephen Hines float lastCasterZ = 0.0f; 37537b74a387bb3993387029859c2d9d051c41c724eStephen Hines while (shadowIndex < endIndex || drawIndex < endIndex) { 37637b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (shadowIndex < endIndex) { 37737b74a387bb3993387029859c2d9d051c41c724eStephen Hines const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; 37837b74a387bb3993387029859c2d9d051c41c724eStephen Hines const float casterZ = zTranslatedNodes[shadowIndex].key; 37937b74a387bb3993387029859c2d9d051c41c724eStephen Hines // attempt to render the shadow if the caster about to be drawn is its caster, 38037b74a387bb3993387029859c2d9d051c41c724eStephen Hines // OR if its caster's Z value is similar to the previous potential caster 38137b74a387bb3993387029859c2d9d051c41c724eStephen Hines if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { 38237b74a387bb3993387029859c2d9d051c41c724eStephen Hines deferShadow(reorderClip, *casterNodeOp); 38337b74a387bb3993387029859c2d9d051c41c724eStephen Hines 3840dea6bc96bb52346737966839ac68644f7939f58Stephen Hines lastCasterZ = casterZ; // must do this even if current caster not casting a shadow 3850dea6bc96bb52346737966839ac68644f7939f58Stephen Hines shadowIndex++; 3866f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines continue; 3876f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines } 38887f34658dec9097d987d254a990ea7f311bfc95fStephen Hines } 38937b74a387bb3993387029859c2d9d051c41c724eStephen Hines 3902bf3f881f79c4d883f379e63725e788c310739a3Pirama Arumuga Nainar const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; 3916f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines deferRenderNodeOpImpl(*childOp); 3926f75755c9204b1d8817ae5a65a2f7e5af0ec3f70Stephen Hines drawIndex++; 3930dea6bc96bb52346737966839ac68644f7939f58Stephen Hines } 3945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao} 3955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao 39637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) { 3975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao auto& node = *casterNodeOp.renderNode; 39837b74a387bb3993387029859c2d9d051c41c724eStephen Hines auto& properties = node.properties(); 399 400 if (properties.getAlpha() <= 0.0f 401 || properties.getOutline().getAlpha() <= 0.0f 402 || !properties.getOutline().getPath() 403 || properties.getScaleX() == 0 404 || properties.getScaleY() == 0) { 405 // no shadow to draw 406 return; 407 } 408 409 const SkPath* casterOutlinePath = properties.getOutline().getPath(); 410 const SkPath* revealClipPath = properties.getRevealClip().getPath(); 411 if (revealClipPath && revealClipPath->isEmpty()) return; 412 413 float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha(); 414 415 // holds temporary SkPath to store the result of intersections 416 SkPath* frameAllocatedPath = nullptr; 417 const SkPath* casterPath = casterOutlinePath; 418 419 // intersect the shadow-casting path with the reveal, if present 420 if (revealClipPath) { 421 frameAllocatedPath = createFrameAllocatedPath(); 422 423 Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath); 424 casterPath = frameAllocatedPath; 425 } 426 427 // intersect the shadow-casting path with the clipBounds, if present 428 if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) { 429 if (!frameAllocatedPath) { 430 frameAllocatedPath = createFrameAllocatedPath(); 431 } 432 Rect clipBounds; 433 properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); 434 SkPath clipBoundsPath; 435 clipBoundsPath.addRect(clipBounds.left, clipBounds.top, 436 clipBounds.right, clipBounds.bottom); 437 438 Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath); 439 casterPath = frameAllocatedPath; 440 } 441 442 // apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk 443 int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); 444 mCanvasState.writableSnapshot()->applyClip(reorderClip, 445 *mCanvasState.currentSnapshot()->transform); 446 if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) { 447 Matrix4 shadowMatrixXY(casterNodeOp.localMatrix); 448 Matrix4 shadowMatrixZ(casterNodeOp.localMatrix); 449 node.applyViewPropertyTransforms(shadowMatrixXY, false); 450 node.applyViewPropertyTransforms(shadowMatrixZ, true); 451 452 sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask( 453 mCanvasState.currentTransform(), 454 mCanvasState.getLocalClipBounds(), 455 casterAlpha >= 1.0f, 456 casterPath, 457 &shadowMatrixXY, &shadowMatrixZ, 458 mCanvasState.currentSnapshot()->getRelativeLightCenter(), 459 mLightRadius); 460 ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha); 461 BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct( 462 mAllocator, *mCanvasState.writableSnapshot(), shadowOp); 463 if (CC_LIKELY(bakedOpState)) { 464 currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow); 465 } 466 } 467 mCanvasState.restoreToCount(restoreTo); 468} 469 470void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { 471 int count = mCanvasState.save(SaveFlags::MatrixClip); 472 const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); 473 474 SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy 475 if (projectionReceiverOutline) { 476 // transform the mask for this projector into render target space 477 // TODO: consider combining both transforms by stashing transform instead of applying 478 SkMatrix skCurrentTransform; 479 mCanvasState.currentTransform()->copyTo(skCurrentTransform); 480 projectionReceiverOutline->transform( 481 skCurrentTransform, 482 &transformedMaskPath); 483 mCanvasState.setProjectionPathMask(&transformedMaskPath); 484 } 485 486 for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { 487 RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; 488 RenderNode& childNode = *childOp->renderNode; 489 490 // Draw child if it has content, but ignore state in childOp - matrix already applied to 491 // transformFromCompositingAncestor, and record-time clip is ignored when projecting 492 if (!childNode.nothingToDraw()) { 493 int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); 494 495 // Apply transform between ancestor and projected descendant 496 mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); 497 498 deferNodePropsAndOps(childNode); 499 500 mCanvasState.restoreToCount(restoreTo); 501 } 502 } 503 mCanvasState.restoreToCount(count); 504} 505 506/** 507 * Used to define a list of lambdas referencing private FrameBuilder::onXX::defer() methods. 508 * 509 * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. 510 * E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&) 511 */ 512#define OP_RECEIVER(Type) \ 513 [](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); }, 514void FrameBuilder::deferNodeOps(const RenderNode& renderNode) { 515 typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op); 516 static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER); 517 518 // can't be null, since DL=null node rejection happens before deferNodePropsAndOps 519 const DisplayList& displayList = *(renderNode.getDisplayList()); 520 for (auto& chunk : displayList.getChunks()) { 521 FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; 522 buildZSortedChildList(&zTranslatedNodes, displayList, chunk); 523 524 defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes); 525 for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { 526 const RecordedOp* op = displayList.getOps()[opIndex]; 527 receivers[op->opId](*this, *op); 528 529 if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() 530 && displayList.projectionReceiveIndex >= 0 531 && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) { 532 deferProjectedChildren(renderNode); 533 } 534 } 535 defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes); 536 } 537} 538 539void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) { 540 if (op.renderNode->nothingToDraw()) return; 541 int count = mCanvasState.save(SaveFlags::MatrixClip); 542 543 // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix) 544 mCanvasState.writableSnapshot()->applyClip(op.localClip, 545 *mCanvasState.currentSnapshot()->transform); 546 mCanvasState.concatMatrix(op.localMatrix); 547 548 // then apply state from node properties, and defer ops 549 deferNodePropsAndOps(*op.renderNode); 550 551 mCanvasState.restoreToCount(count); 552} 553 554void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { 555 if (!op.skipInOrderDraw) { 556 deferRenderNodeOpImpl(op); 557 } 558} 559 560/** 561 * Defers an unmergeable, strokeable op, accounting correctly 562 * for paint's style on the bounds being computed. 563 */ 564BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, 565 BakedOpState::StrokeBehavior strokeBehavior) { 566 // Note: here we account for stroke when baking the op 567 BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( 568 mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior); 569 if (!bakedState) return nullptr; // quick rejected 570 571 if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) { 572 bakedState->setupOpacity(op.paint); 573 } 574 575 currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); 576 return bakedState; 577} 578 579/** 580 * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will 581 * be used, since they trigger significantly different rendering paths. 582 * 583 * Note: not used for lines/points, since they don't currently support path effects. 584 */ 585static batchid_t tessBatchId(const RecordedOp& op) { 586 const SkPaint& paint = *(op.paint); 587 return paint.getPathEffect() 588 ? OpBatchType::AlphaMaskTexture 589 : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); 590} 591 592void FrameBuilder::deferArcOp(const ArcOp& op) { 593 deferStrokeableOp(op, tessBatchId(op)); 594} 595 596static bool hasMergeableClip(const BakedOpState& state) { 597 return !state.computedState.clipState 598 || state.computedState.clipState->mode == ClipMode::Rectangle; 599} 600 601void FrameBuilder::deferBitmapOp(const BitmapOp& op) { 602 BakedOpState* bakedState = tryBakeOpState(op); 603 if (!bakedState) return; // quick rejected 604 605 if (op.bitmap->isOpaque()) { 606 bakedState->setupOpacity(op.paint); 607 } 608 609 // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation 610 // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in 611 // MergingDrawBatch::canMergeWith() 612 if (bakedState->computedState.transform.isSimple() 613 && bakedState->computedState.transform.positiveScale() 614 && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver 615 && op.bitmap->colorType() != kAlpha_8_SkColorType 616 && hasMergeableClip(*bakedState)) { 617 mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID()); 618 currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); 619 } else { 620 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 621 } 622} 623 624void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) { 625 BakedOpState* bakedState = tryBakeOpState(op); 626 if (!bakedState) return; // quick rejected 627 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 628} 629 630void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) { 631 BakedOpState* bakedState = tryBakeOpState(op); 632 if (!bakedState) return; // quick rejected 633 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 634} 635 636void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) { 637 Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty(); 638 SkPaint* paint = op.vectorDrawable->getPaint(); 639 const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds, 640 op.localMatrix, 641 op.localClip, 642 paint, 643 &bitmap, 644 Rect(bitmap.width(), bitmap.height())); 645 deferBitmapRectOp(*resolvedOp); 646} 647 648void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) { 649 // allocate a temporary oval op (with mAllocator, so it persists until render), so the 650 // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. 651 float x = *(op.x); 652 float y = *(op.y); 653 float radius = *(op.radius); 654 Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); 655 const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>( 656 unmappedBounds, 657 op.localMatrix, 658 op.localClip, 659 op.paint); 660 deferOvalOp(*resolvedOp); 661} 662 663void FrameBuilder::deferColorOp(const ColorOp& op) { 664 BakedOpState* bakedState = tryBakeUnboundedOpState(op); 665 if (!bakedState) return; // quick rejected 666 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); 667} 668 669void FrameBuilder::deferFunctorOp(const FunctorOp& op) { 670 BakedOpState* bakedState = tryBakeUnboundedOpState(op); 671 if (!bakedState) return; // quick rejected 672 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); 673} 674 675void FrameBuilder::deferLinesOp(const LinesOp& op) { 676 batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; 677 deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); 678} 679 680void FrameBuilder::deferOvalOp(const OvalOp& op) { 681 deferStrokeableOp(op, tessBatchId(op)); 682} 683 684void FrameBuilder::deferPatchOp(const PatchOp& op) { 685 BakedOpState* bakedState = tryBakeOpState(op); 686 if (!bakedState) return; // quick rejected 687 688 if (bakedState->computedState.transform.isPureTranslate() 689 && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver 690 && hasMergeableClip(*bakedState)) { 691 mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID()); 692 693 // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together 694 currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId); 695 } else { 696 // Use Bitmap batchId since Bitmap+Patch use same shader 697 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 698 } 699} 700 701void FrameBuilder::deferPathOp(const PathOp& op) { 702 auto state = deferStrokeableOp(op, OpBatchType::AlphaMaskTexture); 703 if (CC_LIKELY(state)) { 704 mCaches.pathCache.precache(op.path, op.paint); 705 } 706} 707 708void FrameBuilder::deferPointsOp(const PointsOp& op) { 709 batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; 710 deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); 711} 712 713void FrameBuilder::deferRectOp(const RectOp& op) { 714 deferStrokeableOp(op, tessBatchId(op)); 715} 716 717void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) { 718 auto state = deferStrokeableOp(op, tessBatchId(op)); 719 if (CC_LIKELY(state && !op.paint->getPathEffect())) { 720 // TODO: consider storing tessellation task in BakedOpState 721 mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint), 722 op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry); 723 } 724} 725 726void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) { 727 // allocate a temporary round rect op (with mAllocator, so it persists until render), so the 728 // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. 729 const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>( 730 Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), 731 op.localMatrix, 732 op.localClip, 733 op.paint, *op.rx, *op.ry); 734 deferRoundRectOp(*resolvedOp); 735} 736 737void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) { 738 BakedOpState* bakedState = tryBakeOpState(op); 739 if (!bakedState) return; // quick rejected 740 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); 741} 742 743static batchid_t textBatchId(const SkPaint& paint) { 744 // TODO: better handling of shader (since we won't care about color then) 745 return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText; 746} 747 748void FrameBuilder::deferTextOp(const TextOp& op) { 749 BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( 750 mAllocator, *mCanvasState.writableSnapshot(), op, 751 BakedOpState::StrokeBehavior::StyleDefined); 752 if (!bakedState) return; // quick rejected 753 754 batchid_t batchId = textBatchId(*(op.paint)); 755 if (bakedState->computedState.transform.isPureTranslate() 756 && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver 757 && hasMergeableClip(*bakedState)) { 758 mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor()); 759 currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId); 760 } else { 761 currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); 762 } 763 764 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); 765 auto& totalTransform = bakedState->computedState.transform; 766 if (totalTransform.isPureTranslate() || totalTransform.isPerspective()) { 767 fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::I()); 768 } else { 769 // Partial transform case, see BakedOpDispatcher::renderTextOp 770 float sx, sy; 771 totalTransform.decomposeScale(sx, sy); 772 fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale( 773 roundf(std::max(1.0f, sx)), 774 roundf(std::max(1.0f, sy)))); 775 } 776} 777 778void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { 779 BakedOpState* bakedState = tryBakeUnboundedOpState(op); 780 if (!bakedState) return; // quick rejected 781 currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint))); 782 783 mCaches.fontRenderer.getFontRenderer().precache( 784 op.paint, op.glyphs, op.glyphCount, SkMatrix::I()); 785} 786 787void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) { 788 GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer()); 789 if (CC_UNLIKELY(!layer || !layer->isRenderable())) return; 790 791 const TextureLayerOp* textureLayerOp = &op; 792 // Now safe to access transform (which was potentially unready at record time) 793 if (!layer->getTransform().isIdentity()) { 794 // non-identity transform present, so 'inject it' into op by copying + replacing matrix 795 Matrix4 combinedMatrix(op.localMatrix); 796 combinedMatrix.multiply(layer->getTransform()); 797 textureLayerOp = mAllocator.create<TextureLayerOp>(op, combinedMatrix); 798 } 799 BakedOpState* bakedState = tryBakeOpState(*textureLayerOp); 800 801 if (!bakedState) return; // quick rejected 802 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); 803} 804 805void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, 806 float contentTranslateX, float contentTranslateY, 807 const Rect& repaintRect, 808 const Vector3& lightCenter, 809 const BeginLayerOp* beginLayerOp, RenderNode* renderNode) { 810 mCanvasState.save(SaveFlags::MatrixClip); 811 mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight); 812 mCanvasState.writableSnapshot()->roundRectClipState = nullptr; 813 mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter); 814 mCanvasState.writableSnapshot()->transform->loadTranslate( 815 contentTranslateX, contentTranslateY, 0); 816 mCanvasState.writableSnapshot()->setClip( 817 repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom); 818 819 // create a new layer repaint, and push its index on the stack 820 mLayerStack.push_back(mLayerBuilders.size()); 821 auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight, 822 repaintRect, beginLayerOp, renderNode); 823 mLayerBuilders.push_back(newFbo); 824} 825 826void FrameBuilder::restoreForLayer() { 827 // restore canvas, and pop finished layer off of the stack 828 mCanvasState.restore(); 829 mLayerStack.pop_back(); 830} 831 832// TODO: defer time rejection (when bounds become empty) + tests 833// Option - just skip layers with no bounds at playback + defer? 834void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) { 835 uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); 836 uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); 837 838 auto previous = mCanvasState.currentSnapshot(); 839 Vector3 lightCenter = previous->getRelativeLightCenter(); 840 841 // Combine all transforms used to present saveLayer content: 842 // parent content transform * canvas transform * bounds offset 843 Matrix4 contentTransform(*(previous->transform)); 844 contentTransform.multiply(op.localMatrix); 845 contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); 846 847 Matrix4 inverseContentTransform; 848 inverseContentTransform.loadInverse(contentTransform); 849 850 // map the light center into layer-relative space 851 inverseContentTransform.mapPoint3d(lightCenter); 852 853 // Clip bounds of temporary layer to parent's clip rect, so: 854 Rect saveLayerBounds(layerWidth, layerHeight); 855 // 1) transform Rect(width, height) into parent's space 856 // note: left/top offsets put in contentTransform above 857 contentTransform.mapRect(saveLayerBounds); 858 // 2) intersect with parent's clip 859 saveLayerBounds.doIntersect(previous->getRenderTargetClip()); 860 // 3) and transform back 861 inverseContentTransform.mapRect(saveLayerBounds); 862 saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); 863 saveLayerBounds.roundOut(); 864 865 // if bounds are reduced, will clip the layer's area by reducing required bounds... 866 layerWidth = saveLayerBounds.getWidth(); 867 layerHeight = saveLayerBounds.getHeight(); 868 // ...and shifting drawing content to account for left/top side clipping 869 float contentTranslateX = -saveLayerBounds.left; 870 float contentTranslateY = -saveLayerBounds.top; 871 872 saveForLayer(layerWidth, layerHeight, 873 contentTranslateX, contentTranslateY, 874 Rect(layerWidth, layerHeight), 875 lightCenter, 876 &op, nullptr); 877} 878 879void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) { 880 const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; 881 int finishedLayerIndex = mLayerStack.back(); 882 883 restoreForLayer(); 884 885 // saveLayer will clip & translate the draw contents, so we need 886 // to translate the drawLayer by how much the contents was translated 887 // TODO: Unify this with beginLayerOp so we don't have to calculate this 888 // twice 889 uint32_t layerWidth = (uint32_t) beginLayerOp.unmappedBounds.getWidth(); 890 uint32_t layerHeight = (uint32_t) beginLayerOp.unmappedBounds.getHeight(); 891 892 auto previous = mCanvasState.currentSnapshot(); 893 Vector3 lightCenter = previous->getRelativeLightCenter(); 894 895 // Combine all transforms used to present saveLayer content: 896 // parent content transform * canvas transform * bounds offset 897 Matrix4 contentTransform(*(previous->transform)); 898 contentTransform.multiply(beginLayerOp.localMatrix); 899 contentTransform.translate(beginLayerOp.unmappedBounds.left, 900 beginLayerOp.unmappedBounds.top); 901 902 Matrix4 inverseContentTransform; 903 inverseContentTransform.loadInverse(contentTransform); 904 905 // map the light center into layer-relative space 906 inverseContentTransform.mapPoint3d(lightCenter); 907 908 // Clip bounds of temporary layer to parent's clip rect, so: 909 Rect saveLayerBounds(layerWidth, layerHeight); 910 // 1) transform Rect(width, height) into parent's space 911 // note: left/top offsets put in contentTransform above 912 contentTransform.mapRect(saveLayerBounds); 913 // 2) intersect with parent's clip 914 saveLayerBounds.doIntersect(previous->getRenderTargetClip()); 915 // 3) and transform back 916 inverseContentTransform.mapRect(saveLayerBounds); 917 saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); 918 saveLayerBounds.roundOut(); 919 920 Matrix4 localMatrix(beginLayerOp.localMatrix); 921 localMatrix.translate(saveLayerBounds.left, saveLayerBounds.top); 922 923 // record the draw operation into the previous layer's list of draw commands 924 // uses state from the associated beginLayerOp, since it has all the state needed for drawing 925 LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>( 926 beginLayerOp.unmappedBounds, 927 localMatrix, 928 beginLayerOp.localClip, 929 beginLayerOp.paint, 930 &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer)); 931 BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); 932 933 if (bakedOpState) { 934 // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack) 935 currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); 936 } else { 937 // Layer won't be drawn - delete its drawing batches to prevent it from doing any work 938 // TODO: need to prevent any render work from being done 939 // - create layerop earlier for reject purposes? 940 mLayerBuilders[finishedLayerIndex]->clear(); 941 return; 942 } 943} 944 945void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { 946 Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform)); 947 boundsTransform.multiply(op.localMatrix); 948 949 Rect dstRect(op.unmappedBounds); 950 boundsTransform.mapRect(dstRect); 951 dstRect.roundOut(); 952 dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip()); 953 954 if (dstRect.isEmpty()) { 955 // Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored 956 currentLayer().activeUnclippedSaveLayers.push_back(nullptr); 957 } else { 958 // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume) 959 OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr); 960 961 /** 962 * First, defer an operation to copy out the content from the rendertarget into a layer. 963 */ 964 auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle); 965 BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator, 966 &(currentLayer().repaintClip), dstRect, *copyToOp); 967 currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer); 968 969 /** 970 * Defer a clear rect, so that clears from multiple unclipped layers can be drawn 971 * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible 972 */ 973 currentLayer().deferLayerClear(dstRect); 974 975 /** 976 * And stash an operation to copy that layer back under the rendertarget until 977 * a balanced EndUnclippedLayerOp is seen 978 */ 979 auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle); 980 bakedState = BakedOpState::directConstruct(mAllocator, 981 &(currentLayer().repaintClip), dstRect, *copyFromOp); 982 currentLayer().activeUnclippedSaveLayers.push_back(bakedState); 983 } 984} 985 986void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { 987 LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!"); 988 989 BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back(); 990 currentLayer().activeUnclippedSaveLayers.pop_back(); 991 if (copyFromLayerOp) { 992 currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer); 993 } 994} 995 996void FrameBuilder::finishDefer() { 997 mCaches.fontRenderer.endPrecaching(); 998} 999 1000} // namespace uirenderer 1001} // namespace android 1002