15ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik/* 25ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Copyright (C) 2016 The Android Open Source Project 35ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 45ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Licensed under the Apache License, Version 2.0 (the "License"); 55ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * you may not use this file except in compliance with the License. 65ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * You may obtain a copy of the License at 75ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 85ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * http://www.apache.org/licenses/LICENSE-2.0 95ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 105ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Unless required by applicable law or agreed to in writing, software 115ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * distributed under the License is distributed on an "AS IS" BASIS, 125ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * See the License for the specific language governing permissions and 145ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * limitations under the License. 155ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik */ 165ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 17f158b49c888f722194afe5a80539a2b020c130bcChris Craik#include "LayerBuilder.h" 185ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 195ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik#include "BakedOpState.h" 205ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik#include "RenderNode.h" 215ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik#include "utils/PaintUtils.h" 225ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik#include "utils/TraceUtils.h" 235ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 245ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik#include <utils/TypeHelpers.h> 255ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 265ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craiknamespace android { 275ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craiknamespace uirenderer { 285ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 295ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikclass BatchBase { 305ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikpublic: 315ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BatchBase(batchid_t batchId, BakedOpState* op, bool merging) 325ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik : mBatchId(batchId) 335ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , mMerging(merging) { 345ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBounds = op->computedState.clippedBounds; 355ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mOps.push_back(op); 365ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 375ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 385ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool intersects(const Rect& rect) const { 395ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!rect.intersects(mBounds)) return false; 405ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 415ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (const BakedOpState* op : mOps) { 425ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (rect.intersects(op->computedState.clippedBounds)) { 435ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return true; 445ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 455ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 465ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return false; 475ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 485ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 495ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik batchid_t getBatchId() const { return mBatchId; } 505ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool isMerging() const { return mMerging; } 515ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 525ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const std::vector<BakedOpState*>& getOps() const { return mOps; } 535ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 545ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik void dump() const { 555ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, 56b250a834e433b4f483e8d8362a6fda8d6594c7b8Chris Craik this, mBatchId, mMerging, (int) mOps.size(), RECT_ARGS(mBounds)); 575ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 585ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikprotected: 595ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik batchid_t mBatchId; 605ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Rect mBounds; 615ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik std::vector<BakedOpState*> mOps; 625ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool mMerging; 635ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik}; 645ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 655ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikclass OpBatch : public BatchBase { 665ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikpublic: 675ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik OpBatch(batchid_t batchId, BakedOpState* op) 685ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik : BatchBase(batchId, op, false) { 695ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 705ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 715ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik void batchOp(BakedOpState* op) { 725ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBounds.unionWith(op->computedState.clippedBounds); 735ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mOps.push_back(op); 745ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 755ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik}; 765ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 775ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikclass MergingOpBatch : public BatchBase { 785ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikpublic: 795ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik MergingOpBatch(batchid_t batchId, BakedOpState* op) 805ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik : BatchBase(batchId, op, true) 815ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , mClipSideFlags(op->computedState.clipSideFlags) { 825ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 835ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 845ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik /* 855ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds 865ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * and clip side flags. Positive bounds delta means new bounds fit in old. 875ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik */ 885ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik static inline bool checkSide(const int currentFlags, const int newFlags, const int side, 895ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik float boundsDelta) { 905ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool currentClipExists = currentFlags & side; 915ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool newClipExists = newFlags & side; 925ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 935ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // if current is clipped, we must be able to fit new bounds in current 945ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (boundsDelta > 0 && currentClipExists) return false; 955ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 965ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // if new is clipped, we must be able to fit current bounds in new 975ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (boundsDelta < 0 && newClipExists) return false; 985ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 995ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return true; 1005ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1015ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1025ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik static bool paintIsDefault(const SkPaint& paint) { 1035ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return paint.getAlpha() == 255 1045ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik && paint.getColorFilter() == nullptr 1055ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik && paint.getShader() == nullptr; 1065ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1075ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1085ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) { 1095ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Note: don't check color, since all currently mergeable ops can merge across colors 1105ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return a.getAlpha() == b.getAlpha() 1115ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik && a.getColorFilter() == b.getColorFilter() 1125ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik && a.getShader() == b.getShader(); 1135ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1145ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1155ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik /* 1165ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Checks if a (mergeable) op can be merged into this batch 1175ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 1185ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is 1195ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * important to consider all paint attributes used in the draw calls in deciding both a) if an 1205ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * op tries to merge at all, and b) if the op can merge with another set of ops 1215ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 1225ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * False positives can lead to information from the paints of subsequent merged operations being 1235ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * dropped, so we make simplifying qualifications on the ops that can merge, per op type. 1245ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik */ 1255ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool canMergeWith(BakedOpState* op) const { 1265ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bool isTextBatch = getBatchId() == OpBatchType::Text 1275ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik || getBatchId() == OpBatchType::ColorText; 1285ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1295ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Overlapping other operations is only allowed for text without shadow. For other ops, 1305ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // multiDraw isn't guaranteed to overdraw correctly 1315ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { 1325ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (intersects(op->computedState.clippedBounds)) return false; 1335ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1345ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1355ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const BakedOpState* lhs = op; 1365ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const BakedOpState* rhs = mOps[0]; 1375ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1385ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; 1395ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1405ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Identical round rect clip state means both ops will clip in the same way, or not at all. 1415ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // As the state objects are const, we can compare their pointers to determine mergeability 1425ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (lhs->roundRectClipState != rhs->roundRectClipState) return false; 143678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik 144678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik // Local masks prevent merge, since they're potentially in different coordinate spaces 145678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik if (lhs->computedState.localProjectionPathMask 146678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik || rhs->computedState.localProjectionPathMask) return false; 1475ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1485ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik /* Clipping compatibility check 1495ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * 1505ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its 1515ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * clip for that side. 1525ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik */ 1535ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const int currentFlags = mClipSideFlags; 1545ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const int newFlags = op->computedState.clipSideFlags; 1555ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { 1565ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const Rect& opBounds = op->computedState.clippedBounds; 1575ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik float boundsDelta = mBounds.left - opBounds.left; 1585ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false; 1595ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik boundsDelta = mBounds.top - opBounds.top; 1605ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; 1615ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1625ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // right and bottom delta calculation reversed to account for direction 1635ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik boundsDelta = opBounds.right - mBounds.right; 1645ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false; 1655ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik boundsDelta = opBounds.bottom - mBounds.bottom; 1665ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false; 1675ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1685ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1695ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const SkPaint* newPaint = op->op->paint; 1705ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const SkPaint* oldPaint = mOps[0]->op->paint; 1715ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1725ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (newPaint == oldPaint) { 1735ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // if paints are equal, then modifiers + paint attribs don't need to be compared 1745ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return true; 1755ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } else if (newPaint && !oldPaint) { 1765ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return paintIsDefault(*newPaint); 1775ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } else if (!newPaint && oldPaint) { 1785ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return paintIsDefault(*oldPaint); 1795ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1805ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik return paintsAreEquivalent(*newPaint, *oldPaint); 1815ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1825ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1835ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik void mergeOp(BakedOpState* op) { 1845ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBounds.unionWith(op->computedState.clippedBounds); 1855ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mOps.push_back(op); 1865ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1875ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat 1885ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // check, and doesn't extend past a side of the clip that's in use by the merged batch. 1895ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. 1905ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mClipSideFlags |= op->computedState.clipSideFlags; 1915ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 1925ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1935ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik int getClipSideFlags() const { return mClipSideFlags; } 1945ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const Rect& getClipRect() const { return mBounds; } 1955ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 1965ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craikprivate: 1975ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik int mClipSideFlags; 1985ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik}; 1995ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 200f158b49c888f722194afe5a80539a2b020c130bcChris CraikLayerBuilder::LayerBuilder(uint32_t width, uint32_t height, 2015ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode) 2025ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik : width(width) 2035ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , height(height) 2045ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , repaintRect(repaintRect) 2054876de16e34622634266d09522c9153c78c7c2fbChris Craik , repaintClip(repaintRect) 2065ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) 2075ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik , beginLayerOp(beginLayerOp) 2084876de16e34622634266d09522c9153c78c7c2fbChris Craik , renderNode(renderNode) {} 2095ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2105ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik// iterate back toward target to see if anything drawn since should overlap the new op 2115ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik// if no target, merging ops still iterate to find similar batch to insert after 212f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds, 2135ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BatchBase** targetBatch, size_t* insertBatchIndex) const { 2145ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (int i = mBatches.size() - 1; i >= 0; i--) { 2155ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BatchBase* overBatch = mBatches[i]; 2165ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2175ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (overBatch == *targetBatch) break; 2185ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2195ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // TODO: also consider shader shared between batch types 2205ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (batchId == overBatch->getBatchId()) { 2215ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik *insertBatchIndex = i + 1; 2225ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!*targetBatch) break; // found insert position, quit 2235ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2245ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2255ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (overBatch->intersects(clippedBounds)) { 2265ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // NOTE: it may be possible to optimize for special cases where two operations 2275ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // of the same batch/paint could swap order, such as with a non-mergeable 2285ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // (clipped) and a mergeable text operation 2295ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik *targetBatch = nullptr; 2305ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik break; 2315ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2325ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2335ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 2345ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 235f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::deferLayerClear(const Rect& rect) { 2365ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mClearRects.push_back(rect); 2375ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 2385ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 23980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craikvoid LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState) { 24080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (bakedState->op->opId != RecordedOpId::CopyToLayerOp) { 24180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // First non-CopyToLayer, so stop stashing up layer clears for unclipped save layers, 24280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // and issue them together in one draw. 24380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik flushLayerClears(allocator); 24480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 24580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik if (CC_UNLIKELY(activeUnclippedSaveLayers.empty() 24680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik && bakedState->computedState.opaqueOverClippedBounds 2479cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik && bakedState->computedState.clippedBounds.contains(repaintRect) 2489cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik && !Properties::debugOverdraw)) { 24980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik // discard all deferred drawing ops, since new one will occlude them 25080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik clear(); 25180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik } 25280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik } 25380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 25480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 255f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::flushLayerClears(LinearAllocator& allocator) { 2565ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (CC_UNLIKELY(!mClearRects.empty())) { 2575ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const int vertCount = mClearRects.size() * 4; 2585ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // put the verts in the frame allocator, since 2595ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // 1) SimpleRectsOps needs verts, not rects 2605ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // 2) even if mClearRects stored verts, std::vectors will move their contents 2617a89600bac7ab889a5ba8a994c57d677de0e45d5Chris Craik Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount); 2625ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2635ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Vertex* currentVert = verts; 2645ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Rect bounds = mClearRects[0]; 2655ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (auto&& rect : mClearRects) { 2665ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik bounds.unionWith(rect); 2675ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Vertex::set(currentVert++, rect.left, rect.top); 2685ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Vertex::set(currentVert++, rect.right, rect.top); 2695ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Vertex::set(currentVert++, rect.left, rect.bottom); 2705ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Vertex::set(currentVert++, rect.right, rect.bottom); 2715ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2725ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mClearRects.clear(); // discard rects before drawing so this method isn't reentrant 2735ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2745ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // One or more unclipped saveLayers have been enqueued, with deferred clears. 2755ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Flush all of these clears with a single draw 2765ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik SkPaint* paint = allocator.create<SkPaint>(); 2775ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik paint->setXfermodeMode(SkXfermode::kClear_Mode); 2787df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds, 2795ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik Matrix4::identity(), nullptr, paint, 2805ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik verts, vertCount); 2815ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BakedOpState* bakedState = BakedOpState::directConstruct(allocator, 2824876de16e34622634266d09522c9153c78c7c2fbChris Craik &repaintClip, bounds, *op); 2835ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices); 2845ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2855ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 2865ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 287f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator, 2885ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BakedOpState* op, batchid_t batchId) { 28980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik onDeferOp(allocator, op); 2905ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik OpBatch* targetBatch = mBatchLookup[batchId]; 2915ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2925ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik size_t insertBatchIndex = mBatches.size(); 2935ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (targetBatch) { 2945ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik locateInsertIndex(batchId, op->computedState.clippedBounds, 2955ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik (BatchBase**)(&targetBatch), &insertBatchIndex); 2965ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 2975ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 2985ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (targetBatch) { 2995ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik targetBatch->batchOp(op); 3005ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } else { 3015ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // new non-merging batch 3027df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck targetBatch = allocator.create<OpBatch>(batchId, op); 3035ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBatchLookup[batchId] = targetBatch; 3045ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); 3055ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3065ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 3075ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 308f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::deferMergeableOp(LinearAllocator& allocator, 3095ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BakedOpState* op, batchid_t batchId, mergeid_t mergeId) { 31080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik onDeferOp(allocator, op); 3115ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik MergingOpBatch* targetBatch = nullptr; 3125ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 3135ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // Try to merge with any existing batch with same mergeId 3145ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik auto getResult = mMergingBatchLookup[batchId].find(mergeId); 3155ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (getResult != mMergingBatchLookup[batchId].end()) { 3165ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik targetBatch = getResult->second; 3175ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (!targetBatch->canMergeWith(op)) { 3185ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik targetBatch = nullptr; 3195ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3205ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3215ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 3225ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik size_t insertBatchIndex = mBatches.size(); 3235ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik locateInsertIndex(batchId, op->computedState.clippedBounds, 3245ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik (BatchBase**)(&targetBatch), &insertBatchIndex); 3255ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 3265ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (targetBatch) { 3275ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik targetBatch->mergeOp(op); 3285ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } else { 3295ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik // new merging batch 3307df9ff2a08fd4bbd9b2e734a357cffcf64675df9John Reck targetBatch = allocator.create<MergingOpBatch>(batchId, op); 3315ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch)); 3325ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 3335ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); 3345ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3355ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 3365ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 337f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::replayBakedOpsImpl(void* arg, 3385ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const { 339aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik if (renderNode) { 340aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u", 341aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik renderNode->getName(), width, height); 342aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik } else { 343aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik ATRACE_BEGIN("flush drawing commands"); 344aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik } 345aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik 3465ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (const BatchBase* batch : mBatches) { 3475ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik size_t size = batch->getOps().size(); 3485ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik if (size > 1 && batch->isMerging()) { 3495ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik int opId = batch->getOps()[0]->op->opId; 3505ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch); 3515ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik MergedBakedOpList data = { 3525ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik batch->getOps().data(), 3535ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik size, 3545ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mergingBatch->getClipSideFlags(), 3555ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mergingBatch->getClipRect() 3565ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik }; 3575ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik mergedReceivers[opId](arg, data); 3585ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } else { 3595ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (const BakedOpState* op : batch->getOps()) { 3605ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik unmergedReceivers[op->op->opId](arg, *op); 3615ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3625ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3635ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 364aff230f6f9f9e44a5e111ba3f087d03f7a0e24f3Chris Craik ATRACE_END(); 3655ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 3665ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 36780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craikvoid LayerBuilder::clear() { 36880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik mBatches.clear(); 36980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik for (int i = 0; i < OpBatchType::Count; i++) { 37080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik mBatchLookup[i] = nullptr; 37180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik mMergingBatchLookup[i].clear(); 37280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik } 37380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik} 37480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik 375f158b49c888f722194afe5a80539a2b020c130bcChris Craikvoid LayerBuilder::dump() const { 37602806288d1c56475413888a934c796e6e4eb11c5Chris Craik ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)", 37702806288d1c56475413888a934c796e6e4eb11c5Chris Craik this, width, height, offscreenBuffer, beginLayerOp, 37802806288d1c56475413888a934c796e6e4eb11c5Chris Craik renderNode, renderNode ? renderNode->getName() : "-"); 3795ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik for (const BatchBase* batch : mBatches) { 3805ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik batch->dump(); 3815ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik } 3825ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} 3835ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik 3845ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} // namespace uirenderer 3855ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik} // namespace android 386