FrameBuilder.cpp revision e4db79de127cfe961195f52907af8451026eaa20
1b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/* 2b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Copyright (C) 2015 The Android Open Source Project 3b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 4b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Licensed under the Apache License, Version 2.0 (the "License"); 5b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * you may not use this file except in compliance with the License. 6b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * You may obtain a copy of the License at 7b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 8b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * http://www.apache.org/licenses/LICENSE-2.0 9b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 10b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Unless required by applicable law or agreed to in writing, software 11b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * distributed under the License is distributed on an "AS IS" BASIS, 12b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * See the License for the specific language governing permissions and 14b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * limitations under the License. 15b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */ 16b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 17b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include "OpReorderer.h" 18b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 190b7e8245db728d127ada698be63d78b33fc6e4daChris Craik#include "LayerUpdateQueue.h" 20161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik#include "RenderNode.h" 2198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik#include "renderstate/OffscreenBufferPool.h" 22161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik#include "utils/FatVector.h" 23161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik#include "utils/PaintUtils.h" 248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik#include "utils/TraceUtils.h" 25b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 26161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik#include <SkCanvas.h> 27d3daa3198e2212c985c634821682d5819346b653Chris Craik#include <SkPathOps.h> 28161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik#include <utils/TypeHelpers.h> 29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android { 31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer { 32b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 33b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass BatchBase { 34b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 35b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic: 36b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik BatchBase(batchid_t batchId, BakedOpState* op, bool merging) 3798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik : mBatchId(batchId) 3898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik , mMerging(merging) { 39b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mBounds = op->computedState.clippedBounds; 40b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mOps.push_back(op); 41b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 42b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 43b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool intersects(const Rect& rect) const { 44b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!rect.intersects(mBounds)) return false; 45b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 46b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik for (const BakedOpState* op : mOps) { 47b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (rect.intersects(op->computedState.clippedBounds)) { 48b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return true; 49b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 50b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 51b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return false; 52b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 53b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 54b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik batchid_t getBatchId() const { return mBatchId; } 55b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool isMerging() const { return mMerging; } 56b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 57b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const std::vector<BakedOpState*>& getOps() const { return mOps; } 58b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 59b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik void dump() const { 606fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, 616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds)); 62b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 63b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikprotected: 64b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik batchid_t mBatchId; 65b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik Rect mBounds; 66b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik std::vector<BakedOpState*> mOps; 67b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool mMerging; 68b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}; 69b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 70b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass OpBatch : public BatchBase { 71b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic: 72b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik static void* operator new(size_t size, LinearAllocator& allocator) { 73b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return allocator.alloc(size); 74b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 75b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 76b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik OpBatch(batchid_t batchId, BakedOpState* op) 77b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik : BatchBase(batchId, op, false) { 78b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 79b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 80b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik void batchOp(BakedOpState* op) { 81b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mBounds.unionWith(op->computedState.clippedBounds); 82b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mOps.push_back(op); 83b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 84b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}; 85b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 86b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass MergingOpBatch : public BatchBase { 87b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic: 88b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik static void* operator new(size_t size, LinearAllocator& allocator) { 89b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return allocator.alloc(size); 90b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 91b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 92b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik MergingOpBatch(batchid_t batchId, BakedOpState* op) 93d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik : BatchBase(batchId, op, true) 9493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik , mClipSideFlags(op->computedState.clipSideFlags) { 95b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 96b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 97b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik /* 98b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds 99b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * and clip side flags. Positive bounds delta means new bounds fit in old. 100b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */ 101b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik static inline bool checkSide(const int currentFlags, const int newFlags, const int side, 102b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik float boundsDelta) { 103b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool currentClipExists = currentFlags & side; 104b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool newClipExists = newFlags & side; 105b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 106b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // if current is clipped, we must be able to fit new bounds in current 107b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (boundsDelta > 0 && currentClipExists) return false; 108b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 109b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // if new is clipped, we must be able to fit current bounds in new 110b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (boundsDelta < 0 && newClipExists) return false; 111b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 112b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return true; 113b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 114b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 115b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik static bool paintIsDefault(const SkPaint& paint) { 116b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return paint.getAlpha() == 255 117b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik && paint.getColorFilter() == nullptr 118b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik && paint.getShader() == nullptr; 119b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 120b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 121b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) { 122b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return a.getAlpha() == b.getAlpha() 123b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik && a.getColorFilter() == b.getColorFilter() 124b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik && a.getShader() == b.getShader(); 125b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 126b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 127b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik /* 128b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Checks if a (mergeable) op can be merged into this batch 129b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 130b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is 131b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * important to consider all paint attributes used in the draw calls in deciding both a) if an 132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * op tries to merge at all, and b) if the op can merge with another set of ops 133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * False positives can lead to information from the paints of subsequent merged operations being 135b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * dropped, so we make simplifying qualifications on the ops that can merge, per op type. 136b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */ 137b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool canMergeWith(BakedOpState* op) const { 138b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik bool isTextBatch = getBatchId() == OpBatchType::Text 139b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik || getBatchId() == OpBatchType::ColorText; 140b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 141b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // Overlapping other operations is only allowed for text without shadow. For other ops, 142b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // multiDraw isn't guaranteed to overdraw correctly 143b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { 144b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (intersects(op->computedState.clippedBounds)) return false; 145b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 146b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 147b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const BakedOpState* lhs = op; 148b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const BakedOpState* rhs = mOps[0]; 149b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 150b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; 151b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 152b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // Identical round rect clip state means both ops will clip in the same way, or not at all. 153b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // As the state objects are const, we can compare their pointers to determine mergeability 154b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (lhs->roundRectClipState != rhs->roundRectClipState) return false; 155b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (lhs->projectionPathMask != rhs->projectionPathMask) return false; 156b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 157b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik /* Clipping compatibility check 158b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 159b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its 160b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * clip for that side. 161b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */ 162b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const int currentFlags = mClipSideFlags; 163b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const int newFlags = op->computedState.clipSideFlags; 164b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { 165b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const Rect& opBounds = op->computedState.clippedBounds; 166b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik float boundsDelta = mBounds.left - opBounds.left; 167b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false; 168b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik boundsDelta = mBounds.top - opBounds.top; 169b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; 170b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 171b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // right and bottom delta calculation reversed to account for direction 172b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik boundsDelta = opBounds.right - mBounds.right; 173b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false; 174b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik boundsDelta = opBounds.bottom - mBounds.bottom; 175b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false; 176b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 177b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 178b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const SkPaint* newPaint = op->op->paint; 179b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik const SkPaint* oldPaint = mOps[0]->op->paint; 180b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (newPaint == oldPaint) { 182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik // if paints are equal, then modifiers + paint attribs don't need to be compared 183b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return true; 184b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } else if (newPaint && !oldPaint) { 185b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return paintIsDefault(*newPaint); 186b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } else if (!newPaint && oldPaint) { 187b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return paintIsDefault(*oldPaint); 188b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 189b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return paintsAreEquivalent(*newPaint, *oldPaint); 190b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 191b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 192b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik void mergeOp(BakedOpState* op) { 193b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mBounds.unionWith(op->computedState.clippedBounds); 194b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mOps.push_back(op); 195b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 19693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat 19793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik // check, and doesn't extend past a side of the clip that's in use by the merged batch. 19893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. 19993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik mClipSideFlags |= op->computedState.clipSideFlags; 200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 202d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik int getClipSideFlags() const { return mClipSideFlags; } 20393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik const Rect& getClipRect() const { return mBounds; } 20415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikprivate: 206d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik int mClipSideFlags; 207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}; 208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 2090b7e8245db728d127ada698be63d78b33fc6e4daChris CraikOpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, 21098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode) 2110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik : width(width) 2120b7e8245db728d127ada698be63d78b33fc6e4daChris Craik , height(height) 21398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik , repaintRect(repaintRect) 2140b7e8245db728d127ada698be63d78b33fc6e4daChris Craik , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) 2150b7e8245db728d127ada698be63d78b33fc6e4daChris Craik , beginLayerOp(beginLayerOp) 2160b7e8245db728d127ada698be63d78b33fc6e4daChris Craik , renderNode(renderNode) {} 2170b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 2186fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// iterate back toward target to see if anything drawn since should overlap the new op 219818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik// if no target, merging ops still iterate to find similar batch to insert after 2206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds, 2216fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik BatchBase** targetBatch, size_t* insertBatchIndex) const { 2226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik for (int i = mBatches.size() - 1; i >= 0; i--) { 2236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik BatchBase* overBatch = mBatches[i]; 2246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (overBatch == *targetBatch) break; 2266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // TODO: also consider shader shared between batch types 2286fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (batchId == overBatch->getBatchId()) { 2296fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *insertBatchIndex = i + 1; 2306fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (!*targetBatch) break; // found insert position, quit 2316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (overBatch->intersects(clippedBounds)) { 2346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // NOTE: it may be possible to optimize for special cases where two operations 2356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // of the same batch/paint could swap order, such as with a non-mergeable 2366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // (clipped) and a mergeable text operation 2376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *targetBatch = nullptr; 2386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik break; 2396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} 2426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator, 2446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik BakedOpState* op, batchid_t batchId) { 2456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik OpBatch* targetBatch = mBatchLookup[batchId]; 2466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik size_t insertBatchIndex = mBatches.size(); 2486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (targetBatch) { 2496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik locateInsertIndex(batchId, op->computedState.clippedBounds, 2506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik (BatchBase**)(&targetBatch), &insertBatchIndex); 2516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (targetBatch) { 2546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch->batchOp(op); 2556fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } else { 2566fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // new non-merging batch 2576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch = new (allocator) OpBatch(batchId, op); 2586fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mBatchLookup[batchId] = targetBatch; 2596fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); 2606fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} 2626fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2636fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// insertion point of a new batch, will hopefully be immediately after similar batch 2646fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// (generally, should be similar shader) 2656fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator, 2666fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik BakedOpState* op, batchid_t batchId, mergeid_t mergeId) { 2676fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik MergingOpBatch* targetBatch = nullptr; 2686fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2696fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // Try to merge with any existing batch with same mergeId 2706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik auto getResult = mMergingBatchLookup[batchId].find(mergeId); 2716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (getResult != mMergingBatchLookup[batchId].end()) { 2726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch = getResult->second; 2736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (!targetBatch->canMergeWith(op)) { 2746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch = nullptr; 2756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik size_t insertBatchIndex = mBatches.size(); 2796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik locateInsertIndex(batchId, op->computedState.clippedBounds, 2806fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik (BatchBase**)(&targetBatch), &insertBatchIndex); 2816fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (targetBatch) { 2836fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch->mergeOp(op); 2846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } else { 2856fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // new merging batch 2866fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik targetBatch = new (allocator) MergingOpBatch(batchId, op); 2876fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch)); 2886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 2896fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); 2906fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 2916fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} 2926fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 29315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craikvoid OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, 29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const { 2955854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik ATRACE_NAME("flush drawing commands"); 2966fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik for (const BatchBase* batch : mBatches) { 29715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik size_t size = batch->getOps().size(); 29815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (size > 1 && batch->isMerging()) { 29915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik int opId = batch->getOps()[0]->op->opId; 30015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch); 30115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik MergedBakedOpList data = { 30215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik batch->getOps().data(), 30315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik size, 30415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik mergingBatch->getClipSideFlags(), 30515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik mergingBatch->getClipRect() 30615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik }; 30715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik mergedReceivers[opId](arg, data); 30815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } else { 30915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik for (const BakedOpState* op : batch->getOps()) { 31015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik unmergedReceivers[op->op->opId](arg, *op); 31115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 3126fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 3136fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 3146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} 3156fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 3166fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::dump() const { 3170b7e8245db728d127ada698be63d78b33fc6e4daChris Craik ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p", 3180b7e8245db728d127ada698be63d78b33fc6e4daChris Craik this, width, height, offscreenBuffer, beginLayerOp, renderNode); 3196fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik for (const BatchBase* batch : mBatches) { 3206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik batch->dump(); 3216fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } 3226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} 323b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 3240b7e8245db728d127ada698be63d78b33fc6e4daChris CraikOpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, 3250b7e8245db728d127ada698be63d78b33fc6e4daChris Craik uint32_t viewportWidth, uint32_t viewportHeight, 32698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter) 3276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik : mCanvasState(*this) { 328818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik ATRACE_NAME("prepare drawing commands"); 3296fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 33098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mLayerReorderers.reserve(layers.entries().size()); 33198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mLayerStack.reserve(layers.entries().size()); 33298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik 33398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik // Prepare to defer Fbo0 33498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mLayerReorderers.emplace_back(viewportWidth, viewportHeight, Rect(clip)); 33598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mLayerStack.push_back(0); 336b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 337ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik clip.fLeft, clip.fTop, clip.fRight, clip.fBottom, 33898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik lightCenter); 3390b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 3400b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // Render all layers to be updated, in order. Defer in reverse order, so that they'll be 3410b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // updated in the order they're passed in (mLayerReorderers are issued to Renderer in reverse) 3420b7e8245db728d127ada698be63d78b33fc6e4daChris Craik for (int i = layers.entries().size() - 1; i >= 0; i--) { 3430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik RenderNode* layerNode = layers.entries()[i].renderNode; 3440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik const Rect& layerDamage = layers.entries()[i].damage; 3458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik layerNode->computeOrdering(); 3460b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 3478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // map current light center into RenderNode's coordinate space 3488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); 3498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter); 3508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 3518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, 3528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik layerDamage, lightCenter, nullptr, layerNode); 3530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 3540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik if (layerNode->getDisplayList()) { 3558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik deferNodeOps(*layerNode); 3560b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } 3570b7e8245db728d127ada698be63d78b33fc6e4daChris Craik restoreForLayer(); 3580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } 3590b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 3600b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // Defer Fbo0 361b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik for (const sp<RenderNode>& node : nodes) { 362b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik if (node->nothingToDraw()) continue; 3638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik node->computeOrdering(); 364b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 3650b7e8245db728d127ada698be63d78b33fc6e4daChris Craik int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); 3660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik deferNodePropsAndOps(*node); 3670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik mCanvasState.restoreToCount(count); 368b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 369b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 370b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 371818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craikvoid OpReorderer::onViewportInitialized() {} 372818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik 373818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craikvoid OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} 374818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik 3750b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::deferNodePropsAndOps(RenderNode& node) { 3768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const RenderProperties& properties = node.properties(); 3778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const Outline& outline = properties.getOutline(); 3788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.getAlpha() <= 0 3798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik || (outline.getShouldClip() && outline.isEmpty()) 3808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik || properties.getScaleX() == 0 3818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik || properties.getScaleY() == 0) { 3828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik return; // rejected 3838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 3848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 3858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.getLeft() != 0 || properties.getTop() != 0) { 3868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.translate(properties.getLeft(), properties.getTop()); 3878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 3888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.getStaticMatrix()) { 3898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.concatMatrix(*properties.getStaticMatrix()); 3908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } else if (properties.getAnimationMatrix()) { 3918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.concatMatrix(*properties.getAnimationMatrix()); 3928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 3938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.hasTransformMatrix()) { 3948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.isTransformTranslateOnly()) { 3958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY()); 3968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } else { 3978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.concatMatrix(*properties.getTransformMatrix()); 3988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 3998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 4018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const int width = properties.getWidth(); 4028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const int height = properties.getHeight(); 4038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 4048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Rect saveLayerBounds; // will be set to non-empty if saveLayer needed 4058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const bool isLayer = properties.effectiveLayerType() != LayerType::None; 4068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik int clipFlags = properties.getClippingFlags(); 4078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.getAlpha() < 1) { 4088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (isLayer) { 4098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer 4108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { 4128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // simply scale rendering content's alpha 4138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.scaleAlpha(properties.getAlpha()); 4148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } else { 4158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // schedule saveLayer by initializing saveLayerBounds 4168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerBounds.set(0, 0, width, height); 4178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (clipFlags) { 4188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik properties.getClippingRectForFlags(clipFlags, &saveLayerBounds); 4198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik clipFlags = 0; // all clipping done by savelayer 4208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 4238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { 4248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // pretend alpha always causes savelayer to warn about 4258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // performance problem affecting old versions 4268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height); 4278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (clipFlags) { 4308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Rect clipRect; 4318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik properties.getClippingRectForFlags(clipFlags, &clipRect); 4328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, 4338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik SkRegion::kIntersect_Op); 4348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 4368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (properties.getRevealClip().willClip()) { 4378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Rect bounds; 4388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik properties.getRevealClip().getBounds(&bounds); 4398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.setClippingRoundRect(mAllocator, 4408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik bounds, properties.getRevealClip().getRadius()); 4418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } else if (properties.getOutline().willClip()) { 4428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); 4438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } 4448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 4458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik if (!mCanvasState.quickRejectConservative(0, 0, width, height)) { 4468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) 4470b7e8245db728d127ada698be63d78b33fc6e4daChris Craik if (node.getLayer()) { 4480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // HW layer 4490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik LayerOp* drawLayerOp = new (mAllocator) LayerOp(node); 4500b7e8245db728d127ada698be63d78b33fc6e4daChris Craik BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); 4510b7e8245db728d127ada698be63d78b33fc6e4daChris Craik if (bakedOpState) { 4528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // Node's layer already deferred, schedule it to render into parent layer 4530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); 4540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } 4558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) { 4568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // draw DisplayList contents within temporary, since persisted layer could not be used. 4578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // (temp layers are clipped to viewport, since they don't persist offscreen content) 4588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik SkPaint saveLayerPaint; 4598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerPaint.setAlpha(properties.getAlpha()); 460268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferBeginLayerOp(*new (mAllocator) BeginLayerOp( 4618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerBounds, 4628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Matrix4::identity(), 463e4db79de127cfe961195f52907af8451026eaa20Chris Craik nullptr, // no record-time clip - need only respect defer-time one 4648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik &saveLayerPaint)); 4658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik deferNodeOps(node); 466268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferEndLayerOp(*new (mAllocator) EndLayerOp()); 4670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } else { 4688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik deferNodeOps(node); 4690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } 4700b7e8245db728d127ada698be63d78b33fc6e4daChris Craik } 4710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik} 4720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 473161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craiktypedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair; 474161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 475161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craiktemplate <typename V> 476161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void buildZSortedChildList(V* zTranslatedNodes, 477161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const DisplayList& displayList, const DisplayList::Chunk& chunk) { 478161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (chunk.beginChildIndex == chunk.endChildIndex) return; 479161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 480161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { 481161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik RenderNodeOp* childOp = displayList.getChildren()[i]; 482161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik RenderNode* child = childOp->renderNode; 483161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik float childZ = child->properties().getZ(); 484161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 485161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { 486161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); 487161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik childOp->skipInOrderDraw = true; 488161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } else if (!child->properties().getProjectBackwards()) { 489161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik // regular, in order drawing DisplayList 490161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik childOp->skipInOrderDraw = false; 491161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 492161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 493161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 494161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) 495161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); 496161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik} 497161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 498161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craiktemplate <typename V> 499161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic size_t findNonNegativeIndex(const V& zTranslatedNodes) { 500161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik for (size_t i = 0; i < zTranslatedNodes.size(); i++) { 501161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (zTranslatedNodes[i].key >= 0.0f) return i; 502161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 503161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik return zTranslatedNodes.size(); 504161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik} 505161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 506161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craiktemplate <typename V> 507161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikvoid OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) { 508161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const int size = zTranslatedNodes.size(); 509161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (size == 0 510161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f) 511161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { 512161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik // no 3d children to draw 513161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik return; 514161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 515161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 516161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik /** 517161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters 518161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik * with very similar Z heights to draw together. 519161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik * 520161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are 521161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik * underneath both, and neither's shadow is drawn on top of the other. 522161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik */ 523161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); 524161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik size_t drawIndex, shadowIndex, endIndex; 525161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (mode == ChildrenSelectMode::Negative) { 526161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik drawIndex = 0; 527161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik endIndex = nonNegativeIndex; 528161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik shadowIndex = endIndex; // draw no shadows 529161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } else { 530161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik drawIndex = nonNegativeIndex; 531161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik endIndex = size; 532161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik shadowIndex = drawIndex; // potentially draw shadow for each pos Z child 533161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 534161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 535161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik float lastCasterZ = 0.0f; 536161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik while (shadowIndex < endIndex || drawIndex < endIndex) { 537161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (shadowIndex < endIndex) { 538161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; 539161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const float casterZ = zTranslatedNodes[shadowIndex].key; 540161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik // attempt to render the shadow if the caster about to be drawn is its caster, 541161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik // OR if its caster's Z value is similar to the previous potential caster 542161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { 543161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik deferShadow(*casterNodeOp); 544161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 545161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik lastCasterZ = casterZ; // must do this even if current caster not casting a shadow 546161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik shadowIndex++; 547161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik continue; 548161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 549161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 550161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 551161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; 552268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferRenderNodeOpImpl(*childOp); 553161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik drawIndex++; 554161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 555161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik} 556161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 557161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikvoid OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { 558d3daa3198e2212c985c634821682d5819346b653Chris Craik auto& node = *casterNodeOp.renderNode; 559d3daa3198e2212c985c634821682d5819346b653Chris Craik auto& properties = node.properties(); 560d3daa3198e2212c985c634821682d5819346b653Chris Craik 561d3daa3198e2212c985c634821682d5819346b653Chris Craik if (properties.getAlpha() <= 0.0f 562d3daa3198e2212c985c634821682d5819346b653Chris Craik || properties.getOutline().getAlpha() <= 0.0f 563d3daa3198e2212c985c634821682d5819346b653Chris Craik || !properties.getOutline().getPath() 564d3daa3198e2212c985c634821682d5819346b653Chris Craik || properties.getScaleX() == 0 565d3daa3198e2212c985c634821682d5819346b653Chris Craik || properties.getScaleY() == 0) { 566d3daa3198e2212c985c634821682d5819346b653Chris Craik // no shadow to draw 567d3daa3198e2212c985c634821682d5819346b653Chris Craik return; 568d3daa3198e2212c985c634821682d5819346b653Chris Craik } 569d3daa3198e2212c985c634821682d5819346b653Chris Craik 570d3daa3198e2212c985c634821682d5819346b653Chris Craik const SkPath* casterOutlinePath = properties.getOutline().getPath(); 571d3daa3198e2212c985c634821682d5819346b653Chris Craik const SkPath* revealClipPath = properties.getRevealClip().getPath(); 572d3daa3198e2212c985c634821682d5819346b653Chris Craik if (revealClipPath && revealClipPath->isEmpty()) return; 573d3daa3198e2212c985c634821682d5819346b653Chris Craik 574d3daa3198e2212c985c634821682d5819346b653Chris Craik float casterAlpha = properties.getAlpha() * properties.getOutline().getAlpha(); 575d3daa3198e2212c985c634821682d5819346b653Chris Craik 576d3daa3198e2212c985c634821682d5819346b653Chris Craik // holds temporary SkPath to store the result of intersections 577d3daa3198e2212c985c634821682d5819346b653Chris Craik SkPath* frameAllocatedPath = nullptr; 578d3daa3198e2212c985c634821682d5819346b653Chris Craik const SkPath* casterPath = casterOutlinePath; 579d3daa3198e2212c985c634821682d5819346b653Chris Craik 580d3daa3198e2212c985c634821682d5819346b653Chris Craik // intersect the shadow-casting path with the reveal, if present 581d3daa3198e2212c985c634821682d5819346b653Chris Craik if (revealClipPath) { 582d3daa3198e2212c985c634821682d5819346b653Chris Craik frameAllocatedPath = createFrameAllocatedPath(); 583d3daa3198e2212c985c634821682d5819346b653Chris Craik 584d3daa3198e2212c985c634821682d5819346b653Chris Craik Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath); 585d3daa3198e2212c985c634821682d5819346b653Chris Craik casterPath = frameAllocatedPath; 586d3daa3198e2212c985c634821682d5819346b653Chris Craik } 587d3daa3198e2212c985c634821682d5819346b653Chris Craik 588d3daa3198e2212c985c634821682d5819346b653Chris Craik // intersect the shadow-casting path with the clipBounds, if present 589d3daa3198e2212c985c634821682d5819346b653Chris Craik if (properties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS) { 590d3daa3198e2212c985c634821682d5819346b653Chris Craik if (!frameAllocatedPath) { 591d3daa3198e2212c985c634821682d5819346b653Chris Craik frameAllocatedPath = createFrameAllocatedPath(); 592d3daa3198e2212c985c634821682d5819346b653Chris Craik } 593d3daa3198e2212c985c634821682d5819346b653Chris Craik Rect clipBounds; 594d3daa3198e2212c985c634821682d5819346b653Chris Craik properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); 595d3daa3198e2212c985c634821682d5819346b653Chris Craik SkPath clipBoundsPath; 596d3daa3198e2212c985c634821682d5819346b653Chris Craik clipBoundsPath.addRect(clipBounds.left, clipBounds.top, 597d3daa3198e2212c985c634821682d5819346b653Chris Craik clipBounds.right, clipBounds.bottom); 598d3daa3198e2212c985c634821682d5819346b653Chris Craik 599d3daa3198e2212c985c634821682d5819346b653Chris Craik Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath); 600d3daa3198e2212c985c634821682d5819346b653Chris Craik casterPath = frameAllocatedPath; 601d3daa3198e2212c985c634821682d5819346b653Chris Craik } 602d3daa3198e2212c985c634821682d5819346b653Chris Craik 603d3daa3198e2212c985c634821682d5819346b653Chris Craik ShadowOp* shadowOp = new (mAllocator) ShadowOp(casterNodeOp, casterAlpha, casterPath, 60498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mCanvasState.getLocalClipBounds(), 60598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mCanvasState.currentSnapshot()->getRelativeLightCenter()); 606d3daa3198e2212c985c634821682d5819346b653Chris Craik BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct( 607e4db79de127cfe961195f52907af8451026eaa20Chris Craik mAllocator, *mCanvasState.writableSnapshot(), shadowOp); 608d3daa3198e2212c985c634821682d5819346b653Chris Craik if (CC_LIKELY(bakedOpState)) { 609d3daa3198e2212c985c634821682d5819346b653Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow); 610d3daa3198e2212c985c634821682d5819346b653Chris Craik } 611161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik} 612d3daa3198e2212c985c634821682d5819346b653Chris Craik 6138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craikvoid OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { 6148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); 6158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 6168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // can't be null, since DL=null node rejection happens before deferNodePropsAndOps 6188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const DisplayList& displayList = *(renderNode.getDisplayList()); 6198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]); 6218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op); 6228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const RenderProperties& backgroundProps = backgroundOp->renderNode->properties(); 6238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // Transform renderer to match background we're projecting onto 6258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) 6268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); 6278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // If the projection receiver has an outline, we mask projected content to it 6298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // (which we know, apriori, are all tessellated paths) 6308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline); 6318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // draw projected nodes 6338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { 6348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; 6358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag); 6378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); 638268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferRenderNodeOpImpl(*childOp); 6398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik mCanvasState.restoreToCount(restoreTo); 6408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik } 6418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik mCanvasState.restoreToCount(count); 6438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik} 6448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 645b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/** 646268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods. 647b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * 6488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. 6498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) 650b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */ 6516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik#define OP_RECEIVER(Type) \ 652268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, 6538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craikvoid OpReorderer::deferNodeOps(const RenderNode& renderNode) { 65415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); 65515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik static OpDispatcher receivers[] = { 6566fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik MAP_OPS(OP_RECEIVER) 657b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik }; 6588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik // can't be null, since DL=null node rejection happens before deferNodePropsAndOps 6608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik const DisplayList& displayList = *(renderNode.getDisplayList()); 661b36af87f8275f4b982906f88193ec27600f2746aChris Craik for (const DisplayList::Chunk& chunk : displayList.getChunks()) { 662161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes; 663161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik buildZSortedChildList(&zTranslatedNodes, displayList, chunk); 664161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 665161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes); 666b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { 667b36af87f8275f4b982906f88193ec27600f2746aChris Craik const RecordedOp* op = displayList.getOps()[opIndex]; 668b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik receivers[op->opId](*this, *op); 6698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik 6708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() 6718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik && displayList.projectionReceiveIndex >= 0 6728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) { 6738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik deferProjectedChildren(renderNode); 6748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik } 675b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 676161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes); 677b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 678b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 679b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 680268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { 681161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (op.renderNode->nothingToDraw()) return; 6826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); 683b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 684e4db79de127cfe961195f52907af8451026eaa20Chris Craik // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix) 685e4db79de127cfe961195f52907af8451026eaa20Chris Craik mCanvasState.writableSnapshot()->mutateClipArea().applyClip(op.localClip, 686e4db79de127cfe961195f52907af8451026eaa20Chris Craik *mCanvasState.currentSnapshot()->transform); 687b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik mCanvasState.concatMatrix(op.localMatrix); 688b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 6890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // then apply state from node properties, and defer ops 6900b7e8245db728d127ada698be63d78b33fc6e4daChris Craik deferNodePropsAndOps(*op.renderNode); 6910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 6926fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mCanvasState.restoreToCount(count); 693b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 694b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 695268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { 696161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik if (!op.skipInOrderDraw) { 697268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferRenderNodeOpImpl(op); 698161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik } 699161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik} 700161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik 701386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik/** 702386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * Defers an unmergeable, strokeable op, accounting correctly 703386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * for paint's style on the bounds being computed. 704386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik */ 705268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, 706386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik BakedOpState::StrokeBehavior strokeBehavior) { 707386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik // Note: here we account for stroke when baking the op 708386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( 709e4db79de127cfe961195f52907af8451026eaa20Chris Craik mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior); 710386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik if (!bakedState) return; // quick rejected 711386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); 712386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 713386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 714386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik/** 715386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will 716386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * be used, since they trigger significantly different rendering paths. 717386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * 718386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik * Note: not used for lines/points, since they don't currently support path effects. 719386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik */ 720386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craikstatic batchid_t tessBatchId(const RecordedOp& op) { 721386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik const SkPaint& paint = *(op.paint); 722b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik return paint.getPathEffect() 723b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik ? OpBatchType::AlphaMaskTexture 724b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); 725b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 726b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 727268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferArcOp(const ArcOp& op) { 728268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, tessBatchId(op)); 729386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 730386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 731268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferBitmapOp(const BitmapOp& op) { 73215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 73315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!bakedState) return; // quick rejected 73415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik 73515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation 73615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in 73715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // MergingDrawBatch::canMergeWith() 73815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (bakedState->computedState.transform.isSimple() 73915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik && bakedState->computedState.transform.positiveScale() 74015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode 74115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik && op.bitmap->colorType() != kAlpha_8_SkColorType) { 74215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); 74315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik // TODO: AssetAtlas in mergeId 74415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); 74515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } else { 74615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 74715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 748b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 749b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 750268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) { 751f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik BakedOpState* bakedState = tryBakeOpState(op); 752f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!bakedState) return; // quick rejected 753f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 754f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 755f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 756268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) { 757f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik BakedOpState* bakedState = tryBakeOpState(op); 758f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!bakedState) return; // quick rejected 759f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 760f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 761f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 762268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { 763268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik // allocate a temporary oval op (with mAllocator, so it persists until render), so the 764268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. 765268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik float x = *(op.x); 766268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik float y = *(op.y); 767268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik float radius = *(op.radius); 768268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); 769268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik const OvalOp* resolvedOp = new (mAllocator) OvalOp( 770268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik unmappedBounds, 771268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik op.localMatrix, 772e4db79de127cfe961195f52907af8451026eaa20Chris Craik op.localClip, 773268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik op.paint); 774268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferOvalOp(*resolvedOp); 775268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik} 776268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik 777e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craikvoid OpReorderer::deferFunctorOp(const FunctorOp& op) { 778e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 779e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik if (!bakedState) return; // quick rejected 780d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); 781e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik} 782e29ce6f51d681af7649c0a7cddee97c471e43eb5Chris Craik 783268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferLinesOp(const LinesOp& op) { 784386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; 785268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); 786386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 787386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 788268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferOvalOp(const OvalOp& op) { 789268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, tessBatchId(op)); 790386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 791386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 792268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferPatchOp(const PatchOp& op) { 793f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik BakedOpState* bakedState = tryBakeOpState(op); 794f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (!bakedState) return; // quick rejected 795f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 796f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik if (bakedState->computedState.transform.isPureTranslate() 797f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) { 798f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); 799f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // TODO: AssetAtlas in mergeId 800f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 801f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together 802f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId); 803f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } else { 804f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik // Use Bitmap batchId since Bitmap+Patch use same shader 805f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); 806f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik } 807f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik} 808f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik 809268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferPathOp(const PathOp& op) { 810268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, OpBatchType::Bitmap); 811386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 812386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 813268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferPointsOp(const PointsOp& op) { 814386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; 815268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); 816268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik} 817268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik 818268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferRectOp(const RectOp& op) { 819268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, tessBatchId(op)); 820a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik} 821a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik 822268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferRoundRectOp(const RoundRectOp& op) { 823268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferStrokeableOp(op, tessBatchId(op)); 824386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik} 825386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik 826268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { 827268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik // allocate a temporary round rect op (with mAllocator, so it persists until render), so the 828268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. 829268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp( 830268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), 831268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik op.localMatrix, 832e4db79de127cfe961195f52907af8451026eaa20Chris Craik op.localClip, 833268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik op.paint, *op.rx, *op.ry); 834268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craik deferRoundRectOp(*resolvedOp); 835b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 836b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 837268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) { 83815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 83915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!bakedState) return; // quick rejected 84015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); 841b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 842b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 843d7448e65e243754f31890baef29dff187dc2e5e5Chris Craikstatic batchid_t textBatchId(const SkPaint& paint) { 844d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik // TODO: better handling of shader (since we won't care about color then) 845d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText; 846d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik} 847d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 848268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferTextOp(const TextOp& op) { 84915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 85015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (!bakedState) return; // quick rejected 851a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik 852d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik batchid_t batchId = textBatchId(*(op.paint)); 85315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik if (bakedState->computedState.transform.isPureTranslate() 85415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) { 85515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor()); 85615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId); 85715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } else { 85815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); 85915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik } 860a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik} 861a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik 862d7448e65e243754f31890baef29dff187dc2e5e5Chris Craikvoid OpReorderer::deferTextOnPathOp(const TextOnPathOp& op) { 863d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 864d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik if (!bakedState) return; // quick rejected 865d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint))); 866d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik} 867d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik 868d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craikvoid OpReorderer::deferTextureLayerOp(const TextureLayerOp& op) { 869d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik BakedOpState* bakedState = tryBakeOpState(op); 870d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik if (!bakedState) return; // quick rejected 871d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); 872d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik} 873d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik 8748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, 8758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik float contentTranslateX, float contentTranslateY, 8768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const Rect& repaintRect, 8778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik const Vector3& lightCenter, 8780b7e8245db728d127ada698be63d78b33fc6e4daChris Craik const BeginLayerOp* beginLayerOp, RenderNode* renderNode) { 8796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); 880818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight); 8816fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mCanvasState.writableSnapshot()->roundRectClipState = nullptr; 88298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter); 8838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.writableSnapshot()->transform->loadTranslate( 8848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik contentTranslateX, contentTranslateY, 0); 8858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik mCanvasState.writableSnapshot()->setClip( 8868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom); 88798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik 8888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // create a new layer repaint, and push its index on the stack 8896fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mLayerStack.push_back(mLayerReorderers.size()); 89098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik mLayerReorderers.emplace_back(layerWidth, layerHeight, repaintRect, beginLayerOp, renderNode); 891b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 892b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 8930b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::restoreForLayer() { 8940b7e8245db728d127ada698be63d78b33fc6e4daChris Craik // restore canvas, and pop finished layer off of the stack 8956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mCanvasState.restore(); 8960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik mLayerStack.pop_back(); 8970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik} 898b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 8990b7e8245db728d127ada698be63d78b33fc6e4daChris Craik// TODO: test rejection at defer time, where the bounds become empty 900268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { 9018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); 9028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); 9038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik auto previous = mCanvasState.currentSnapshot(); 9058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Vector3 lightCenter = previous->getRelativeLightCenter(); 9068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // Combine all transforms used to present saveLayer content: 9088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // parent content transform * canvas transform * bounds offset 9098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Matrix4 contentTransform(*previous->transform); 9108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik contentTransform.multiply(op.localMatrix); 9118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); 9128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Matrix4 inverseContentTransform; 9148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik inverseContentTransform.loadInverse(contentTransform); 9158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // map the light center into layer-relative space 9178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik inverseContentTransform.mapPoint3d(lightCenter); 9188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // Clip bounds of temporary layer to parent's clip rect, so: 9208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Rect saveLayerBounds(layerWidth, layerHeight); 9218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // 1) transform Rect(width, height) into parent's space 9228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // note: left/top offsets put in contentTransform above 9238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik contentTransform.mapRect(saveLayerBounds); 9248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // 2) intersect with parent's clip 9258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerBounds.doIntersect(previous->getRenderTargetClip()); 9268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // 3) and transform back 9278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik inverseContentTransform.mapRect(saveLayerBounds); 9288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); 9298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveLayerBounds.roundOut(); 9308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // if bounds are reduced, will clip the layer's area by reducing required bounds... 9328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik layerWidth = saveLayerBounds.getWidth(); 9338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik layerHeight = saveLayerBounds.getHeight(); 9348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik // ...and shifting drawing content to account for left/top side clipping 9358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik float contentTranslateX = -saveLayerBounds.left; 9368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik float contentTranslateY = -saveLayerBounds.top; 9378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik 9388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik saveForLayer(layerWidth, layerHeight, 9398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik contentTranslateX, contentTranslateY, 9408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik Rect(layerWidth, layerHeight), 9418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik lightCenter, 9428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik &op, nullptr); 9430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik} 9446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 945268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { 9460b7e8245db728d127ada698be63d78b33fc6e4daChris Craik const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; 9476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik int finishedLayerIndex = mLayerStack.back(); 9480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik 9490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik restoreForLayer(); 9506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 9516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // record the draw operation into the previous layer's list of draw commands 9526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // uses state from the associated beginLayerOp, since it has all the state needed for drawing 9536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik LayerOp* drawLayerOp = new (mAllocator) LayerOp( 9546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik beginLayerOp.unmappedBounds, 9556fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik beginLayerOp.localMatrix, 956e4db79de127cfe961195f52907af8451026eaa20Chris Craik beginLayerOp.localClip, 957818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik beginLayerOp.paint, 9585854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik &mLayerReorderers[finishedLayerIndex].offscreenBuffer); 9596fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); 9606fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik 9616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik if (bakedOpState) { 9626fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack) 9636fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); 9646fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik } else { 9656fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik // Layer won't be drawn - delete its drawing batches to prevent it from doing any work 9666fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik mLayerReorderers[finishedLayerIndex].clear(); 9676fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik return; 968b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik } 969b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 970b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 971268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferLayerOp(const LayerOp& op) { 9726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik LOG_ALWAYS_FATAL("unsupported"); 973b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} 974b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik 975268a9c0f29c16a64d5819c7dbe8b0633baedab83Chris Craikvoid OpReorderer::deferShadowOp(const ShadowOp& op) { 976d3daa3198e2212c985c634821682d5819346b653Chris Craik LOG_ALWAYS_FATAL("unsupported"); 977d3daa3198e2212c985c634821682d5819346b653Chris Craik} 978d3daa3198e2212c985c634821682d5819346b653Chris Craik 979b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} // namespace uirenderer 980b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} // namespace android 981