FrameBuilder.cpp revision 0b7e8245db728d127ada698be63d78b33fc6e4da
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
19b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include "utils/PaintUtils.h"
20b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include "RenderNode.h"
210b7e8245db728d127ada698be63d78b33fc6e4daChris Craik#include "LayerUpdateQueue.h"
22b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
23b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include "SkCanvas.h"
24b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include "utils/Trace.h"
25b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
26b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android {
27b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer {
28b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass BatchBase {
30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic:
32b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
33b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        : mBatchId(batchId)
34b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        , mMerging(merging) {
35b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mBounds = op->computedState.clippedBounds;
36b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mOps.push_back(op);
37b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
38b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
39b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    bool intersects(const Rect& rect) const {
40b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (!rect.intersects(mBounds)) return false;
41b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
42b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        for (const BakedOpState* op : mOps) {
43b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (rect.intersects(op->computedState.clippedBounds)) {
44b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                return true;
45b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            }
46b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
47b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return false;
48b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
49b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
50b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    batchid_t getBatchId() const { return mBatchId; }
51b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    bool isMerging() const { return mMerging; }
52b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
53b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    const std::vector<BakedOpState*>& getOps() const { return mOps; }
54b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
55b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    void dump() const {
566fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        ALOGD("    Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                this, mBatchId, mMerging, mOps.size(), RECT_ARGS(mBounds));
58b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
59b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikprotected:
60b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    batchid_t mBatchId;
61b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    Rect mBounds;
62b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    std::vector<BakedOpState*> mOps;
63b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    bool mMerging;
64b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik};
65b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
66b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass OpBatch : public BatchBase {
67b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic:
68b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static void* operator new(size_t size, LinearAllocator& allocator) {
69b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return allocator.alloc(size);
70b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
71b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
72b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    OpBatch(batchid_t batchId, BakedOpState* op)
73b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            : BatchBase(batchId, op, false) {
74b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
75b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
76b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    void batchOp(BakedOpState* op) {
77b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mBounds.unionWith(op->computedState.clippedBounds);
78b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mOps.push_back(op);
79b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
80b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik};
81b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
82b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikclass MergingOpBatch : public BatchBase {
83b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikpublic:
84b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static void* operator new(size_t size, LinearAllocator& allocator) {
85b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return allocator.alloc(size);
86b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
87b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
88b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    MergingOpBatch(batchid_t batchId, BakedOpState* op)
89b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            : BatchBase(batchId, op, true) {
90b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
91b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
92b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    /*
93b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
94b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * and clip side flags. Positive bounds delta means new bounds fit in old.
95b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     */
96b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
97b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            float boundsDelta) {
98b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        bool currentClipExists = currentFlags & side;
99b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        bool newClipExists = newFlags & side;
100b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
101b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // if current is clipped, we must be able to fit new bounds in current
102b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (boundsDelta > 0 && currentClipExists) return false;
103b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
104b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // if new is clipped, we must be able to fit current bounds in new
105b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (boundsDelta < 0 && newClipExists) return false;
106b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
107b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return true;
108b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
109b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
110b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static bool paintIsDefault(const SkPaint& paint) {
111b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return paint.getAlpha() == 255
112b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                && paint.getColorFilter() == nullptr
113b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                && paint.getShader() == nullptr;
114b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
115b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
116b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
117b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return a.getAlpha() == b.getAlpha()
118b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                && a.getColorFilter() == b.getColorFilter()
119b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                && a.getShader() == b.getShader();
120b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
121b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
122b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    /*
123b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * Checks if a (mergeable) op can be merged into this batch
124b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     *
125b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is
126b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * important to consider all paint attributes used in the draw calls in deciding both a) if an
127b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * op tries to merge at all, and b) if the op can merge with another set of ops
128b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     *
129b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * False positives can lead to information from the paints of subsequent merged operations being
130b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     * dropped, so we make simplifying qualifications on the ops that can merge, per op type.
131b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik     */
132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    bool canMergeWith(BakedOpState* op) const {
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        bool isTextBatch = getBatchId() == OpBatchType::Text
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik                || getBatchId() == OpBatchType::ColorText;
135b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
136b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Overlapping other operations is only allowed for text without shadow. For other ops,
137b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // multiDraw isn't guaranteed to overdraw correctly
138b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) {
139b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (intersects(op->computedState.clippedBounds)) return false;
140b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
141b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
142b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const BakedOpState* lhs = op;
143b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const BakedOpState* rhs = mOps[0];
144b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
145b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false;
146b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
147b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Identical round rect clip state means both ops will clip in the same way, or not at all.
148b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // As the state objects are const, we can compare their pointers to determine mergeability
149b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
150b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (lhs->projectionPathMask != rhs->projectionPathMask) return false;
151b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
152b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        /* Clipping compatibility check
153b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik         *
154b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik         * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its
155b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik         * clip for that side.
156b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik         */
157b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const int currentFlags = mClipSideFlags;
158b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const int newFlags = op->computedState.clipSideFlags;
159b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
160b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            const Rect& opBounds = op->computedState.clippedBounds;
161b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            float boundsDelta = mBounds.left - opBounds.left;
162b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
163b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            boundsDelta = mBounds.top - opBounds.top;
164b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
165b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
166b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            // right and bottom delta calculation reversed to account for direction
167b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            boundsDelta = opBounds.right - mBounds.right;
168b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
169b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            boundsDelta = opBounds.bottom - mBounds.bottom;
170b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
171b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
172b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
173b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const SkPaint* newPaint = op->op->paint;
174b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const SkPaint* oldPaint = mOps[0]->op->paint;
175b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
176b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (newPaint == oldPaint) {
177b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            // if paints are equal, then modifiers + paint attribs don't need to be compared
178b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            return true;
179b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        } else if (newPaint && !oldPaint) {
180b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            return paintIsDefault(*newPaint);
181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        } else if (!newPaint && oldPaint) {
182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            return paintIsDefault(*oldPaint);
183b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
184b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return paintsAreEquivalent(*newPaint, *oldPaint);
185b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
186b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
187b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    void mergeOp(BakedOpState* op) {
188b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mBounds.unionWith(op->computedState.clippedBounds);
189b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mOps.push_back(op);
190b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
191b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const int newClipSideFlags = op->computedState.clipSideFlags;
192b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        mClipSideFlags |= newClipSideFlags;
193b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
194b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        const Rect& opClip = op->computedState.clipRect;
195b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left;
196b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top;
197b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right;
198b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom;
199b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikprivate:
202b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    int mClipSideFlags = 0;
203b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    Rect mClipRect;
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik};
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
2060b7e8245db728d127ada698be63d78b33fc6e4daChris CraikOpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height,
2070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
2080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        : width(width)
2090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        , height(height)
2100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr)
2110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        , beginLayerOp(beginLayerOp)
2120b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        , renderNode(renderNode) {}
2130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
2146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// iterate back toward target to see if anything drawn since should overlap the new op
215818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik// if no target, merging ops still iterate to find similar batch to insert after
2166fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
2176fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        BatchBase** targetBatch, size_t* insertBatchIndex) const {
2186fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    for (int i = mBatches.size() - 1; i >= 0; i--) {
2196fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        BatchBase* overBatch = mBatches[i];
2206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2216fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        if (overBatch == *targetBatch) break;
2226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // TODO: also consider shader shared between batch types
2246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        if (batchId == overBatch->getBatchId()) {
2256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            *insertBatchIndex = i + 1;
2266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            if (!*targetBatch) break; // found insert position, quit
2276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
2286fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2296fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        if (overBatch->intersects(clippedBounds)) {
2306fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            // NOTE: it may be possible to optimize for special cases where two operations
2316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            // of the same batch/paint could swap order, such as with a non-mergeable
2326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            // (clipped) and a mergeable text operation
2336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            *targetBatch = nullptr;
2346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            break;
2356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
2366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
2386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator,
2406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        BakedOpState* op, batchid_t batchId) {
2416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    OpBatch* targetBatch = mBatchLookup[batchId];
2426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    size_t insertBatchIndex = mBatches.size();
2446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    if (targetBatch) {
2456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        locateInsertIndex(batchId, op->computedState.clippedBounds,
2466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                (BatchBase**)(&targetBatch), &insertBatchIndex);
2476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    if (targetBatch) {
2506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        targetBatch->batchOp(op);
2516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    } else  {
2526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // new non-merging batch
2536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        targetBatch = new (allocator) OpBatch(batchId, op);
2546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        mBatchLookup[batchId] = targetBatch;
2556fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
2566fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
2586fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2596fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// insertion point of a new batch, will hopefully be immediately after similar batch
2606fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik// (generally, should be similar shader)
2616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator,
2626fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
2636fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    MergingOpBatch* targetBatch = nullptr;
2646fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2656fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // Try to merge with any existing batch with same mergeId
2666fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    auto getResult = mMergingBatchLookup[batchId].find(mergeId);
2676fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    if (getResult != mMergingBatchLookup[batchId].end()) {
2686fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        targetBatch = getResult->second;
2696fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        if (!targetBatch->canMergeWith(op)) {
2706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            targetBatch = nullptr;
2716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
2726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    size_t insertBatchIndex = mBatches.size();
2756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    locateInsertIndex(batchId, op->computedState.clippedBounds,
2766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            (BatchBase**)(&targetBatch), &insertBatchIndex);
2776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    if (targetBatch) {
2796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        targetBatch->mergeOp(op);
2806fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    } else  {
2816fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // new merging batch
2826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        targetBatch = new (allocator) MergingOpBatch(batchId, op);
2836fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
2846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2856fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
2866fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2876fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
2886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikvoid OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const {
2905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ATRACE_NAME("flush drawing commands");
2916fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    for (const BatchBase* batch : mBatches) {
2926fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // TODO: different behavior based on batch->isMerging()
2936fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        for (const BakedOpState* op : batch->getOps()) {
2946fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            receivers[op->op->opId](arg, *op->op, *op);
2956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
2966fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
2976fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
2986fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
2996fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::LayerReorderer::dump() const {
3000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p",
3010b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            this, width, height, offscreenBuffer, beginLayerOp, renderNode);
3026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    for (const BatchBase* batch : mBatches) {
3036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        batch->dump();
3046fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
3056fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
306b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3070b7e8245db728d127ada698be63d78b33fc6e4daChris CraikOpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
3080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        uint32_t viewportWidth, uint32_t viewportHeight,
309818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik        const std::vector< sp<RenderNode> >& nodes)
3106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        : mCanvasState(*this) {
311818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik    ATRACE_NAME("prepare drawing commands");
312818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
3130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        mLayerStack.push_back(0);
3146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
315b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
316ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik            clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
317ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik            Vector3());
3180b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
3190b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // Render all layers to be updated, in order. Defer in reverse order, so that they'll be
3200b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // updated in the order they're passed in (mLayerReorderers are issued to Renderer in reverse)
3210b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    for (int i = layers.entries().size() - 1; i >= 0; i--) {
3220b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        RenderNode* layerNode = layers.entries()[i].renderNode;
3230b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        const Rect& layerDamage = layers.entries()[i].damage;
3240b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
3250b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        saveForLayer(layerNode->getWidth(), layerNode->getHeight(), nullptr, layerNode);
3260b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        mCanvasState.writableSnapshot()->setClip(
3270b7e8245db728d127ada698be63d78b33fc6e4daChris Craik                layerDamage.left, layerDamage.top, layerDamage.right, layerDamage.bottom);
3280b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
3290b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        if (layerNode->getDisplayList()) {
3300b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            deferImpl(*(layerNode->getDisplayList()));
3310b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        }
3320b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        restoreForLayer();
3330b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    }
3340b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
3350b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // Defer Fbo0
336b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    for (const sp<RenderNode>& node : nodes) {
337b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        if (node->nothingToDraw()) continue;
338b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3390b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
3400b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        deferNodePropsAndOps(*node);
3410b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        mCanvasState.restoreToCount(count);
342b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
343b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
344b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
345818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris CraikOpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
346818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik        : mCanvasState(*this) {
347b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    ATRACE_NAME("prepare drawing commands");
348818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik
349818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
350818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik    mLayerStack.push_back(0);
351818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik
352b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
353b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            0, 0, viewportWidth, viewportHeight, Vector3());
354b36af87f8275f4b982906f88193ec27600f2746aChris Craik    deferImpl(displayList);
355b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
356b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
357818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craikvoid OpReorderer::onViewportInitialized() {}
358818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik
359818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craikvoid OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
360818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik
3610b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::deferNodePropsAndOps(RenderNode& node) {
3620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    if (node.applyViewProperties(mCanvasState)) {
3630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        // not rejected so render
3640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        if (node.getLayer()) {
3650b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            // HW layer
3660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
3670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
3680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            if (bakedOpState) {
3690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik                // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
3700b7e8245db728d127ada698be63d78b33fc6e4daChris Craik                currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
3710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            }
3720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        } else {
3730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            deferImpl(*(node.getDisplayList()));
3740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        }
3750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    }
3760b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
3770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
378b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/**
379b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
380b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
381b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. E.g. a
382b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&)
383b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */
3846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik#define OP_RECEIVER(Type) \
385b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
386b36af87f8275f4b982906f88193ec27600f2746aChris Craikvoid OpReorderer::deferImpl(const DisplayList& displayList) {
387b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
3886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        MAP_OPS(OP_RECEIVER)
389b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    };
390b36af87f8275f4b982906f88193ec27600f2746aChris Craik    for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
391b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
392b36af87f8275f4b982906f88193ec27600f2746aChris Craik            const RecordedOp* op = displayList.getOps()[opIndex];
393b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            receivers[op->opId](*this, *op);
394b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
395b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
396b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
397b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
398b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikvoid OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
399b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    if (op.renderNode->nothingToDraw()) {
400b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        return;
401b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
4026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
403b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
404b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    // apply state from RecordedOp
405b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    mCanvasState.concatMatrix(op.localMatrix);
406b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
407b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
408b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // then apply state from node properties, and defer ops
4100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    deferNodePropsAndOps(*op.renderNode);
4110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
4126fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mCanvasState.restoreToCount(count);
413b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
414b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
415b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikstatic batchid_t tessellatedBatchId(const SkPaint& paint) {
416b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    return paint.getPathEffect()
417b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            ? OpBatchType::AlphaMaskTexture
418b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
419b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
420b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
421b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikvoid OpReorderer::onBitmapOp(const BitmapOp& op) {
4226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    BakedOpState* bakedStateOp = tryBakeOpState(op);
423b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    if (!bakedStateOp) return; // quick rejected
424b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
425b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
426b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    // TODO: AssetAtlas
4276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    currentLayer().deferMergeableOp(mAllocator, bakedStateOp, OpBatchType::Bitmap, mergeId);
428b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
429b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
430b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikvoid OpReorderer::onRectOp(const RectOp& op) {
4316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    BakedOpState* bakedStateOp = tryBakeOpState(op);
432b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    if (!bakedStateOp) return; // quick rejected
4336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, tessellatedBatchId(*op.paint));
434b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
435b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
436b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craikvoid OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) {
4376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    BakedOpState* bakedStateOp = tryBakeOpState(op);
438b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    if (!bakedStateOp) return; // quick rejected
4396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices);
440b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
441b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4420b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
4430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
444818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik
4456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
4466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mCanvasState.writableSnapshot()->transform->loadIdentity();
447818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik    mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
4486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
4496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
4506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // create a new layer, and push its index on the stack
4516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mLayerStack.push_back(mLayerReorderers.size());
4520b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    mLayerReorderers.emplace_back(layerWidth, layerHeight, beginLayerOp, renderNode);
453b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
454b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4550b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::restoreForLayer() {
4560b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // restore canvas, and pop finished layer off of the stack
4576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    mCanvasState.restore();
4580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    mLayerStack.pop_back();
4590b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
460b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4610b7e8245db728d127ada698be63d78b33fc6e4daChris Craik// TODO: test rejection at defer time, where the bounds become empty
4620b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
4630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    const uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
4640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    const uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
4650b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    saveForLayer(layerWidth, layerHeight, &op, nullptr);
4660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
4676fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
4680b7e8245db728d127ada698be63d78b33fc6e4daChris Craikvoid OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
4690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
4706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    int finishedLayerIndex = mLayerStack.back();
4710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
4720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    restoreForLayer();
4736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
4746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // record the draw operation into the previous layer's list of draw commands
4756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // uses state from the associated beginLayerOp, since it has all the state needed for drawing
4766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    LayerOp* drawLayerOp = new (mAllocator) LayerOp(
4776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            beginLayerOp.unmappedBounds,
4786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            beginLayerOp.localMatrix,
4796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            beginLayerOp.localClipRect,
480818c9fbf1d76d5df19253ba4eb964efa939ec9ecChris Craik            beginLayerOp.paint,
4815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik            &mLayerReorderers[finishedLayerIndex].offscreenBuffer);
4826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
4836fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
4846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    if (bakedOpState) {
4856fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
4866fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
4876fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    } else {
4886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // Layer won't be drawn - delete its drawing batches to prevent it from doing any work
4896fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        mLayerReorderers[finishedLayerIndex].clear();
4906fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        return;
491b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    }
492b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
493b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4946fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikvoid OpReorderer::onLayerOp(const LayerOp& op) {
4956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    LOG_ALWAYS_FATAL("unsupported");
496b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
497b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
498b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} // namespace uirenderer
499b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik} // namespace android
500