blob: a4e99504c125e6178262af58600349125386d380 [file] [log] [blame]
Chris Craikc3566d02013-02-04 16:16:33 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18#define ATRACE_TAG ATRACE_TAG_VIEW
19
20#include <utils/Trace.h>
21
22#include "Debug.h"
23#include "DisplayListOp.h"
24#include "OpenGLRenderer.h"
25
26#if DEBUG_DEFER
27 #define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
28#else
29 #define DEFER_LOGD(...)
30#endif
31
32namespace android {
33namespace uirenderer {
34
35class DrawOpBatch {
36public:
37 DrawOpBatch() {
38 mOps.clear();
39 }
40
41 ~DrawOpBatch() {
42 mOps.clear();
43 }
44
45 void add(DrawOp* op) {
46 // NOTE: ignore empty bounds special case, since we don't merge across those ops
47 mBounds.unionWith(op->state.mBounds);
48 mOps.add(op);
49 }
50
51 bool intersects(Rect& rect) {
52 if (!rect.intersects(mBounds)) return false;
53 for (unsigned int i = 0; i < mOps.size(); i++) {
54 if (rect.intersects(mOps[i]->state.mBounds)) {
55#if DEBUG_DEFER
56 DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
57 mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
58 mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
59 mOps[i]->output(2);
60#endif
61 return true;
62 }
63 }
64 return false;
65 }
66
67 Vector<DrawOp*> mOps;
68private:
69 Rect mBounds;
70};
71
72void DeferredDisplayList::clear() {
73 for (int i = 0; i < kOpBatch_Count; i++) {
74 mBatchIndices[i] = -1;
75 }
76 for (unsigned int i = 0; i < mBatches.size(); i++) {
77 delete mBatches[i];
78 }
79 mBatches.clear();
80}
81
82void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
83 if (CC_UNLIKELY(disallowReorder)) {
84 if (!mBatches.isEmpty()) {
85 mBatches[0]->add(op);
86 return;
87 }
88 DrawOpBatch* b = new DrawOpBatch();
89 b->add(op);
90 mBatches.add(b);
91 return;
92 }
93
94 // disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
95 // the new op into it
96 DrawOpBatch* targetBatch = NULL;
97 int batchId = op->getBatchId();
98
99 if (!mBatches.isEmpty()) {
100 if (op->state.mBounds.isEmpty()) {
101 // don't know the bounds for op, so add to last batch and start from scratch on next op
102 mBatches.top()->add(op);
103 for (int i = 0; i < kOpBatch_Count; i++) {
104 mBatchIndices[i] = -1;
105 }
106#if DEBUG_DEFER
107 DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
108 op->output(2);
109#endif
110 return;
111 }
112
113 if (batchId >= 0 && mBatchIndices[batchId] != -1) {
114 int targetIndex = mBatchIndices[batchId];
115 targetBatch = mBatches[targetIndex];
116 // iterate back toward target to see if anything drawn since should overlap the new op
117 for (int i = mBatches.size() - 1; i > targetIndex; i--) {
118 DrawOpBatch* overBatch = mBatches[i];
119 if (overBatch->intersects(op->state.mBounds)) {
120 targetBatch = NULL;
121#if DEBUG_DEFER
122 DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
123 targetIndex, i);
124 op->output(2);
125#endif
126 break;
127 }
128 }
129 }
130 }
131 if (!targetBatch) {
132 targetBatch = new DrawOpBatch();
133 mBatches.add(targetBatch);
134 if (batchId >= 0) {
135 mBatchIndices[batchId] = mBatches.size() - 1;
136 }
137 }
138 targetBatch->add(op);
139}
140
141status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
142 uint32_t level) {
143 ATRACE_CALL();
144 status_t status = DrawGlInfo::kStatusDone;
145
146 if (isEmpty()) return status; // nothing to flush
147
148 DEFER_LOGD("--flushing");
Romain Guy0f667532013-03-01 14:31:04 -0800149 renderer.eventMark("Flush");
150
Chris Craikc3566d02013-02-04 16:16:33 -0800151 DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
152 int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
153 int opCount = 0;
154 for (unsigned int i = 0; i < mBatches.size(); i++) {
155 DrawOpBatch* batch = mBatches[i];
156 for (unsigned int j = 0; j < batch->mOps.size(); j++) {
157 DrawOp* op = batch->mOps[j];
158
159 renderer.restoreDisplayState(op->state);
160
161#if DEBUG_DEFER
162 op->output(2);
163#endif
164 status |= op->applyDraw(renderer, dirty, level,
165 op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
166 opCount++;
167 }
168 }
169
170 DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
Romain Guy0f667532013-03-01 14:31:04 -0800171
Chris Craikc3566d02013-02-04 16:16:33 -0800172 renderer.restoreToCount(restoreTo);
173 renderer.setDrawModifiers(restoreDrawModifiers);
174 clear();
175 return status;
176}
177
178}; // namespace uirenderer
179}; // namespace android