summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/DeferredDisplayList.cpp176
-rw-r--r--libs/hwui/DeferredDisplayList.h78
-rw-r--r--libs/hwui/DisplayList.cpp24
-rw-r--r--libs/hwui/DisplayList.h4
-rw-r--r--libs/hwui/DisplayListOp.h158
-rw-r--r--libs/hwui/DisplayListRenderer.cpp3
-rw-r--r--libs/hwui/DisplayListRenderer.h8
-rw-r--r--libs/hwui/OpenGLRenderer.cpp178
-rw-r--r--libs/hwui/OpenGLRenderer.h71
-rw-r--r--libs/hwui/Properties.h13
-rw-r--r--libs/hwui/Rect.h7
13 files changed, 621 insertions, 103 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index affb4d0..33d8063 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -12,6 +12,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
GammaFontRenderer.cpp \
Caches.cpp \
DisplayList.cpp \
+ DeferredDisplayList.cpp \
DisplayListLogBuffer.cpp \
DisplayListRenderer.cpp \
Dither.cpp \
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 20eb5e1..9a6494f 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -74,6 +74,9 @@
// Turn on to enable additional debugging in the font renderers
#define DEBUG_FONT_RENDERER 0
+// Turn on to log draw operation batching and deferral information
+#define DEBUG_DEFER 0
+
// Turn on to dump display list state
#define DEBUG_DISPLAY_LIST 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
new file mode 100644
index 0000000..8962964
--- /dev/null
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/Trace.h>
+
+#include "Debug.h"
+#include "DisplayListOp.h"
+#include "OpenGLRenderer.h"
+
+#if DEBUG_DEFER
+ #define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+ #define DEFER_LOGD(...)
+#endif
+
+namespace android {
+namespace uirenderer {
+
+class DrawOpBatch {
+public:
+ DrawOpBatch() {
+ mOps.clear();
+ }
+
+ ~DrawOpBatch() {
+ mOps.clear();
+ }
+
+ void add(DrawOp* op) {
+ // NOTE: ignore empty bounds special case, since we don't merge across those ops
+ mBounds.unionWith(op->state.mBounds);
+ mOps.add(op);
+ }
+
+ bool intersects(Rect& rect) {
+ if (!rect.intersects(mBounds)) return false;
+ for (unsigned int i = 0; i < mOps.size(); i++) {
+ if (rect.intersects(mOps[i]->state.mBounds)) {
+#if DEBUG_DEFER
+ DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i],
+ mOps[i]->state.mBounds.left, mOps[i]->state.mBounds.top,
+ mOps[i]->state.mBounds.right, mOps[i]->state.mBounds.bottom);
+ mOps[i]->output(2);
+#endif
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Vector<DrawOp*> mOps;
+private:
+ Rect mBounds;
+};
+
+void DeferredDisplayList::clear() {
+ for (int i = 0; i < kOpBatch_Count; i++) {
+ mBatchIndices[i] = -1;
+ }
+ for (unsigned int i = 0; i < mBatches.size(); i++) {
+ delete mBatches[i];
+ }
+ mBatches.clear();
+}
+
+void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
+ if (CC_UNLIKELY(disallowReorder)) {
+ if (!mBatches.isEmpty()) {
+ mBatches[0]->add(op);
+ return;
+ }
+ DrawOpBatch* b = new DrawOpBatch();
+ b->add(op);
+ mBatches.add(b);
+ return;
+ }
+
+ // disallowReorder isn't set, so find the latest batch of the new op's type, and try to merge
+ // the new op into it
+ DrawOpBatch* targetBatch = NULL;
+ int batchId = op->getBatchId();
+
+ if (!mBatches.isEmpty()) {
+ if (op->state.mBounds.isEmpty()) {
+ // don't know the bounds for op, so add to last batch and start from scratch on next op
+ mBatches.top()->add(op);
+ for (int i = 0; i < kOpBatch_Count; i++) {
+ mBatchIndices[i] = -1;
+ }
+#if DEBUG_DEFER
+ DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches");
+ op->output(2);
+#endif
+ return;
+ }
+
+ if (batchId >= 0 && mBatchIndices[batchId] != -1) {
+ int targetIndex = mBatchIndices[batchId];
+ targetBatch = mBatches[targetIndex];
+ // iterate back toward target to see if anything drawn since should overlap the new op
+ for (int i = mBatches.size() - 1; i > targetIndex; i--) {
+ DrawOpBatch* overBatch = mBatches[i];
+ if (overBatch->intersects(op->state.mBounds)) {
+ targetBatch = NULL;
+#if DEBUG_DEFER
+ DEFER_LOGD("op couldn't join batch %d, was intersected by batch %d",
+ targetIndex, i);
+ op->output(2);
+#endif
+ break;
+ }
+ }
+ }
+ }
+ if (!targetBatch) {
+ targetBatch = new DrawOpBatch();
+ mBatches.add(targetBatch);
+ if (batchId >= 0) {
+ mBatchIndices[batchId] = mBatches.size() - 1;
+ }
+ }
+ targetBatch->add(op);
+}
+
+status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
+ uint32_t level) {
+ ATRACE_CALL();
+ status_t status = DrawGlInfo::kStatusDone;
+
+ if (isEmpty()) return status; // nothing to flush
+
+ DEFER_LOGD("--flushing");
+ DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ int opCount = 0;
+ for (unsigned int i = 0; i < mBatches.size(); i++) {
+ DrawOpBatch* batch = mBatches[i];
+ for (unsigned int j = 0; j < batch->mOps.size(); j++) {
+ DrawOp* op = batch->mOps[j];
+
+ renderer.restoreDisplayState(op->state);
+
+#if DEBUG_DEFER
+ op->output(2);
+#endif
+ status |= op->applyDraw(renderer, dirty, level,
+ op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
+ opCount++;
+ }
+ }
+
+ DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
+ renderer.restoreToCount(restoreTo);
+ renderer.setDrawModifiers(restoreDrawModifiers);
+ clear();
+ return status;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
new file mode 100644
index 0000000..4fcb297
--- /dev/null
+++ b/libs/hwui/DeferredDisplayList.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
+#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
+
+#include <utils/Errors.h>
+#include <utils/Vector.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+class DrawOp;
+class DrawOpBatch;
+class OpenGLRenderer;
+class SkiaShader;
+
+class DeferredDisplayList {
+public:
+ DeferredDisplayList() { clear(); }
+ ~DeferredDisplayList() { clear(); }
+
+ enum OpBatchId {
+ kOpBatch_None = -1, // Don't batch
+ kOpBatch_Bitmap,
+ kOpBatch_Patch,
+ kOpBatch_AlphaVertices,
+ kOpBatch_Vertices,
+ kOpBatch_AlphaMaskTexture,
+ kOpBatch_Text,
+ kOpBatch_ColorText,
+
+ kOpBatch_Count, // Add other batch ids before this
+ };
+
+ bool isEmpty() { return mBatches.isEmpty(); }
+
+ /**
+ * Plays back all of the draw ops recorded into batches to the renderer.
+ * Adjusts the state of the renderer as necessary, and restores it when complete
+ */
+ status_t flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
+ uint32_t level);
+
+ /**
+ * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
+ * disallowReorder is false, respecting draw order when overlaps occur
+ */
+ void add(DrawOp* op, bool disallowReorder);
+
+private:
+ void clear();
+
+
+ Vector<DrawOpBatch*> mBatches;
+ int mBatchIndices[kOpBatch_Count];
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a52ea98..8aac628 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
@@ -386,7 +387,8 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
}
}
-status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
+status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
+ DeferredDisplayList* deferredList) {
status_t drawGlStatus = DrawGlInfo::kStatusDone;
#if DEBUG_DISPLAY_LIST
@@ -401,6 +403,12 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
+
+ if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
+ // flush before a saveLayerAlpha/setAlpha
+ // TODO: make this cleaner
+ drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
+ }
setViewProperties(renderer, level);
if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
@@ -418,8 +426,13 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
Caches::getInstance().eventMark(strlen(op->name()), op->name());
#endif
- drawGlStatus |= op->replay(renderer, dirty, flags,
- saveCount, level, mCaching, mMultipliedAlpha);
+ if (deferredList) {
+ drawGlStatus |= op->replay(renderer, dirty, flags,
+ saveCount, level, mCaching, mMultipliedAlpha, *deferredList);
+ } else {
+ drawGlStatus |= op->replay(renderer, dirty, flags,
+ saveCount, level, mCaching, mMultipliedAlpha);
+ }
logBuffer.writeCommand(level, op->name());
}
@@ -429,6 +442,11 @@ status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flag
DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
drawGlStatus);
+
+ if (!level && CC_LIKELY(deferredList)) {
+ drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
+ }
+
return drawGlStatus;
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 70a9755..d06827d 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -44,6 +44,7 @@ class SkRegion;
namespace android {
namespace uirenderer {
+class DeferredDisplayList;
class DisplayListOp;
class DisplayListRenderer;
class OpenGLRenderer;
@@ -83,7 +84,8 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
- status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
+ status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0,
+ DeferredDisplayList* deferredList = NULL);
void output(uint32_t level = 0);
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 78b432c..8e80647 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -22,6 +22,7 @@
#include <private/hwui/DrawGlInfo.h>
#include "OpenGLRenderer.h"
+#include "DeferredDisplayList.h"
#include "DisplayListRenderer.h"
#include "utils/LinearAllocator.h"
@@ -43,7 +44,6 @@
#define OP_LOGS(s) OP_LOG("%s", s)
#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
-
namespace android {
namespace uirenderer {
@@ -74,11 +74,15 @@ public:
kOpLogFlag_JSON = 0x2 // TODO: add?
};
- //TODO: for draw batching, DrawOps should override a virtual sub-method, with
- // DrawOps::apply deferring operations to a different list if possible
virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
uint32_t level, bool caching, int multipliedAlpha) = 0;
+ // same as replay above, but draw operations will defer into the deferredList if possible
+ // NOTE: colorfilters, paintfilters, shaders, shadow, and complex clips prevent deferral
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha,
+ DeferredDisplayList& deferredList) = 0;
+
virtual void output(int level, uint32_t flags = 0) = 0;
// NOTE: it would be nice to declare constants and overriding the implementation in each op to
@@ -98,7 +102,28 @@ public:
return DrawGlInfo::kStatusDone;
}
+ /**
+ * State operations are applied directly to the renderer, but can cause the deferred drawing op
+ * list to flush
+ */
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ status_t status = DrawGlInfo::kStatusDone;
+ if (requiresDrawOpFlush()) {
+ // will be setting renderer state that affects ops in deferredList, so flush list first
+ status |= deferredList.flush(renderer, dirty, flags, level);
+ }
+ applyState(renderer, saveCount);
+ return status;
+ }
+
virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
+
+ /**
+ * Returns true if it affects renderer drawing state in such a way to break deferral
+ * see OpenGLRenderer::disallowDeferral()
+ */
+ virtual bool requiresDrawOpFlush() { return false; }
};
class DrawOp : public DisplayListOp {
@@ -115,6 +140,33 @@ public:
return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
}
+ /** Draw operations are stored in the deferredList with information necessary for playback */
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
+ return DrawGlInfo::kStatusDone;
+ }
+
+ if (renderer.disallowDeferral()) {
+ // dispatch draw immediately, since the renderer's state is too complex for deferral
+ return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
+ }
+
+ if (!caching) multipliedAlpha = -1;
+ state.mMultipliedAlpha = multipliedAlpha;
+ if (!getLocalBounds(state.mBounds)) {
+ // empty bounds signify bounds can't be calculated
+ state.mBounds.setEmpty();
+ }
+
+ if (!renderer.storeDisplayState(state)) {
+ // op wasn't quick-rejected, so defer
+ deferredList.add(this, renderer.disallowReorder());
+ }
+
+ return DrawGlInfo::kStatusDone;
+ }
+
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) = 0;
@@ -125,6 +177,19 @@ public:
void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
bool getQuickRejected() { return mQuickRejected; }
+ /** Batching disabled by default, turned on for individual ops */
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_None;
+ }
+
+ float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
+
+public:
+ /**
+ * Stores the relevant canvas state of the object between deferral and replay (if the canvas
+ * state supports being stored) See OpenGLRenderer::simpleClipAndState()
+ */
+ DeferredDisplayState state;
protected:
SkPaint* getPaint(OpenGLRenderer& renderer) {
return renderer.filterPaint(mPaint);
@@ -191,6 +256,8 @@ public:
}
virtual const char* name() { return "RestoreToCount"; }
+ // Note: don't have to return true for requiresDrawOpFlush - even though restore can create a
+ // complex clip, the clip and matrix are overridden by DeferredDisplayList::flush()
private:
int mCount;
@@ -211,6 +278,7 @@ public:
}
virtual const char* name() { return "SaveLayer"; }
+ virtual bool requiresDrawOpFlush() { return true; }
private:
Rect mArea;
@@ -232,6 +300,8 @@ public:
}
virtual const char* name() { return "SaveLayerAlpha"; }
+ virtual bool requiresDrawOpFlush() { return true; }
+
private:
Rect mArea;
int mAlpha;
@@ -391,6 +461,7 @@ public:
}
virtual const char* name() { return "ClipPath"; }
+ virtual bool requiresDrawOpFlush() { return true; }
private:
SkPath* mPath;
@@ -413,6 +484,7 @@ public:
}
virtual const char* name() { return "ClipRegion"; }
+ virtual bool requiresDrawOpFlush() { return true; }
private:
SkRegion* mRegion;
@@ -582,6 +654,9 @@ public:
}
virtual const char* name() { return "DrawBitmap"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Bitmap;
+ }
protected:
SkBitmap* mBitmap;
@@ -606,6 +681,9 @@ public:
}
virtual const char* name() { return "DrawBitmap"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Bitmap;
+ }
private:
SkBitmap* mBitmap;
@@ -632,6 +710,9 @@ public:
}
virtual const char* name() { return "DrawBitmapRect"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Bitmap;
+ }
private:
SkBitmap* mBitmap;
@@ -654,6 +735,9 @@ public:
}
virtual const char* name() { return "DrawBitmapData"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Bitmap;
+ }
};
class DrawBitmapMeshOp : public DrawOp {
@@ -674,6 +758,9 @@ public:
}
virtual const char* name() { return "DrawBitmapMesh"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Bitmap;
+ }
private:
SkBitmap* mBitmap;
@@ -708,6 +795,9 @@ public:
}
virtual const char* name() { return "DrawPatch"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Patch;
+ }
private:
SkBitmap* mBitmap;
@@ -748,15 +838,21 @@ public:
: DrawBoundedOp(left, top, right, bottom, paint) {};
bool getLocalBounds(Rect& localBounds) {
+ localBounds.set(mLocalBounds);
if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
- float outset = mPaint->getStrokeWidth() * 0.5f;
- localBounds.set(mLocalBounds.left - outset, mLocalBounds.top - outset,
- mLocalBounds.right + outset, mLocalBounds.bottom + outset);
- } else {
- localBounds.set(mLocalBounds);
+ localBounds.outset(strokeWidthOutset());
}
return true;
}
+
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ if (mPaint->getPathEffect()) {
+ return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+ }
+ return mPaint->isAntiAlias() ?
+ DeferredDisplayList::kOpBatch_AlphaVertices :
+ DeferredDisplayList::kOpBatch_Vertices;
+ }
};
class DrawRectOp : public DrawStrokableOp {
@@ -793,6 +889,10 @@ public:
virtual const char* name() { return "DrawRects"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_Vertices;
+ }
+
private:
const float* mRects;
int mCount;
@@ -912,22 +1012,24 @@ public:
virtual const char* name() { return "DrawPath"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
+ }
private:
SkPath* mPath;
};
-class DrawLinesOp : public DrawOp {
+class DrawLinesOp : public DrawBoundedOp {
public:
DrawLinesOp(float* points, int count, SkPaint* paint)
- : DrawOp(paint), mPoints(points), mCount(count) {
- /* TODO: inherit from DrawBoundedOp and calculate localbounds something like:
+ : DrawBoundedOp(paint), mPoints(points), mCount(count) {
for (int i = 0; i < count; i += 2) {
mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
mLocalBounds.top = fminf(mLocalBounds.top, points[i+1]);
mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i+1]);
}
- */
+ mLocalBounds.outset(strokeWidthOutset());
}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
@@ -941,6 +1043,12 @@ public:
virtual const char* name() { return "DrawLines"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return mPaint->isAntiAlias() ?
+ DeferredDisplayList::kOpBatch_AlphaVertices :
+ DeferredDisplayList::kOpBatch_Vertices;
+ }
+
protected:
float* mPoints;
int mCount;
@@ -971,6 +1079,12 @@ public:
virtual void output(int level, uint32_t flags) {
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
+
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return mPaint->getColor() == 0xff000000 ?
+ DeferredDisplayList::kOpBatch_Text :
+ DeferredDisplayList::kOpBatch_ColorText;
+ }
protected:
const char* mText;
int mBytesCount;
@@ -1042,6 +1156,12 @@ public:
virtual const char* name() { return "DrawText"; }
+ virtual DeferredDisplayList::OpBatchId getBatchId() {
+ return mPaint->getColor() == 0xff000000 ?
+ DeferredDisplayList::kOpBatch_Text :
+ DeferredDisplayList::kOpBatch_ColorText;
+ }
+
private:
const char* mText;
int mBytesCount;
@@ -1083,9 +1203,21 @@ class DrawDisplayListOp : public DrawOp {
public:
DrawDisplayListOp(DisplayList* displayList, int flags)
: DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
+
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList& deferredList) {
+ if (mDisplayList && mDisplayList->isRenderable()) {
+ return mDisplayList->replay(renderer, dirty, mFlags, level + 1, &deferredList);
+ }
+ return DrawGlInfo::kStatusDone;
+ }
+
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
bool caching, int multipliedAlpha) {
- return renderer.drawDisplayList(mDisplayList, dirty, mFlags, level + 1);
+ if (mDisplayList && mDisplayList->isRenderable()) {
+ return mDisplayList->replay(renderer, dirty, mFlags, level + 1);
+ }
+ return DrawGlInfo::kStatusDone;
}
virtual void output(int level, uint32_t flags) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 31291b1..710f12f 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -21,6 +21,7 @@
#include <private/hwui/DrawGlInfo.h>
#include "DisplayList.h"
+#include "DeferredDisplayList.h"
#include "DisplayListLogBuffer.h"
#include "DisplayListOp.h"
#include "DisplayListRenderer.h"
@@ -239,7 +240,7 @@ bool DisplayListRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
}
status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
- Rect& dirty, int32_t flags, uint32_t level) {
+ Rect& dirty, int32_t flags) {
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 97a2508..bff3b97 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -47,15 +47,12 @@ namespace uirenderer {
// Display list
///////////////////////////////////////////////////////////////////////////////
+class DeferredDisplayList;
class DisplayListRenderer;
class DisplayListOp;
class DrawOp;
class StateOp;
-///////////////////////////////////////////////////////////////////////////////
-// Renderer
-///////////////////////////////////////////////////////////////////////////////
-
/**
* Records drawing commands in a display list for latter playback.
*/
@@ -98,8 +95,7 @@ public:
virtual bool clipPath(SkPath* path, SkRegion::Op op);
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
- virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
- uint32_t level = 0);
+ virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f0d25e1..37bdc7b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -32,6 +32,7 @@
#include <ui/Rect.h>
#include "OpenGLRenderer.h"
+#include "DeferredDisplayList.h"
#include "DisplayListRenderer.h"
#include "PathTessellator.h"
#include "Properties.h"
@@ -111,16 +112,18 @@ static const Blender gBlendsSwap[] = {
OpenGLRenderer::OpenGLRenderer():
mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
- mShader = NULL;
- mColorFilter = NULL;
- mHasShadow = false;
- mHasDrawFilter = false;
+ mDrawModifiers.mShader = NULL;
+ mDrawModifiers.mColorFilter = NULL;
+ mDrawModifiers.mHasShadow = false;
+ mDrawModifiers.mHasDrawFilter = false;
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
mFirstSnapshot = new Snapshot;
mScissorOptimizationDisabled = false;
+ mDrawDeferDisabled = false;
+ mDrawReorderDisabled = false;
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -137,6 +140,20 @@ void OpenGLRenderer::initProperties() {
} else {
INIT_LOGD(" Scissor optimization enabled");
}
+
+ if (property_get(PROPERTY_DISABLE_DRAW_DEFER, property, "false")) {
+ mDrawDeferDisabled = !strcasecmp(property, "true");
+ INIT_LOGD(" Draw defer %s", mDrawDeferDisabled ? "disabled" : "enabled");
+ } else {
+ INIT_LOGD(" Draw defer enabled");
+ }
+
+ if (property_get(PROPERTY_DISABLE_DRAW_REORDER, property, "false")) {
+ mDrawReorderDisabled = !strcasecmp(property, "true");
+ INIT_LOGD(" Draw reorder %s", mDrawReorderDisabled ? "disabled" : "enabled");
+ } else {
+ INIT_LOGD(" Draw reorder enabled");
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -770,7 +787,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
bounds.getWidth() / float(layer->getWidth()), 0.0f);
- layer->setColorFilter(mColorFilter);
+ layer->setColorFilter(mDrawModifiers.mColorFilter);
layer->setBlend(true);
layer->setDirty(false);
@@ -1204,6 +1221,40 @@ void OpenGLRenderer::clearLayerRegions() {
}
///////////////////////////////////////////////////////////////////////////////
+// State Deferral
+///////////////////////////////////////////////////////////////////////////////
+
+bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) {
+ const Rect& currentClip = *(mSnapshot->clipRect);
+ const mat4& currentMatrix = *(mSnapshot->transform);
+
+ // state only has bounds initialized in local coordinates
+ if (!state.mBounds.isEmpty()) {
+ currentMatrix.mapRect(state.mBounds);
+ if (!state.mBounds.intersect(currentClip)) {
+ // quick rejected
+ return true;
+ }
+ }
+
+ state.mClip.set(currentClip);
+ state.mMatrix.load(currentMatrix);
+ state.mDrawModifiers = mDrawModifiers;
+ return false;
+}
+
+void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
+ mSnapshot->transform->load(state.mMatrix);
+
+ // NOTE: a clip RECT will be saved and restored, but DeferredDisplayState doesn't support
+ // complex clips. In the future, we should add support for deferral of operations clipped by
+ // these. for now, we don't defer with complex clips (see OpenGLRenderer::disallowDeferral())
+ mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
+ dirtyClip();
+ mDrawModifiers = state.mDrawModifiers;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Transforms
///////////////////////////////////////////////////////////////////////////////
@@ -1452,7 +1503,7 @@ void OpenGLRenderer::setupDraw(bool clear) {
if (clear) clearLayerRegions();
// Make sure setScissor & setStencil happen at the beginning of
// this method
- if (mDirtyClip) {
+ if (mDirtyClip && mCaches.scissorEnabled) {
setScissorFromClip();
setStencilFromClip();
}
@@ -1524,14 +1575,14 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
}
void OpenGLRenderer::setupDrawShader() {
- if (mShader) {
- mShader->describe(mDescription, mExtensions);
+ if (mDrawModifiers.mShader) {
+ mDrawModifiers.mShader->describe(mDescription, mExtensions);
}
}
void OpenGLRenderer::setupDrawColorFilter() {
- if (mColorFilter) {
- mColorFilter->describe(mDescription, mExtensions);
+ if (mDrawModifiers.mColorFilter) {
+ mDrawModifiers.mColorFilter->describe(mDescription, mExtensions);
}
}
@@ -1547,16 +1598,19 @@ void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
- chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
- mDescription, swapSrcDst);
+ bool blend = (mColorSet && mColorA < 1.0f) ||
+ (mDrawModifiers.mShader && mDrawModifiers.mShader->blend());
+ chooseBlending(blend, mode, mDescription, swapSrcDst);
}
void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
- chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()) ||
- (mColorFilter && mColorFilter->blend()), mode, mDescription, swapSrcDst);
+ blend |= (mColorSet && mColorA < 1.0f) ||
+ (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
+ (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend());
+ chooseBlending(blend, mode, mDescription, swapSrcDst);
}
void OpenGLRenderer::setupDrawProgram() {
@@ -1609,7 +1663,7 @@ void OpenGLRenderer::setupDrawPointUniforms() {
}
void OpenGLRenderer::setupDrawColorUniforms() {
- if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) {
+ if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
}
}
@@ -1621,23 +1675,25 @@ void OpenGLRenderer::setupDrawPureColorUniforms() {
}
void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
- if (mShader) {
+ if (mDrawModifiers.mShader) {
if (ignoreTransform) {
mModelView.loadInverse(*mSnapshot->transform);
}
- mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit);
+ mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
+ mModelView, *mSnapshot, &mTextureUnit);
}
}
void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
- if (mShader) {
- mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit);
+ if (mDrawModifiers.mShader) {
+ mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
+ mIdentity, *mSnapshot, &mTextureUnit);
}
}
void OpenGLRenderer::setupDrawColorFilterUniforms() {
- if (mColorFilter) {
- mColorFilter->setupProgram(mCaches.currentProgram);
+ if (mDrawModifiers.mColorFilter) {
+ mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
}
}
@@ -1726,21 +1782,24 @@ void OpenGLRenderer::finishDrawTexture() {
// Drawing
///////////////////////////////////////////////////////////////////////////////
-status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList,
- Rect& dirty, int32_t flags, uint32_t level) {
-
+status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) {
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
- return displayList->replay(*this, dirty, flags, level);
+ if (CC_UNLIKELY(mDrawDeferDisabled)) {
+ return displayList->replay(*this, dirty, flags, 0);
+ }
+
+ DeferredDisplayList deferredList;
+ return displayList->replay(*this, dirty, flags, 0, &deferredList);
}
return DrawGlInfo::kStatusDone;
}
-void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
if (displayList) {
- displayList->output(level);
+ displayList->output(0);
}
}
@@ -1990,7 +2049,7 @@ status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
// Apply a scale transform on the canvas only when a shader is in use
// Skia handles the ratio between the dst and src rects as a scale factor
// when a shader is set
- bool useScaleTransform = mShader && scaled;
+ bool useScaleTransform = mDrawModifiers.mShader && scaled;
bool ignoreTransform = false;
if (CC_LIKELY(mSnapshot->transform->isPureTranslate() && !useScaleTransform)) {
@@ -2445,15 +2504,15 @@ void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesC
// if shader-based correction is enabled
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
- paint, text, bytesCount, count, mShadowRadius, positions);
+ paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
const AutoTexture autoCleanup(shadow);
- const float sx = x - shadow->left + mShadowDx;
- const float sy = y - shadow->top + mShadowDy;
+ const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
+ const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
- const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
- int shadowColor = mShadowColor;
- if (mShader) {
+ const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
+ int shadowColor = mDrawModifiers.mShadowColor;
+ if (mDrawModifiers.mShader) {
shadowColor = 0xffffffff;
}
@@ -2501,7 +2560,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- if (CC_UNLIKELY(mHasShadow)) {
+ if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
alpha, mode, 0.0f, 0.0f);
}
@@ -2592,7 +2651,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- if (CC_UNLIKELY(mHasShadow)) {
+ if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
oldX, oldY);
}
@@ -2748,8 +2807,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
- SkiaColorFilter* oldFilter = mColorFilter;
- mColorFilter = layer->getColorFilter();
+ SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter;
+ mDrawModifiers.mColorFilter = layer->getColorFilter();
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
@@ -2788,7 +2847,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
#endif
}
- mColorFilter = oldFilter;
+ mDrawModifiers.mColorFilter = oldFilter;
if (layer->debugDrawUpdate) {
layer->debugDrawUpdate = false;
@@ -2809,13 +2868,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetShader() {
- mShader = NULL;
+ mDrawModifiers.mShader = NULL;
}
void OpenGLRenderer::setupShader(SkiaShader* shader) {
- mShader = shader;
- if (mShader) {
- mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
+ mDrawModifiers.mShader = shader;
+ if (mDrawModifiers.mShader) {
+ mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
}
}
@@ -2824,11 +2883,11 @@ void OpenGLRenderer::setupShader(SkiaShader* shader) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetColorFilter() {
- mColorFilter = NULL;
+ mDrawModifiers.mColorFilter = NULL;
}
void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
- mColorFilter = filter;
+ mDrawModifiers.mColorFilter = filter;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2836,15 +2895,15 @@ void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetShadow() {
- mHasShadow = false;
+ mDrawModifiers.mHasShadow = false;
}
void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
- mHasShadow = true;
- mShadowRadius = radius;
- mShadowDx = dx;
- mShadowDy = dy;
- mShadowColor = color;
+ mDrawModifiers.mHasShadow = true;
+ mDrawModifiers.mShadowRadius = radius;
+ mDrawModifiers.mShadowDx = dx;
+ mDrawModifiers.mShadowDy = dy;
+ mDrawModifiers.mShadowColor = color;
}
///////////////////////////////////////////////////////////////////////////////
@@ -2852,22 +2911,23 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::resetPaintFilter() {
- mHasDrawFilter = false;
+ mDrawModifiers.mHasDrawFilter = false;
}
void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
- mHasDrawFilter = true;
- mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
- mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
+ mDrawModifiers.mHasDrawFilter = true;
+ mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
+ mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
}
SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
- if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint;
+ if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) return paint;
uint32_t flags = paint->getFlags();
mFilteredPaint = *paint;
- mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
+ mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) |
+ mDrawModifiers.mPaintFilterSetBits);
return &mFilteredPaint;
}
@@ -2967,7 +3027,7 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint
int color = paint->getColor();
// If a shader is set, preserve only the alpha
- if (mShader) {
+ if (mDrawModifiers.mShader) {
color |= 0x00ffffff;
}
SkXfermode::Mode mode = getXfermode(paint->getXfermode());
@@ -3040,7 +3100,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform) {
// If a shader is set, preserve only the alpha
- if (mShader) {
+ if (mDrawModifiers.mShader) {
color |= 0x00ffffff;
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ad80d36..e12083c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -48,6 +48,34 @@
namespace android {
namespace uirenderer {
+struct DrawModifiers {
+ SkiaShader* mShader;
+ SkiaColorFilter* mColorFilter;
+
+ // Drop shadow
+ bool mHasShadow;
+ float mShadowRadius;
+ float mShadowDx;
+ float mShadowDy;
+ int mShadowColor;
+
+ // Draw filters
+ bool mHasDrawFilter;
+ int mPaintFilterClearBits;
+ int mPaintFilterSetBits;
+};
+
+struct DeferredDisplayState {
+ Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
+ int mMultipliedAlpha; // -1 if invalid (because caching not set)
+
+ // the below are set and used by the OpenGLRenderer at record and deferred playback
+ Rect mClip;
+ mat4 mMatrix;
+ SkiaShader* mShader;
+ DrawModifiers mDrawModifiers;
+};
+
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -182,9 +210,8 @@ public:
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
virtual Rect* getClipRect();
- virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
- uint32_t level = 0);
- virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
+ virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
+ virtual void outputDisplayList(DisplayList* displayList);
virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -233,6 +260,23 @@ public:
SkPaint* filterPaint(SkPaint* paint);
+ bool disallowDeferral() {
+ // returns true if the OpenGLRenderer's state can be completely represented by
+ // a DeferredDisplayState object
+ return !mSnapshot->clipRegion->isEmpty() ||
+ mSnapshot->alpha < 1.0 ||
+ (mSnapshot->flags & Snapshot::kFlagIsLayer) ||
+ (mSnapshot->flags & Snapshot::kFlagFboTarget); // ensure we're not in a layer
+ }
+
+ bool disallowReorder() { return mDrawReorderDisabled; }
+
+ bool storeDisplayState(DeferredDisplayState& state);
+ void restoreDisplayState(const DeferredDisplayState& state);
+
+ const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
+ void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
+
ANDROID_API bool isCurrentTransformSimple() {
return mSnapshot->transform->isSimple();
}
@@ -868,26 +912,11 @@ private:
// State used to define the clipping region
sp<Snapshot> mTilingSnapshot;
- // Shaders
- SkiaShader* mShader;
-
- // Color filters
- SkiaColorFilter* mColorFilter;
-
// Used to draw textured quads
TextureVertex mMeshVertices[4];
- // Drop shadow
- bool mHasShadow;
- float mShadowRadius;
- float mShadowDx;
- float mShadowDy;
- int mShadowColor;
-
- // Draw filters
- bool mHasDrawFilter;
- int mPaintFilterClearBits;
- int mPaintFilterSetBits;
+ // shader, filters, and shadow
+ DrawModifiers mDrawModifiers;
SkPaint mFilteredPaint;
// Various caches
@@ -925,6 +954,8 @@ private:
// See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in
// Properties.h
bool mScissorOptimizationDisabled;
+ bool mDrawDeferDisabled;
+ bool mDrawReorderDisabled;
// No-ops start/endTiling when set
bool mSuppressTiling;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 0c75242..f3957cf 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -82,6 +82,19 @@ enum DebugLevel {
*/
#define PROPERTY_DISABLE_SCISSOR_OPTIMIZATION "ro.hwui.disable_scissor_opt"
+/**
+ * Disables draw operation deferral if set to "true", forcing draw
+ * commands to be issued to OpenGL in order, and processed in sequence
+ * with state-manipulation canvas commands.
+ */
+#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
+
+/**
+ * Used to disable draw operation reordering when deferring draw operations
+ * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
+ */
+#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
+
// These properties are defined in mega-bytes
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 5f4bb5a..f50ac3c 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -159,6 +159,13 @@ public:
bottom += dy;
}
+ void outset(float delta) {
+ left -= delta;
+ top -= delta;
+ right += delta;
+ bottom += delta;
+ }
+
void snapToPixelBoundaries() {
left = floorf(left + 0.5f);
top = floorf(top + 0.5f);