diff options
author | Chris Craik <ccraik@google.com> | 2013-02-19 09:56:33 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-02-19 09:56:33 -0800 |
commit | 620cff4006ee0b507f00ef8a242ecff4e60ba4e9 (patch) | |
tree | 30c29f1ee548bb5da57a0a68b95f3c25beaa8eb6 /libs | |
parent | 57a8b612fa6b31a18f9e00a7bdf7dfbd261f793c (diff) | |
parent | ad82f20d2382396f5ac75fdf6f7db5c4da1c4c23 (diff) | |
download | frameworks_base-620cff4006ee0b507f00ef8a242ecff4e60ba4e9.zip frameworks_base-620cff4006ee0b507f00ef8a242ecff4e60ba4e9.tar.gz frameworks_base-620cff4006ee0b507f00ef8a242ecff4e60ba4e9.tar.bz2 |
am ad82f20d: Merge "DisplayList draw operation reordering"
* commit 'ad82f20d2382396f5ac75fdf6f7db5c4da1c4c23':
DisplayList draw operation reordering
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/Debug.h | 3 | ||||
-rw-r--r-- | libs/hwui/DeferredDisplayList.cpp | 176 | ||||
-rw-r--r-- | libs/hwui/DeferredDisplayList.h | 78 | ||||
-rw-r--r-- | libs/hwui/DisplayList.cpp | 24 | ||||
-rw-r--r-- | libs/hwui/DisplayList.h | 4 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 158 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 3 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 8 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 178 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 71 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 13 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 7 |
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); |