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