Object-based DisplayList recording
bug:8037003
Changes the DisplayList from using stream read/write commands to use an array of
objects manually allocated on a linear buffer.
Depends on frameworks/native change https://googleplex-android-review.googlesource.com/#/c/257695/ which adds LinearAllocator
Also changes drawRects to use float count instead of rect count, to be more like drawLines/drawPoints
Change-Id: Ia2e4a11acd8f0a757042a05cbc9e7563cb73ee47
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
new file mode 100644
index 0000000..a4de56d
--- /dev/null
+++ b/libs/hwui/DisplayListOp.h
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (C) 2012 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_DISPLAY_OPERATION_H
+#define ANDROID_HWUI_DISPLAY_OPERATION_H
+
+#include <SkXfermode.h>
+
+#include "OpenGLRenderer.h"
+#include "DisplayListRenderer.h"
+#include "utils/LinearAllocator.h"
+
+#define CRASH() do { \
+ *(int *)(uintptr_t)0xbbadbeef = 0; \
+ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
+} while(false)
+
+#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
+#define MATRIX_ARGS(m) \
+ m->get(0), m->get(1), m->get(2), \
+ m->get(3), m->get(4), m->get(5), \
+ m->get(6), m->get(7), m->get(8)
+#define RECT_STRING "%.2f %.2f %.2f %.2f"
+#define RECT_ARGS(r) \
+ r.left, r.top, r.right, r.bottom
+
+// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
+#define OP_LOGS(s) OP_LOG("%s", s)
+#define OP_LOG(s, ...) ALOGD( "%*s--%p " s, level * 2, "", this, __VA_ARGS__ )
+
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
+ * may be replayed to an OpenGLRenderer.
+ *
+ * To avoid individual memory allocations, DisplayListOps may only be allocated into a
+ * LinearAllocator's managed memory buffers. Each pointer held by a DisplayListOp is either a
+ * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
+ * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
+ * never called as LinearAllocators are simply discarded, so no memory management should be done in
+ * this class.
+ */
+class DisplayListOp {
+public:
+ // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
+ // standard new() intentionally not implemented, and delete/deconstructor should never be used.
+ virtual ~DisplayListOp() { CRASH(); }
+ static void operator delete(void* ptr) { CRASH(); }
+ /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+ static void* operator new(size_t size, LinearAllocator& allocator) {
+ return allocator.alloc(size);
+ }
+
+ enum OpLogFlag {
+ kOpLogFlag_Recurse = 0x1,
+ 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;
+
+ 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
+ // point at the constants, but that seems to require a .cpp file
+ virtual const char* name() = 0;
+};
+
+class StateOp : public DisplayListOp {
+public:
+ StateOp() {};
+
+ virtual ~StateOp() {}
+
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha) {
+ applyState(renderer, saveCount);
+ return DrawGlInfo::kStatusDone;
+ }
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
+};
+
+class DrawOp : public DisplayListOp {
+public:
+ DrawOp(SkPaint* paint)
+ : mPaint(paint), mQuickRejected(false) {}
+
+ virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
+ uint32_t level, bool caching, int multipliedAlpha) {
+ if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
+ return DrawGlInfo::kStatusDone;
+ }
+
+ return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) = 0;
+
+ // returns true if bounds exist
+ virtual bool getLocalBounds(Rect& localBounds) { return false; }
+
+ // TODO: better refine localbounds usage
+ void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
+ bool getQuickRejected() { return mQuickRejected; }
+
+protected:
+ SkPaint* getPaint(OpenGLRenderer& renderer) {
+ return renderer.filterPaint(mPaint);
+ }
+
+ SkPaint* mPaint; // should be accessed via getPaint() when applying
+ bool mQuickRejected;
+};
+
+class DrawBoundedOp : public DrawOp {
+public:
+ DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
+ : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
+
+ // default constructor for area, to be overridden in child constructor body
+ DrawBoundedOp(SkPaint* paint)
+ : DrawOp(paint) {}
+
+ bool getLocalBounds(Rect& localBounds) {
+ localBounds.set(mLocalBounds);
+ return true;
+ }
+
+protected:
+ Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
+// not directly draw or alter output
+///////////////////////////////////////////////////////////////////////////////
+
+class SaveOp : public StateOp {
+public:
+ SaveOp(int flags)
+ : mFlags(flags) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.save(mFlags);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Save flags %x", mFlags);
+ }
+
+ virtual const char* name() { return "Save"; }
+
+private:
+ int mFlags;
+};
+
+class RestoreToCountOp : public StateOp {
+public:
+ RestoreToCountOp(int count)
+ : mCount(count) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.restoreToCount(saveCount + mCount);
+
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Restore to count %d", mCount);
+ }
+
+ virtual const char* name() { return "RestoreToCount"; }
+
+private:
+ int mCount;
+};
+
+class SaveLayerOp : public StateOp {
+public:
+ SaveLayerOp(float left, float top, float right, float bottom, SkPaint* paint, int flags)
+ : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ SkPaint* paint = renderer.filterPaint(mPaint);
+ renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, paint, mFlags);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SaveLayer of area " RECT_STRING, RECT_ARGS(mArea));
+ }
+
+ virtual const char* name() { return "SaveLayer"; }
+
+private:
+ Rect mArea;
+ SkPaint* mPaint;
+ int mFlags;
+};
+
+class SaveLayerAlphaOp : public StateOp {
+public:
+ SaveLayerAlphaOp(float left, float top, float right, float bottom, int alpha, int flags)
+ : mArea(left, top, right, bottom), mAlpha(alpha), mFlags(flags) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.saveLayerAlpha(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mFlags);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SaveLayerAlpha of area " RECT_STRING, RECT_ARGS(mArea));
+ }
+
+ virtual const char* name() { return "SaveLayerAlpha"; }
+private:
+ Rect mArea;
+ int mAlpha;
+ int mFlags;
+};
+
+class TranslateOp : public StateOp {
+public:
+ TranslateOp(float dx, float dy)
+ : mDx(dx), mDy(dy) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.translate(mDx, mDy);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Translate by %f %f", mDx, mDy);
+ }
+
+ virtual const char* name() { return "Translate"; }
+
+private:
+ float mDx;
+ float mDy;
+};
+
+class RotateOp : public StateOp {
+public:
+ RotateOp(float degrees)
+ : mDegrees(degrees) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.rotate(mDegrees);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Rotate by %f degrees", mDegrees);
+ }
+
+ virtual const char* name() { return "Rotate"; }
+
+private:
+ float mDegrees;
+};
+
+class ScaleOp : public StateOp {
+public:
+ ScaleOp(float sx, float sy)
+ : mSx(sx), mSy(sy) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.scale(mSx, mSy);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Scale by %f %f", mSx, mSy);
+ }
+
+ virtual const char* name() { return "Scale"; }
+
+private:
+ float mSx;
+ float mSy;
+};
+
+class SkewOp : public StateOp {
+public:
+ SkewOp(float sx, float sy)
+ : mSx(sx), mSy(sy) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.skew(mSx, mSy);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("Skew by %f %f", mSx, mSy);
+ }
+
+ virtual const char* name() { return "Skew"; }
+
+private:
+ float mSx;
+ float mSy;
+};
+
+class SetMatrixOp : public StateOp {
+public:
+ SetMatrixOp(SkMatrix* matrix)
+ : mMatrix(matrix) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.setMatrix(mMatrix);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ }
+
+ virtual const char* name() { return "SetMatrix"; }
+
+private:
+ SkMatrix* mMatrix;
+};
+
+class ConcatMatrixOp : public StateOp {
+public:
+ ConcatMatrixOp(SkMatrix* matrix)
+ : mMatrix(matrix) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.concatMatrix(mMatrix);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
+ }
+
+ virtual const char* name() { return "ConcatMatrix"; }
+
+private:
+ SkMatrix* mMatrix;
+};
+
+class ClipRectOp : public StateOp {
+public:
+ ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
+ : mArea(left, top, right, bottom), mOp(op) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
+ }
+
+ virtual const char* name() { return "ClipRect"; }
+
+private:
+ Rect mArea;
+ SkRegion::Op mOp;
+};
+
+class ClipPathOp : public StateOp {
+public:
+ ClipPathOp(SkPath* path, SkRegion::Op op)
+ : mPath(path), mOp(op) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.clipPath(mPath, mOp);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ SkRect bounds = mPath->getBounds();
+ OP_LOG("ClipPath bounds " RECT_STRING,
+ bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+ }
+
+ virtual const char* name() { return "ClipPath"; }
+
+private:
+ SkPath* mPath;
+ SkRegion::Op mOp;
+};
+
+class ClipRegionOp : public StateOp {
+public:
+ ClipRegionOp(SkRegion* region, SkRegion::Op op)
+ : mRegion(region), mOp(op) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.clipRegion(mRegion, mOp);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ SkIRect bounds = mRegion->getBounds();
+ OP_LOG("ClipRegion bounds %d %d %d %d",
+ bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+ }
+
+ virtual const char* name() { return "ClipRegion"; }
+
+private:
+ SkRegion* mRegion;
+ SkRegion::Op mOp;
+};
+
+class ResetShaderOp : public StateOp {
+public:
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.resetShader();
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOGS("ResetShader");
+ }
+
+ virtual const char* name() { return "ResetShader"; }
+};
+
+class SetupShaderOp : public StateOp {
+public:
+ SetupShaderOp(SkiaShader* shader)
+ : mShader(shader) {}
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.setupShader(mShader);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SetupShader, shader %p", mShader);
+ }
+
+ virtual const char* name() { return "SetupShader"; }
+
+private:
+ SkiaShader* mShader;
+};
+
+class ResetColorFilterOp : public StateOp {
+public:
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.resetColorFilter();
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOGS("ResetColorFilter");
+ }
+
+ virtual const char* name() { return "ResetColorFilter"; }
+};
+
+class SetupColorFilterOp : public StateOp {
+public:
+ SetupColorFilterOp(SkiaColorFilter* colorFilter)
+ : mColorFilter(colorFilter) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.setupColorFilter(mColorFilter);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SetupColorFilter, filter %p", mColorFilter);
+ }
+
+ virtual const char* name() { return "SetupColorFilter"; }
+
+private:
+ SkiaColorFilter* mColorFilter;
+};
+
+class ResetShadowOp : public StateOp {
+public:
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.resetShadow();
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOGS("ResetShadow");
+ }
+
+ virtual const char* name() { return "ResetShadow"; }
+};
+
+class SetupShadowOp : public StateOp {
+public:
+ SetupShadowOp(float radius, float dx, float dy, int color)
+ : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.setupShadow(mRadius, mDx, mDy, mColor);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
+ }
+
+ virtual const char* name() { return "SetupShadow"; }
+
+private:
+ float mRadius;
+ float mDx;
+ float mDy;
+ int mColor;
+};
+
+class ResetPaintFilterOp : public StateOp {
+public:
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.resetPaintFilter();
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOGS("ResetPaintFilter");
+ }
+
+ virtual const char* name() { return "ResetPaintFilter"; }
+};
+
+class SetupPaintFilterOp : public StateOp {
+public:
+ SetupPaintFilterOp(int clearBits, int setBits)
+ : mClearBits(clearBits), mSetBits(setBits) {}
+
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+ renderer.setupPaintFilter(mClearBits, mSetBits);
+ }
+
+ virtual void output(int level, uint32_t flags = 0) {
+ OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
+ }
+
+ virtual const char* name() { return "SetupPaintFilter"; }
+
+private:
+ int mClearBits;
+ int mSetBits;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// DRAW OPERATIONS - these are operations that can draw to the canvas's device
+///////////////////////////////////////////////////////////////////////////////
+
+class DrawBitmapOp : public DrawBoundedOp {
+public:
+ DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
+ : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(),
+ paint),
+ mBitmap(bitmap) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ SkPaint* paint = getPaint(renderer);
+ int oldAlpha = -1;
+ if (caching && multipliedAlpha < 255) {
+ oldAlpha = paint->getAlpha();
+ paint->setAlpha(multipliedAlpha);
+ }
+ status_t ret = renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top, paint);
+ if (oldAlpha >= 0) {
+ paint->setAlpha(oldAlpha);
+ }
+ return ret;
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
+ }
+
+ virtual const char* name() { return "DrawBitmap"; }
+
+protected:
+ SkBitmap* mBitmap;
+};
+
+class DrawBitmapMatrixOp : public DrawBoundedOp {
+public:
+ DrawBitmapMatrixOp(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint)
+ : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
+ mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
+ const mat4 transform(*matrix);
+ transform.mapRect(mLocalBounds);
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
+ }
+
+ virtual const char* name() { return "DrawBitmap"; }
+
+private:
+ SkBitmap* mBitmap;
+ SkMatrix* mMatrix;
+};
+
+class DrawBitmapRectOp : public DrawBoundedOp {
+public:
+ DrawBitmapRectOp(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
+ float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint)
+ : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
+ mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
+ mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
+ getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
+ mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
+ }
+
+ virtual const char* name() { return "DrawBitmapRect"; }
+
+private:
+ SkBitmap* mBitmap;
+ Rect mSrc;
+};
+
+class DrawBitmapDataOp : public DrawBitmapOp {
+public:
+ DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
+ : DrawBitmapOp(bitmap, left, top, paint) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
+ mLocalBounds.top, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw bitmap %p", mBitmap);
+ }
+
+ virtual const char* name() { return "DrawBitmapData"; }
+};
+
+class DrawBitmapMeshOp : public DrawOp {
+public:
+ DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
+ float* vertices, int* colors, SkPaint* paint)
+ : DrawOp(paint), mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
+ mVertices(vertices), mColors(colors) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
+ mVertices, mColors, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
+ }
+
+ virtual const char* name() { return "DrawBitmapMesh"; }
+
+private:
+ SkBitmap* mBitmap;
+ int mMeshWidth;
+ int mMeshHeight;
+ float* mVertices;
+ int* mColors;
+};
+
+class DrawPatchOp : public DrawBoundedOp {
+public:
+ DrawPatchOp(SkBitmap* bitmap, const int32_t* xDivs,
+ const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height,
+ int8_t numColors, float left, float top, float right, float bottom,
+ int alpha, SkXfermode::Mode mode)
+ : DrawBoundedOp(left, top, right, bottom, 0),
+ mBitmap(bitmap), mxDivs(xDivs), myDivs(yDivs),
+ mColors(colors), mxDivsCount(width), myDivsCount(height),
+ mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ // NOTE: not calling the virtual method, which takes a paint
+ return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
+ mxDivsCount, myDivsCount, mNumColors,
+ mLocalBounds.left, mLocalBounds.top,
+ mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
+ }
+
+ virtual const char* name() { return "DrawPatch"; }
+
+private:
+ SkBitmap* mBitmap;
+ const int32_t* mxDivs;
+ const int32_t* myDivs;
+ const uint32_t* mColors;
+ uint32_t mxDivsCount;
+ uint32_t myDivsCount;
+ int8_t mNumColors;
+ int mAlpha;
+ SkXfermode::Mode mMode;
+};
+
+class DrawColorOp : public DrawOp {
+public:
+ DrawColorOp(int color, SkXfermode::Mode mode)
+ : DrawOp(0), mColor(color), mMode(mode) {};
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawColor(mColor, mMode);
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw color %#x, mode %d", mColor, mMode);
+ }
+
+ virtual const char* name() { return "DrawColor"; }
+
+private:
+ int mColor;
+ SkXfermode::Mode mMode;
+};
+
+class DrawStrokableOp : public DrawBoundedOp {
+public:
+ DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
+ : DrawBoundedOp(left, top, right, bottom, paint) {};
+
+ bool getLocalBounds(Rect& localBounds) {
+ 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);
+ }
+ return true;
+ }
+};
+
+class DrawRectOp : public DrawStrokableOp {
+public:
+ DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
+ : DrawStrokableOp(left, top, right, bottom, paint) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
+ mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
+ }
+
+ virtual const char* name() { return "DrawRect"; }
+};
+
+class DrawRectsOp : public DrawOp {
+public:
+ DrawRectsOp(const float* rects, int count, SkPaint* paint)
+ : DrawOp(paint), mRects(rects), mCount(count) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawRects(mRects, mCount, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Rects count %d", mCount);
+ }
+
+ virtual const char* name() { return "DrawRects"; }
+
+private:
+ const float* mRects;
+ int mCount;
+};
+
+class DrawRoundRectOp : public DrawStrokableOp {
+public:
+ DrawRoundRectOp(float left, float top, float right, float bottom,
+ float rx, float ry, SkPaint* paint)
+ : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
+ mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
+ }
+
+ virtual const char* name() { return "DrawRoundRect"; }
+
+private:
+ float mRx;
+ float mRy;
+};
+
+class DrawCircleOp : public DrawStrokableOp {
+public:
+ DrawCircleOp(float x, float y, float radius, SkPaint* paint)
+ : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
+ mX(x), mY(y), mRadius(radius) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
+ }
+
+ virtual const char* name() { return "DrawCircle"; }
+
+private:
+ float mX;
+ float mY;
+ float mRadius;
+};
+
+class DrawOvalOp : public DrawStrokableOp {
+public:
+ DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
+ : DrawStrokableOp(left, top, right, bottom, paint) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
+ mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
+ }
+
+ virtual const char* name() { return "DrawOval"; }
+};
+
+class DrawArcOp : public DrawStrokableOp {
+public:
+ DrawArcOp(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, bool useCenter, SkPaint* paint)
+ : DrawStrokableOp(left, top, right, bottom, paint),
+ mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
+ mLocalBounds.right, mLocalBounds.bottom,
+ mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
+ RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
+ }
+
+ virtual const char* name() { return "DrawArc"; }
+
+private:
+ float mStartAngle;
+ float mSweepAngle;
+ bool mUseCenter;
+};
+
+class DrawPathOp : public DrawBoundedOp {
+public:
+ DrawPathOp(SkPath* path, SkPaint* paint)
+ : DrawBoundedOp(paint), mPath(path) {
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
+ left -= offset;
+ top -= offset;
+ mLocalBounds.set(left, top, left + width, top + height);
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawPath(mPath, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
+ }
+
+ virtual const char* name() { return "DrawPath"; }
+
+private:
+ SkPath* mPath;
+};
+
+class DrawLinesOp : public DrawOp {
+public:
+ DrawLinesOp(float* points, int count, SkPaint* paint)
+ : DrawOp(paint), mPoints(points), mCount(count) {
+ /* TODO: inherit from DrawBoundedOp and calculate localbounds something like:
+ 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]);
+ }
+ */
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawLines(mPoints, mCount, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Lines count %d", mCount);
+ }
+
+ virtual const char* name() { return "DrawLines"; }
+
+protected:
+ float* mPoints;
+ int mCount;
+};
+
+class DrawPointsOp : public DrawLinesOp {
+public:
+ DrawPointsOp(float* points, int count, SkPaint* paint)
+ : DrawLinesOp(points, count, paint) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Points count %d", mCount);
+ }
+
+ virtual const char* name() { return "DrawPoints"; }
+};
+
+class DrawSomeTextOp : public DrawOp {
+public:
+ DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
+ : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw some text, %d bytes", mBytesCount);
+ }
+protected:
+ const char* mText;
+ int mBytesCount;
+ int mCount;
+};
+
+class DrawTextOnPathOp : public DrawSomeTextOp {
+public:
+ DrawTextOnPathOp(const char* text, int bytesCount, int count,
+ SkPath* path, float hOffset, float vOffset, SkPaint* paint)
+ : DrawSomeTextOp(text, bytesCount, count, paint),
+ mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
+ /* TODO: inherit from DrawBounded and init mLocalBounds */
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
+ mHOffset, mVOffset, getPaint(renderer));
+ }
+
+ virtual const char* name() { return "DrawTextOnPath"; }
+
+private:
+ SkPath* mPath;
+ float mHOffset;
+ float mVOffset;
+};
+
+class DrawPosTextOp : public DrawSomeTextOp {
+public:
+ DrawPosTextOp(const char* text, int bytesCount, int count,
+ const float* positions, SkPaint* paint)
+ : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
+ /* TODO: inherit from DrawBounded and init mLocalBounds */
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
+ }
+
+ virtual const char* name() { return "DrawPosText"; }
+
+private:
+ const float* mPositions;
+};
+
+class DrawTextOp : public DrawBoundedOp {
+public:
+ DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
+ const float* positions, SkPaint* paint, float length)
+ : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
+ mX(x), mY(y), mPositions(positions), mLength(length) {
+ SkPaint::FontMetrics metrics;
+ paint->getFontMetrics(&metrics, 0.0f);
+ mLocalBounds.set(mX, mY + metrics.fTop, mX + length, mY + metrics.fBottom);
+ }
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
+ mPositions, getPaint(renderer), mLength);
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
+ }
+
+ virtual const char* name() { return "DrawText"; }
+
+private:
+ const char* mText;
+ int mBytesCount;
+ int mCount;
+ float mX;
+ float mY;
+ const float* mPositions;
+ float mLength;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SPECIAL DRAW OPERATIONS
+///////////////////////////////////////////////////////////////////////////////
+
+class DrawFunctorOp : public DrawOp {
+public:
+ DrawFunctorOp(Functor* functor)
+ : DrawOp(0), mFunctor(functor) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ renderer.startMark("GL functor");
+ status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
+ renderer.endMark();
+ return ret;
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Functor %p", mFunctor);
+ }
+
+ virtual const char* name() { return "DrawFunctor"; }
+
+private:
+ Functor* mFunctor;
+};
+
+class DrawDisplayListOp : public DrawOp {
+public:
+ DrawDisplayListOp(DisplayList* displayList, int flags)
+ : DrawOp(0), mDisplayList(displayList), mFlags(flags) {}
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ return renderer.drawDisplayList(mDisplayList, dirty, mFlags, level + 1);
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
+ if (mDisplayList && (flags & kOpLogFlag_Recurse)) {
+ mDisplayList->output(level + 1);
+ }
+ }
+
+ virtual const char* name() { return "DrawDisplayList"; }
+
+private:
+ DisplayList* mDisplayList;
+ int mFlags;
+};
+
+class DrawLayerOp : public DrawOp {
+public:
+ DrawLayerOp(Layer* layer, float x, float y, SkPaint* paint)
+ : DrawOp(paint), mLayer(layer), mX(x), mY(y) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
+ bool caching, int multipliedAlpha) {
+ int oldAlpha = -1;
+
+ if (caching && multipliedAlpha < 255) {
+ oldAlpha = mLayer->getAlpha();
+ mLayer->setAlpha(multipliedAlpha);
+ }
+ status_t ret = renderer.drawLayer(mLayer, mX, mY, getPaint(renderer));
+ if (oldAlpha >= 0) {
+ mLayer->setAlpha(oldAlpha);
+ }
+ return ret;
+ }
+
+ virtual void output(int level, uint32_t flags) {
+ OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
+ }
+
+ virtual const char* name() { return "DrawLayer"; }
+
+private:
+ Layer* mLayer;
+ float mX;
+ float mY;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_DISPLAY_OPERATION_H