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/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2b4260d..5e6125f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1868,7 +1868,7 @@
                 mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
                 switch (graphType) {
                     case GraphDataProvider.GRAPH_TYPE_BARS:
-                        mGlCanvas.drawRects(mProfileShapes[i], count, mProfilePaint);
+                        mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
                         break;
                     case GraphDataProvider.GRAPH_TYPE_LINES:
                         mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index de14826..f4fcc81 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -479,7 +479,7 @@
             rects.push(r.fTop);
             rects.push(r.fRight);
             rects.push(r.fBottom);
-            count++;
+            count += 4;
             it.next();
         }
         renderer->drawRects(rects.array(), count, paint);
diff --git a/libs/hwui/DisplayListLogBuffer.cpp b/libs/hwui/DisplayListLogBuffer.cpp
index f204644..f039fcd 100644
--- a/libs/hwui/DisplayListLogBuffer.cpp
+++ b/libs/hwui/DisplayListLogBuffer.cpp
@@ -18,9 +18,8 @@
 
 // BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
 // that mStart always points at the next command, not just the next item
-#define COMMAND_SIZE 2
 #define NUM_COMMANDS 50
-#define BUFFER_SIZE ((NUM_COMMANDS * COMMAND_SIZE) + 1)
+#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
 
 /**
  * DisplayListLogBuffer is a utility class which logs the most recent display
@@ -57,7 +56,7 @@
 
 
 DisplayListLogBuffer::DisplayListLogBuffer() {
-    mBufferFirst = (int*) malloc(BUFFER_SIZE * sizeof(int));
+    mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
     mStart = mBufferFirst;
     mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
     mEnd = mStart;
@@ -71,42 +70,30 @@
  * Called from DisplayListRenderer to output the current buffer into the
  * specified FILE. This only happens in a dumpsys/bugreport operation.
  */
-void DisplayListLogBuffer::outputCommands(FILE *file, const char* opNames[])
+void DisplayListLogBuffer::outputCommands(FILE *file)
 {
-    int *tmpBufferPtr = mStart;
+    OpLog* tmpBufferPtr = mStart;
     while (true) {
         if (tmpBufferPtr == mEnd) {
             break;
         }
-        int level = *tmpBufferPtr++;
+        OpLog* nextOp = tmpBufferPtr++;
         if (tmpBufferPtr > mBufferLast) {
             tmpBufferPtr = mBufferFirst;
         }
-        int op = *tmpBufferPtr++;
-        if (tmpBufferPtr > mBufferLast) {
-            tmpBufferPtr = mBufferFirst;
-        }
-        uint32_t count = (level + 1) * 2;
-        char indent[count + 1];
-        for (uint32_t i = 0; i < count; i++) {
-            indent[i] = ' ';
-        }
-        indent[count] = '\0';
-        fprintf(file, "%s%s\n", indent, opNames[op]);
+
+        fprintf(file, "%*s%s\n", tmpBufferPtr->level*2, "", tmpBufferPtr->label);
     }
 }
 
-void DisplayListLogBuffer::writeCommand(int level, int op) {
-    writeInt(level);
-    writeInt(op);
-}
-
 /**
- * Store the given value in the buffer and increment/wrap the mEnd
- * and mStart values as appropriate.
+ * Store the given level and label in the buffer and increment/wrap the mEnd
+ * and mStart values as appropriate. Label should point to static memory.
  */
-void DisplayListLogBuffer::writeInt(int value) {
-    *((int*)mEnd) = value;
+void DisplayListLogBuffer::writeCommand(int level, const char* label) {
+    mEnd->level = level;
+    mEnd->label = label;
+
     if (mEnd == mBufferLast) {
         mEnd = mBufferFirst;
     } else {
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
index 5d689bb..c884789 100644
--- a/libs/hwui/DisplayListLogBuffer.h
+++ b/libs/hwui/DisplayListLogBuffer.h
@@ -31,19 +31,23 @@
     friend class Singleton<DisplayListLogBuffer>;
 
 public:
-    void writeCommand(int level, int op);
-    void writeInt(int value);
-    void outputCommands(FILE *file, const char* opNames[]);
+    void writeCommand(int level, const char* label);
+    void outputCommands(FILE *file);
 
     bool isEmpty() {
         return (mStart == mEnd);
     }
 
+    struct OpLog {
+        int level;
+        const char* label;
+    };
+
 private:
-    int *mBufferFirst; // where the memory starts
-    int* mStart;       // where the current command stream starts
-    int* mEnd;         // where the current commands end
-    int* mBufferLast;  // where the buffer memory ends
+    OpLog* mBufferFirst; // where the memory starts
+    OpLog* mStart;       // where the current command stream starts
+    OpLog* mEnd;         // where the current commands end
+    OpLog* mBufferLast;  // where the buffer memory ends
 
 };
 
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
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f0c9ce4..5cb629e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -21,6 +21,7 @@
 #include <private/hwui/DrawGlInfo.h>
 
 #include "DisplayListLogBuffer.h"
+#include "DisplayListOp.h"
 #include "DisplayListRenderer.h"
 #include "Caches.h"
 
@@ -31,53 +32,6 @@
 // Display list
 ///////////////////////////////////////////////////////////////////////////////
 
-const char* DisplayList::OP_NAMES[] = {
-    "Save",
-    "Restore",
-    "RestoreToCount",
-    "SaveLayer",
-    "SaveLayerAlpha",
-    "Translate",
-    "Rotate",
-    "Scale",
-    "Skew",
-    "SetMatrix",
-    "ConcatMatrix",
-    "ClipRect",
-    "ClipPath",
-    "ClipRegion",
-    "DrawDisplayList",
-    "DrawLayer",
-    "DrawBitmap",
-    "DrawBitmapMatrix",
-    "DrawBitmapRect",
-    "DrawBitmapData",
-    "DrawBitmapMesh",
-    "DrawPatch",
-    "DrawColor",
-    "DrawRect",
-    "DrawRoundRect",
-    "DrawCircle",
-    "DrawOval",
-    "DrawArc",
-    "DrawPath",
-    "DrawLines",
-    "DrawPoints",
-    "DrawTextOnPath",
-    "DrawPosText",
-    "DrawText",
-    "DrawRects",
-    "ResetShader",
-    "SetupShader",
-    "ResetColorFilter",
-    "SetupColorFilter",
-    "ResetShadow",
-    "SetupShadow",
-    "ResetPaintFilter",
-    "SetupPaintFilter",
-    "DrawGLFunction"
-};
-
 void DisplayList::outputLogBuffer(int fd) {
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     if (logBuffer.isEmpty()) {
@@ -87,7 +41,7 @@
     FILE *file = fdopen(fd, "a");
 
     fprintf(file, "\nRecent DisplayList operations\n");
-    logBuffer.outputCommands(file, OP_NAMES);
+    logBuffer.outputCommands(file);
 
     String8 cachesLog;
     Caches::getInstance().dumpMemoryUsage(cachesLog);
@@ -116,9 +70,7 @@
 }
 
 void DisplayList::clearResources() {
-    sk_free((void*) mReader.base());
-    mReader.setMemory(NULL, 0);
-
+    mDisplayListData = NULL;
     delete mTransformMatrix;
     delete mTransformCamera;
     delete mTransformMatrix3D;
@@ -200,7 +152,6 @@
 }
 
 void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
-
     if (reusing) {
         // re-using display list - clear out previous allocations
         clearResources();
@@ -208,16 +159,13 @@
 
     init();
 
-    const SkWriter32& writer = recorder.writeStream();
-    if (writer.size() == 0) {
+    mDisplayListData = recorder.getDisplayListData();
+    mSize = mDisplayListData->allocator.usedSize();
+
+    if (mSize == 0) {
         return;
     }
 
-    mSize = writer.size();
-    void* buffer = sk_malloc_throw(mSize);
-    writer.flatten(buffer);
-    mReader.setMemory(buffer, mSize);
-
     mFunctorCount = recorder.getFunctorCount();
 
     Caches& caches = Caches::getInstance();
@@ -312,392 +260,17 @@
  * This function is a simplified version of replay(), where we simply retrieve and log the
  * display list. This function should remain in sync with the replay() function.
  */
-void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
-    TextContainer text;
-
-    uint32_t count = (level + 1) * 2;
-    char indent[count + 1];
-    for (uint32_t i = 0; i < count; i++) {
-        indent[i] = ' ';
-    }
-    indent[count] = '\0';
-    ALOGD("%sStart display list (%p, %s, render=%d)", (char*) indent + 2, this,
+void DisplayList::output(uint32_t level) {
+    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
             mName.string(), isRenderable());
 
-    ALOGD("%s%s %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    int saveCount = renderer.getSaveCount() - 1;
-
-    outputViewProperties(renderer, (char*) indent);
-    mReader.rewind();
-
-    while (!mReader.eof()) {
-        int op = mReader.readInt();
-        if (op & OP_MAY_BE_SKIPPED_MASK) {
-            int skip = mReader.readInt();
-            ALOGD("%sSkip %d", (char*) indent, skip);
-            op &= ~OP_MAY_BE_SKIPPED_MASK;
-        }
-
-        switch (op) {
-            case DrawGLFunction: {
-                Functor *functor = (Functor *) getInt();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-            }
-            break;
-            case Save: {
-                int rendererNum = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
-            }
-            break;
-            case Restore: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case RestoreToCount: {
-                int restoreCount = saveCount + getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
-            }
-            break;
-            case SaveLayer: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                int flags = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
-            }
-            break;
-            case SaveLayerAlpha: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int alpha = getInt();
-                int flags = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
-            }
-            break;
-            case Translate: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
-            }
-            break;
-            case Rotate: {
-                float rotation = getFloat();
-                ALOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
-            }
-            break;
-            case Scale: {
-                float sx = getFloat();
-                float sy = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-            }
-            break;
-            case Skew: {
-                float sx = getFloat();
-                float sy = getFloat();
-                ALOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-            }
-            break;
-            case SetMatrix: {
-                SkMatrix* matrix = getMatrix();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
-            }
-            break;
-            case ConcatMatrix: {
-                SkMatrix* matrix = getMatrix();
-                ALOGD("%s%s new concat %p: [%f, %f, %f]   [%f, %f, %f]   [%f, %f, %f]",
-                        (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1),
-                        matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5),
-                        matrix->get(6), matrix->get(7), matrix->get(8));
-            }
-            break;
-            case ClipRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int regionOp = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, regionOp);
-            }
-            break;
-            case ClipPath: {
-                SkPath* path = getPath();
-                int regionOp = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-            }
-            break;
-            case ClipRegion: {
-                SkRegion* region = getRegion();
-                int regionOp = getInt();
-                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-            }
-            break;
-            case DrawDisplayList: {
-                DisplayList* displayList = getDisplayList();
-                int32_t flags = getInt();
-                ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                        displayList, mWidth, mHeight, flags, level + 1);
-                renderer.outputDisplayList(displayList, level + 1);
-            }
-            break;
-            case DrawLayer: {
-                Layer* layer = (Layer*) getInt();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        layer, x, y, paint);
-            }
-            break;
-            case DrawBitmap: {
-                SkBitmap* bitmap = getBitmap();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-            }
-            break;
-            case DrawBitmapMatrix: {
-                SkBitmap* bitmap = getBitmap();
-                SkMatrix* matrix = getMatrix();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, matrix, paint);
-            }
-            break;
-            case DrawBitmapRect: {
-                SkBitmap* bitmap = getBitmap();
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                float f7 = getFloat();
-                float f8 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
-            }
-            break;
-            case DrawBitmapData: {
-                SkBitmap* bitmap = getBitmapData();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %p", (char*) indent, OP_NAMES[op], x, y, paint);
-            }
-            break;
-            case DrawBitmapMesh: {
-                int verticesCount = 0;
-                uint32_t colorsCount = 0;
-                SkBitmap* bitmap = getBitmap();
-                uint32_t meshWidth = getInt();
-                uint32_t meshHeight = getInt();
-                float* vertices = getFloats(verticesCount);
-                bool hasColors = getInt();
-                int* colors = hasColors ? getInts(colorsCount) : NULL;
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawPatch: {
-                int32_t* xDivs = NULL;
-                int32_t* yDivs = NULL;
-                uint32_t* colors = NULL;
-                uint32_t xDivsCount = 0;
-                uint32_t yDivsCount = 0;
-                int8_t numColors = 0;
-                SkBitmap* bitmap = getBitmap();
-                xDivs = getInts(xDivsCount);
-                yDivs = getInts(yDivsCount);
-                colors = getUInts(numColors);
-                float left = getFloat();
-                float top = getFloat();
-                float right = getFloat();
-                float bottom = getFloat();
-                int alpha = getInt();
-                SkXfermode::Mode mode = (SkXfermode::Mode) getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", (char*) indent, OP_NAMES[op],
-                        left, top, right, bottom);
-            }
-            break;
-            case DrawColor: {
-                int color = getInt();
-                int xferMode = getInt();
-                ALOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
-            }
-            break;
-            case DrawRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawRoundRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
-            }
-            break;
-            case DrawCircle: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
-            }
-            break;
-            case DrawOval: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawArc: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                int i1 = getInt();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
-            }
-            break;
-            case DrawPath: {
-                SkPath* path = getPath();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
-            }
-            break;
-            case DrawLines: {
-                int count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawPoints: {
-                int count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case DrawTextOnPath: {
-                getText(&text);
-                int32_t count = getInt();
-                SkPath* path = getPath();
-                float hOffset = getFloat();
-                float vOffset = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawPosText: {
-                getText(&text);
-                int count = getInt();
-                int positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                        text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawText: {
-                getText(&text);
-                int32_t count = getInt();
-                float x = getFloat();
-                float y = getFloat();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                float length = getFloat();
-                ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                        text.text(), text.length(), count, paint);
-            }
-            break;
-            case DrawRects: {
-                int32_t count = 0;
-                float* rects = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                ALOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count / 4, paint);
-            }
-            break;
-            case ResetShader: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupShader: {
-                SkiaShader* shader = getShader();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
-            }
-            break;
-            case ResetColorFilter: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupColorFilter: {
-                SkiaColorFilter *colorFilter = getColorFilter();
-                ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
-            }
-            break;
-            case ResetShadow: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupShadow: {
-                float radius = getFloat();
-                float dx = getFloat();
-                float dy = getFloat();
-                int color = getInt();
-                ALOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                        radius, dx, dy, color);
-            }
-            break;
-            case ResetPaintFilter: {
-                ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
-            }
-            break;
-            case SetupPaintFilter: {
-                int clearBits = getInt();
-                int setBits = getInt();
-                ALOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits);
-            }
-            break;
-            default:
-                ALOGD("Display List error: op not handled: %s%s",
-                        (char*) indent, OP_NAMES[op]);
-                break;
-        }
+    ALOGD("%*s%s %d", level * 4, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    outputViewProperties(level);
+    int flags = DisplayListOp::kOpLogFlag_Recurse;
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        mDisplayListData->displayListOps[i]->output(level, flags);
     }
-    ALOGD("%sDone (%p, %s)", (char*) indent + 2, this, mName.string());
+    ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
 }
 
 void DisplayList::updateMatrix() {
@@ -743,115 +316,68 @@
     }
 }
 
-void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) {
+void DisplayList::outputViewProperties(uint32_t level) {
     updateMatrix();
     if (mLeft != 0 || mTop != 0) {
-        ALOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
+        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
     }
     if (mStaticMatrix) {
-        ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (static)", mStaticMatrix,
-                mStaticMatrix->get(0), mStaticMatrix->get(1),
-                mStaticMatrix->get(2), mStaticMatrix->get(3),
-                mStaticMatrix->get(4), mStaticMatrix->get(5),
-                mStaticMatrix->get(6), mStaticMatrix->get(7),
-                mStaticMatrix->get(8));
+        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
+                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
     }
     if (mAnimationMatrix) {
-        ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (animation)", mAnimationMatrix,
-                mAnimationMatrix->get(0), mAnimationMatrix->get(1),
-                mAnimationMatrix->get(2), mAnimationMatrix->get(3),
-                mAnimationMatrix->get(4), mAnimationMatrix->get(5),
-                mAnimationMatrix->get(6), mAnimationMatrix->get(7),
-                mAnimationMatrix->get(8));
+        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
+                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
-            ALOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
         } else {
-            ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                    indent, "ConcatMatrix", mTransformMatrix,
-                    mTransformMatrix->get(0), mTransformMatrix->get(1),
-                    mTransformMatrix->get(2), mTransformMatrix->get(3),
-                    mTransformMatrix->get(4), mTransformMatrix->get(5),
-                    mTransformMatrix->get(6), mTransformMatrix->get(7),
-                    mTransformMatrix->get(8));
+            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
+                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
         }
     }
     if (mAlpha < 1 && !mCaching) {
         if (!mHasOverlappingRendering) {
-            ALOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
+            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
         } else {
             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
             if (mClipChildren) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
             }
-            ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
                     mMultipliedAlpha, flags);
         }
     }
     if (mClipChildren) {
-        ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
                 (float) mRight - mLeft, (float) mBottom - mTop);
     }
 }
 
 void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
-#if DEBUG_DISPLAY_LIST
-        uint32_t count = (level + 1) * 2;
-        char indent[count + 1];
-        for (uint32_t i = 0; i < count; i++) {
-            indent[i] = ' ';
-        }
-        indent[count] = '\0';
+#if DEBUG_DISPLAYLIST
+    outputViewProperties(level);
 #endif
     updateMatrix();
     if (mLeft != 0 || mTop != 0) {
-        DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate (left, top)", mLeft, mTop);
         renderer.translate(mLeft, mTop);
     }
     if (mStaticMatrix) {
-        DISPLAY_LIST_LOGD(
-                "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (static)", mStaticMatrix,
-                mStaticMatrix->get(0), mStaticMatrix->get(1),
-                mStaticMatrix->get(2), mStaticMatrix->get(3),
-                mStaticMatrix->get(4), mStaticMatrix->get(5),
-                mStaticMatrix->get(6), mStaticMatrix->get(7),
-                mStaticMatrix->get(8));
         renderer.concatMatrix(mStaticMatrix);
     } else if (mAnimationMatrix) {
-        DISPLAY_LIST_LOGD(
-                "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                indent, "ConcatMatrix (animation)", mAnimationMatrix,
-                mAnimationMatrix->get(0), mAnimationMatrix->get(1),
-                mAnimationMatrix->get(2), mAnimationMatrix->get(3),
-                mAnimationMatrix->get(4), mAnimationMatrix->get(5),
-                mAnimationMatrix->get(6), mAnimationMatrix->get(7),
-                mAnimationMatrix->get(8));
         renderer.concatMatrix(mAnimationMatrix);
     }
     if (mMatrixFlags != 0) {
         if (mMatrixFlags == TRANSLATION) {
-            DISPLAY_LIST_LOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
             renderer.translate(mTranslationX, mTranslationY);
         } else {
-            DISPLAY_LIST_LOGD(
-                    "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                    indent, "ConcatMatrix", mTransformMatrix,
-                    mTransformMatrix->get(0), mTransformMatrix->get(1),
-                    mTransformMatrix->get(2), mTransformMatrix->get(3),
-                    mTransformMatrix->get(4), mTransformMatrix->get(5),
-                    mTransformMatrix->get(6), mTransformMatrix->get(7),
-                    mTransformMatrix->get(8));
             renderer.concatMatrix(mTransformMatrix);
         }
     }
     if (mAlpha < 1 && !mCaching) {
         if (!mHasOverlappingRendering) {
-            DISPLAY_LIST_LOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
             renderer.setAlpha(mAlpha);
         } else {
             // TODO: should be able to store the size of a DL at record time and not
@@ -861,53 +387,35 @@
             if (mClipChildren) {
                 flags |= SkCanvas::kClipToLayer_SaveFlag;
             }
-            DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
-                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
-                    mMultipliedAlpha, flags);
             renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
                     mMultipliedAlpha, flags);
         }
     }
     if (mClipChildren) {
-        DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
-                (float) mRight - mLeft, (float) mBottom - mTop);
         renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
                 SkRegion::kIntersect_Op);
     }
 }
 
-/**
- * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
- * in the output() function, since that function processes the same list of opcodes for the
- * purposes of logging display list info for a given view.
- */
 status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
     status_t drawGlStatus = DrawGlInfo::kStatusDone;
-    TextContainer text;
-    mReader.rewind();
 
 #if DEBUG_DISPLAY_LIST
-    uint32_t count = (level + 1) * 2;
-    char indent[count + 1];
-    for (uint32_t i = 0; i < count; i++) {
-        indent[i] = ' ';
-    }
-    indent[count] = '\0';
     Rect* clipRect = renderer.getClipRect();
-    DISPLAY_LIST_LOGD("%sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
-            (char*) indent + 2, this, mName.string(), clipRect->left, clipRect->top,
+    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
+            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
             clipRect->right, clipRect->bottom);
 #endif
 
     renderer.startMark(mName.string());
 
     int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    DISPLAY_LIST_LOGD("%s%s %d %d", indent, "Save",
+    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
     setViewProperties(renderer, level);
 
     if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
-        DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
         renderer.restoreToCount(restoreTo);
         renderer.endMark();
         return drawGlStatus;
@@ -915,469 +423,22 @@
 
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
-
-    while (!mReader.eof()) {
-        int op = mReader.readInt();
-        if (op & OP_MAY_BE_SKIPPED_MASK) {
-            int32_t skip = mReader.readInt();
-            if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) {
-                mReader.skip(skip);
-                DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent,
-                        OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip);
-                continue;
-            } else {
-                op &= ~OP_MAY_BE_SKIPPED_MASK;
-            }
-        }
-        logBuffer.writeCommand(level, op);
-
+    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+        DisplayListOp *op = mDisplayListData->displayListOps[i];
 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
-        Caches::getInstance().eventMark(strlen(OP_NAMES[op]), OP_NAMES[op]);
+        Caches::getInstance().eventMark(strlen(op->name()), op->name());
 #endif
 
-        switch (op) {
-            case DrawGLFunction: {
-                Functor *functor = (Functor *) getInt();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
-                renderer.startMark("GL functor");
-                drawGlStatus |= renderer.callDrawGLFunction(functor, dirty);
-                renderer.endMark();
-            }
-            break;
-            case Save: {
-                int32_t rendererNum = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
-                renderer.save(rendererNum);
-            }
-            break;
-            case Restore: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.restore();
-            }
-            break;
-            case RestoreToCount: {
-                int32_t restoreCount = saveCount + getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
-                renderer.restoreToCount(restoreCount);
-            }
-            break;
-            case SaveLayer: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, paint, flags);
-                renderer.saveLayer(f1, f2, f3, f4, paint, flags);
-            }
-            break;
-            case SaveLayerAlpha: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int32_t alpha = getInt();
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
-                        OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
-                renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
-            }
-            break;
-            case Translate: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
-                renderer.translate(f1, f2);
-            }
-            break;
-            case Rotate: {
-                float rotation = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
-                renderer.rotate(rotation);
-            }
-            break;
-            case Scale: {
-                float sx = getFloat();
-                float sy = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-                renderer.scale(sx, sy);
-            }
-            break;
-            case Skew: {
-                float sx = getFloat();
-                float sy = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
-                renderer.skew(sx, sy);
-            }
-            break;
-            case SetMatrix: {
-                SkMatrix* matrix = getMatrix();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
-                renderer.setMatrix(matrix);
-            }
-            break;
-            case ConcatMatrix: {
-                SkMatrix* matrix = getMatrix();
-                DISPLAY_LIST_LOGD(
-                        "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
-                        (char*) indent, OP_NAMES[op], matrix,
-                        matrix->get(0), matrix->get(1), matrix->get(2),
-                        matrix->get(3), matrix->get(4), matrix->get(5),
-                        matrix->get(6), matrix->get(7), matrix->get(8));
-                renderer.concatMatrix(matrix);
-            }
-            break;
-            case ClipRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, regionOp);
-                renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
-            }
-            break;
-            case ClipPath: {
-                SkPath* path = getPath();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-                renderer.clipPath(path, (SkRegion::Op) regionOp);
-            }
-            break;
-            case ClipRegion: {
-                SkRegion* region = getRegion();
-                int32_t regionOp = getInt();
-                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
-                renderer.clipRegion(region, (SkRegion::Op) regionOp);
-            }
-            break;
-            case DrawDisplayList: {
-                DisplayList* displayList = getDisplayList();
-                int32_t flags = getInt();
-                DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
-                        displayList, mWidth, mHeight, flags, level + 1);
-                drawGlStatus |= renderer.drawDisplayList(displayList, dirty, flags, level + 1);
-            }
-            break;
-            case DrawLayer: {
-                int oldAlpha = -1;
-                Layer* layer = (Layer*) getInt();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                if (mCaching && mMultipliedAlpha < 255) {
-                    oldAlpha = layer->getAlpha();
-                    layer->setAlpha(mMultipliedAlpha);
-                }
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        layer, x, y, paint);
-                drawGlStatus |= renderer.drawLayer(layer, x, y, paint);
-                if (oldAlpha >= 0) {
-                    layer->setAlpha(oldAlpha);
-                }
-            }
-            break;
-            case DrawBitmap: {
-                int oldAlpha = -1;
-                SkBitmap* bitmap = getBitmap();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                if (mCaching && mMultipliedAlpha < 255) {
-                    oldAlpha = paint->getAlpha();
-                    paint->setAlpha(mMultipliedAlpha);
-                }
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
-                if (oldAlpha >= 0) {
-                    paint->setAlpha(oldAlpha);
-                }
-            }
-            break;
-            case DrawBitmapMatrix: {
-                SkBitmap* bitmap = getBitmap();
-                SkMatrix* matrix = getMatrix();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, matrix, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, matrix, paint);
-            }
-            break;
-            case DrawBitmapRect: {
-                SkBitmap* bitmap = getBitmap();
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                float f7 = getFloat();
-                float f8 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], bitmap,
-                        f1, f2, f3, f4, f5, f6, f7, f8,paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
-            }
-            break;
-            case DrawBitmapData: {
-                SkBitmap* bitmap = getBitmapData();
-                float x = getFloat();
-                float y = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        bitmap, x, y, paint);
-                drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
-            }
-            break;
-            case DrawBitmapMesh: {
-                int32_t verticesCount = 0;
-                uint32_t colorsCount = 0;
-
-                SkBitmap* bitmap = getBitmap();
-                uint32_t meshWidth = getInt();
-                uint32_t meshHeight = getInt();
-                float* vertices = getFloats(verticesCount);
-                bool hasColors = getInt();
-                int32_t* colors = hasColors ? getInts(colorsCount) : NULL;
-                SkPaint* paint = getPaint(renderer);
-
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices,
-                        colors, paint);
-            }
-            break;
-            case DrawPatch: {
-                int32_t* xDivs = NULL;
-                int32_t* yDivs = NULL;
-                uint32_t* colors = NULL;
-                uint32_t xDivsCount = 0;
-                uint32_t yDivsCount = 0;
-                int8_t numColors = 0;
-
-                SkBitmap* bitmap = getBitmap();
-
-                xDivs = getInts(xDivsCount);
-                yDivs = getInts(yDivsCount);
-                colors = getUInts(numColors);
-
-                float left = getFloat();
-                float top = getFloat();
-                float right = getFloat();
-                float bottom = getFloat();
-
-                int alpha = getInt();
-                SkXfermode::Mode mode = (SkXfermode::Mode) getInt();
-
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawPatch(bitmap, xDivs, yDivs, colors,
-                        xDivsCount, yDivsCount, numColors, left, top, right, bottom,
-                        alpha, mode);
-            }
-            break;
-            case DrawColor: {
-                int32_t color = getInt();
-                int32_t xferMode = getInt();
-                DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
-                drawGlStatus |= renderer.drawColor(color, (SkXfermode::Mode) xferMode);
-            }
-            break;
-            case DrawRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
-                        f1, f2, f3, f4, paint);
-                drawGlStatus |= renderer.drawRect(f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawRoundRect: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
-                drawGlStatus |= renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint);
-            }
-            break;
-            case DrawCircle: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
-                drawGlStatus |= renderer.drawCircle(f1, f2, f3, paint);
-            }
-            break;
-            case DrawOval: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
-                drawGlStatus |= renderer.drawOval(f1, f2, f3, f4, paint);
-            }
-            break;
-            case DrawArc: {
-                float f1 = getFloat();
-                float f2 = getFloat();
-                float f3 = getFloat();
-                float f4 = getFloat();
-                float f5 = getFloat();
-                float f6 = getFloat();
-                int32_t i1 = getInt();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
-                        (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
-                drawGlStatus |= renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint);
-            }
-            break;
-            case DrawPath: {
-                SkPath* path = getPath();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
-                drawGlStatus |= renderer.drawPath(path, paint);
-            }
-            break;
-            case DrawLines: {
-                int32_t count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawLines(points, count, paint);
-            }
-            break;
-            case DrawPoints: {
-                int32_t count = 0;
-                float* points = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                drawGlStatus |= renderer.drawPoints(points, count, paint);
-            }
-            break;
-            case DrawTextOnPath: {
-                getText(&text);
-                int32_t count = getInt();
-                SkPath* path = getPath();
-                float hOffset = getFloat();
-                float vOffset = getFloat();
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
-                    text.text(), text.length(), count, paint);
-                drawGlStatus |= renderer.drawTextOnPath(text.text(), text.length(), count, path,
-                        hOffset, vOffset, paint);
-            }
-            break;
-            case DrawPosText: {
-                getText(&text);
-                int32_t count = getInt();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
-                        OP_NAMES[op], text.text(), text.length(), count, paint);
-                drawGlStatus |= renderer.drawPosText(text.text(), text.length(), count,
-                        positions, paint);
-            }
-            break;
-            case DrawText: {
-                getText(&text);
-                int32_t count = getInt();
-                float x = getFloat();
-                float y = getFloat();
-                int32_t positionsCount = 0;
-                float* positions = getFloats(positionsCount);
-                SkPaint* paint = getPaint(renderer);
-                float length = getFloat();
-                DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
-                        OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
-                drawGlStatus |= renderer.drawText(text.text(), text.length(), count,
-                        x, y, positions, paint, length);
-            }
-            break;
-            case DrawRects: {
-                int32_t count = 0;
-                float* rects = getFloats(count);
-                SkPaint* paint = getPaint(renderer);
-                DISPLAY_LIST_LOGD("%s%s %d, %p", (char*) indent, OP_NAMES[op], count, paint);
-                drawGlStatus |= renderer.drawRects(rects, count / 4, paint);
-            }
-            break;
-            case ResetShader: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetShader();
-            }
-            break;
-            case SetupShader: {
-                SkiaShader* shader = getShader();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
-                renderer.setupShader(shader);
-            }
-            break;
-            case ResetColorFilter: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetColorFilter();
-            }
-            break;
-            case SetupColorFilter: {
-                SkiaColorFilter *colorFilter = getColorFilter();
-                DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
-                renderer.setupColorFilter(colorFilter);
-            }
-            break;
-            case ResetShadow: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetShadow();
-            }
-            break;
-            case SetupShadow: {
-                float radius = getFloat();
-                float dx = getFloat();
-                float dy = getFloat();
-                int32_t color = getInt();
-                DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
-                        radius, dx, dy, color);
-                renderer.setupShadow(radius, dx, dy, color);
-            }
-            break;
-            case ResetPaintFilter: {
-                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
-                renderer.resetPaintFilter();
-            }
-            break;
-            case SetupPaintFilter: {
-                int32_t clearBits = getInt();
-                int32_t setBits = getInt();
-                DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
-                        clearBits, setBits);
-                renderer.setupPaintFilter(clearBits, setBits);
-            }
-            break;
-            default:
-                DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s",
-                        (char*) indent, OP_NAMES[op]);
-                break;
-        }
+        drawGlStatus |= op->replay(renderer, dirty, flags,
+                saveCount, level, mCaching, mMultipliedAlpha);
+        logBuffer.writeCommand(level, op->name());
     }
 
-    DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
     renderer.restoreToCount(restoreTo);
     renderer.endMark();
 
-    DISPLAY_LIST_LOGD("%sDone (%p, %s), returning %d", (char*) indent + 2, this, mName.string(),
+    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
             drawGlStatus);
     return drawGlStatus;
 }
@@ -1387,7 +448,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DisplayListRenderer::DisplayListRenderer():
-        mCaches(Caches::getInstance()), mWriter(MIN_WRITER_SIZE),
+        mCaches(Caches::getInstance()), mDisplayListData(new DisplayListData),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false),
         mHasDrawOps(false), mFunctorCount(0) {
 }
@@ -1397,8 +458,7 @@
 }
 
 void DisplayListRenderer::reset() {
-    mWriter.reset();
-
+    mDisplayListData = new DisplayListData();
     mCaches.resourceCache.lock();
 
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
@@ -1493,7 +553,7 @@
 
 void DisplayListRenderer::finish() {
     insertRestoreToCount();
-    insertTranlate();
+    insertTranslate();
 }
 
 void DisplayListRenderer::interrupt() {
@@ -1504,15 +564,13 @@
 
 status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
     // Ignore dirty during recording, it matters only when we replay
-    addOp(DisplayList::DrawGLFunction);
-    addInt((int) functor);
+    addDrawOp(new (alloc()) DrawFunctorOp(functor));
     mFunctorCount++;
     return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
 }
 
 int DisplayListRenderer::save(int flags) {
-    addOp(DisplayList::Save);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveOp(flags));
     return OpenGLRenderer::save(flags);
 }
 
@@ -1523,31 +581,25 @@
     }
 
     mRestoreSaveCount--;
-    insertTranlate();
+    insertTranslate();
     OpenGLRenderer::restore();
 }
 
 void DisplayListRenderer::restoreToCount(int saveCount) {
     mRestoreSaveCount = saveCount;
-    insertTranlate();
+    insertTranslate();
     OpenGLRenderer::restoreToCount(saveCount);
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
         SkPaint* p, int flags) {
-    addOp(DisplayList::SaveLayer);
-    addBounds(left, top, right, bottom);
-    addPaint(p);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, p, flags));
     return OpenGLRenderer::save(flags);
 }
 
 int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
         int alpha, int flags) {
-    addOp(DisplayList::SaveLayerAlpha);
-    addBounds(left, top, right, bottom);
-    addInt(alpha);
-    addInt(flags);
+    addStateOp(new (alloc()) SaveLayerAlphaOp(left, top, right, bottom, alpha, flags));
     return OpenGLRenderer::save(flags);
 }
 
@@ -1560,54 +612,47 @@
 }
 
 void DisplayListRenderer::rotate(float degrees) {
-    addOp(DisplayList::Rotate);
-    addFloat(degrees);
+    addStateOp(new (alloc()) RotateOp(degrees));
     OpenGLRenderer::rotate(degrees);
 }
 
 void DisplayListRenderer::scale(float sx, float sy) {
-    addOp(DisplayList::Scale);
-    addPoint(sx, sy);
+    addStateOp(new (alloc()) ScaleOp(sx, sy));
     OpenGLRenderer::scale(sx, sy);
 }
 
 void DisplayListRenderer::skew(float sx, float sy) {
-    addOp(DisplayList::Skew);
-    addPoint(sx, sy);
+    addStateOp(new (alloc()) SkewOp(sx, sy));
     OpenGLRenderer::skew(sx, sy);
 }
 
 void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
-    addOp(DisplayList::SetMatrix);
-    addMatrix(matrix);
+    matrix = refMatrix(matrix);
+    addStateOp(new (alloc()) SetMatrixOp(matrix));
     OpenGLRenderer::setMatrix(matrix);
 }
 
 void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
-    addOp(DisplayList::ConcatMatrix);
-    addMatrix(matrix);
+    matrix = refMatrix(matrix);
+    addStateOp(new (alloc()) ConcatMatrixOp(matrix));
     OpenGLRenderer::concatMatrix(matrix);
 }
 
 bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
         SkRegion::Op op) {
-    addOp(DisplayList::ClipRect);
-    addBounds(left, top, right, bottom);
-    addInt(op);
+    addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
 bool DisplayListRenderer::clipPath(SkPath* path, SkRegion::Op op) {
-    addOp(DisplayList::ClipPath);
-    addPath(path);
-    addInt(op);
+    path = refPath(path);
+    addStateOp(new (alloc()) ClipPathOp(path, op));
     return OpenGLRenderer::clipPath(path, op);
 }
 
 bool DisplayListRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
-    addOp(DisplayList::ClipRegion);
-    addRegion(region);
-    addInt(op);
+    region = refRegion(region);
+    addStateOp(new (alloc()) ClipRegionOp(region, op));
     return OpenGLRenderer::clipRegion(region, op);
 }
 
@@ -1616,84 +661,71 @@
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
 
-    addOp(DisplayList::DrawDisplayList);
-    addDisplayList(displayList);
-    addInt(flags);
+    // TODO: To be safe, the display list should be ref-counted in the
+    //       resources cache, but we rely on the caller (UI toolkit) to
+    //       do the right thing for now
+
+    addDrawOp(new (alloc()) DrawDisplayListOp(displayList, flags));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    addOp(DisplayList::DrawLayer);
-    addLayer(layer);
-    addPoint(x, y);
-    addPaint(paint);
+    mLayers.add(layer);
+    mCaches.resourceCache.incrementRefcount(layer);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawLayerOp(layer, x, y, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(left, top,
-            left + bitmap->width(), top + bitmap->height());
-    uint32_t* location = addOp(DisplayList::DrawBitmap, reject);
-    addBitmap(bitmap);
-    addPoint(left, top);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, left, top, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
-    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
-    const mat4 transform(*matrix);
-    transform.mapRect(r);
+    bitmap = refBitmap(bitmap);
+    matrix = refMatrix(matrix);
+    paint = refPaint(paint);
 
-    const bool reject = quickRejectNoScissor(r.left, r.top, r.right, r.bottom);
-    uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject);
-    addBitmap(bitmap);
-    addMatrix(matrix);
-    addPaint(paint);
-    addSkip(location);
+    addDrawOp(new (alloc()) DrawBitmapMatrixOp(bitmap, matrix, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(dstLeft, dstTop, dstRight, dstBottom);
-    uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject);
-    addBitmap(bitmap);
-    addBounds(srcLeft, srcTop, srcRight, srcBottom);
-    addBounds(dstLeft, dstTop, dstRight, dstBottom);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
+                    srcLeft, srcTop, srcRight, srcBottom,
+                    dstLeft, dstTop, dstRight, dstBottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top,
         SkPaint* paint) {
-    const bool reject = quickRejectNoScissor(left, top,
-            left + bitmap->width(), top + bitmap->height());
-    uint32_t* location = addOp(DisplayList::DrawBitmapData, reject);
-    addBitmapData(bitmap);
-    addPoint(left, top);
-    addPaint(paint);
-    addSkip(location);
+    bitmap = refBitmapData(bitmap);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, left, top, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
         float* vertices, int* colors, SkPaint* paint) {
-    addOp(DisplayList::DrawBitmapMesh);
-    addBitmap(bitmap);
-    addInt(meshWidth);
-    addInt(meshHeight);
-    addFloats(vertices, (meshWidth + 1) * (meshHeight + 1) * 2);
-    if (colors) {
-        addInt(1);
-        addInts(colors, (meshWidth + 1) * (meshHeight + 1));
-    } else {
-        addInt(0);
-    }
-    addPaint(paint);
+    int count = (meshWidth + 1) * (meshHeight + 1) * 2;
+    bitmap = refBitmap(bitmap);
+    vertices = refBuffer<float>(vertices, count);
+    paint = refPaint(paint);
+    colors = refBuffer<int>(colors, count);
+
+    addDrawOp(new (alloc()) DrawBitmapMeshOp(bitmap, meshWidth, meshHeight,
+                    vertices, colors, paint));
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1704,132 +736,114 @@
     SkXfermode::Mode mode;
     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
 
-    const bool reject = quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawPatch, reject);
-    addBitmap(bitmap);
-    addInts(xDivs, width);
-    addInts(yDivs, height);
-    addUInts(colors, numColors);
-    addBounds(left, top, right, bottom);
-    addInt(alpha);
-    addInt(mode);
-    addSkip(location);
+    bitmap = refBitmap(bitmap);
+    xDivs = refBuffer<int>(xDivs, width);
+    yDivs = refBuffer<int>(yDivs, height);
+    colors = refBuffer<uint32_t>(colors, numColors);
+
+    addDrawOp(new (alloc()) DrawPatchOp(bitmap, xDivs, yDivs, colors, width, height, numColors,
+                    left, top, right, bottom, alpha, mode));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
-    addOp(DisplayList::DrawColor);
-    addInt(color);
-    addInt(mode);
+    addDrawOp(new (alloc()) DrawColorOp(color, mode));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
-            quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawRect, reject);
-    addBounds(left, top, right, bottom);
-    addPaint(paint);
-    addSkip(location);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, SkPaint* paint) {
-    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
-            quickRejectNoScissor(left, top, right, bottom);
-    uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
-    addBounds(left, top, right, bottom);
-    addPoint(rx, ry);
-    addPaint(paint);
-    addSkip(location);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
-    addOp(DisplayList::DrawCircle);
-    addPoint(x, y);
-    addFloat(radius);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    addOp(DisplayList::DrawOval);
-    addBounds(left, top, right, bottom);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    addOp(DisplayList::DrawArc);
-    addBounds(left, top, right, bottom);
-    addPoint(startAngle, sweepAngle);
-    addInt(useCenter ? 1 : 0);
-    addPaint(paint);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
+                    startAngle, sweepAngle, useCenter, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    float left, top, offset;
-    uint32_t width, height;
-    computePathBounds(path, paint, left, top, offset, width, height);
+    path = refPath(path);
+    paint = refPaint(paint);
 
-    left -= offset;
-    top -= offset;
-
-    const bool reject = quickRejectNoScissor(left, top, left + width, top + height);
-    uint32_t* location = addOp(DisplayList::DrawPath, reject);
-    addPath(path);
-    addPaint(paint);
-    addSkip(location);
+    addDrawOp(new (alloc()) DrawPathOp(path, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
-    addOp(DisplayList::DrawLines);
-    addFloats(points, count);
-    addPaint(paint);
+    points = refBuffer<float>(points, count);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawLinesOp(points, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {
-    addOp(DisplayList::DrawPoints);
-    addFloats(points, count);
-    addPaint(paint);
+    points = refBuffer<float>(points, count);
+    paint = refPaint(paint);
+
+    addDrawOp(new (alloc()) DrawPointsOp(points, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
         SkPath* path, float hOffset, float vOffset, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
-    addOp(DisplayList::DrawTextOnPath);
-    addText(text, bytesCount);
-    addInt(count);
-    addPath(path);
-    addFloat(hOffset);
-    addFloat(vOffset);
+
     paint->setAntiAlias(true);
-    SkPaint* addedPaint = addPaint(paint);
-    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-    fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    text = refText(text, bytesCount);
+    path = refPath(path);
+    paint = refPaint(paint);
+
+    DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
+            hOffset, vOffset, paint);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
+    }
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (!text || count <= 0) return DrawGlInfo::kStatusDone;
-    addOp(DisplayList::DrawPosText);
-    addText(text, bytesCount);
-    addInt(count);
-    addFloats(positions, count * 2);
+
     paint->setAntiAlias(true);
-    SkPaint* addedPaint = addPaint(paint);
-    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-    fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    text = refText(text, bytesCount);
+    positions = refBuffer<float>(positions, count * 2);
+    paint = refPaint(paint);
+
+    DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
+    }
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1847,75 +861,96 @@
     paint->setAntiAlias(true);
     if (length < 0.0f) length = paint->measureText(text, bytesCount);
 
-    bool reject = false;
-    if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
-        SkPaint::FontMetrics metrics;
-        paint->getFontMetrics(&metrics, 0.0f);
-        reject = quickRejectNoScissor(x, y + metrics.fTop, x + length, y + metrics.fBottom);
-    }
+    text = refText(text, bytesCount);
+    positions = refBuffer<float>(positions, count * 2);
+    paint = refPaint(paint);
 
-    uint32_t* location = addOp(DisplayList::DrawText, reject);
-    addText(text, bytesCount);
-    addInt(count);
-    addFloat(x);
-    addFloat(y);
-    addFloats(positions, count * 2);
-    SkPaint* addedPaint = addPaint(paint);
-    if (!reject) {
-        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
-        fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
+    DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count, x, y, positions, paint, length);
+    if (addDrawOp(op)) {
+        // precache if draw operation is visible
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
+        fontRenderer.precache(paint, text, count, *mSnapshot->transform);
     }
-    addFloat(length);
-    addSkip(location);
     return DrawGlInfo::kStatusDone;
 }
 
 status_t DisplayListRenderer::drawRects(const float* rects, int count, SkPaint* paint) {
     if (count <= 0) return DrawGlInfo::kStatusDone;
 
-    addOp(DisplayList::DrawRects);
-    addFloats(rects, count * 4);
-    addPaint(paint);
+    rects = refBuffer<float>(rects, count);
+    paint = refPaint(paint);
+    addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint));
     return DrawGlInfo::kStatusDone;
 }
 
 void DisplayListRenderer::resetShader() {
-    addOp(DisplayList::ResetShader);
+    addStateOp(new (alloc()) ResetShaderOp());
 }
 
 void DisplayListRenderer::setupShader(SkiaShader* shader) {
-    addOp(DisplayList::SetupShader);
-    addShader(shader);
+    shader = refShader(shader);
+    addStateOp(new (alloc()) SetupShaderOp(shader));
 }
 
 void DisplayListRenderer::resetColorFilter() {
-    addOp(DisplayList::ResetColorFilter);
+    addStateOp(new (alloc()) ResetColorFilterOp());
 }
 
 void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    addOp(DisplayList::SetupColorFilter);
-    addColorFilter(filter);
+    filter = refColorFilter(filter);
+    addStateOp(new (alloc()) SetupColorFilterOp(filter));
 }
 
 void DisplayListRenderer::resetShadow() {
-    addOp(DisplayList::ResetShadow);
+    addStateOp(new (alloc()) ResetShadowOp());
 }
 
 void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    addOp(DisplayList::SetupShadow);
-    addFloat(radius);
-    addPoint(dx, dy);
-    addInt(color);
+    addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
 }
 
 void DisplayListRenderer::resetPaintFilter() {
-    addOp(DisplayList::ResetPaintFilter);
+    addStateOp(new (alloc()) ResetPaintFilterOp());
 }
 
 void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
-    addOp(DisplayList::SetupPaintFilter);
-    addInt(clearBits);
-    addInt(setBits);
+    addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
+}
+
+void DisplayListRenderer::insertRestoreToCount() {
+    if (mRestoreSaveCount >= 0) {
+        DisplayListOp* op = new (alloc()) RestoreToCountOp(mRestoreSaveCount);
+        mDisplayListData->displayListOps.add(op);
+        mRestoreSaveCount = -1;
+    }
+}
+
+void DisplayListRenderer::insertTranslate() {
+    if (mHasTranslate) {
+        if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
+            DisplayListOp* op = new (alloc()) TranslateOp(mTranslateX, mTranslateY);
+            mDisplayListData->displayListOps.add(op);
+            mTranslateX = mTranslateY = 0.0f;
+        }
+        mHasTranslate = false;
+    }
+}
+
+void DisplayListRenderer::addStateOp(StateOp* op) {
+    addOpInternal(op);
+}
+
+bool DisplayListRenderer::addDrawOp(DrawOp* op) {
+    bool rejected = false;
+    Rect localBounds;
+    if (op->getLocalBounds(localBounds)) {
+        rejected = quickRejectNoScissor(localBounds.left, localBounds.top,
+                localBounds.right, localBounds.bottom);
+        op->setQuickRejected(rejected);
+    }
+    mHasDrawOps = true;
+    addOpInternal(op);
+    return !rejected;
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index f55f1f2..b25288b 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -31,6 +31,7 @@
 
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
+#include "utils/LinearAllocator.h"
 
 namespace android {
 namespace uirenderer {
@@ -60,6 +61,18 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class DisplayListRenderer;
+class DisplayListOp;
+class DrawOp;
+class StateOp;
+
+/**
+ * Refcounted structure that holds data used in display list stream
+ */
+class DisplayListData: public LightRefBase<DisplayListData> {
+public:
+    LinearAllocator allocator;
+    Vector<DisplayListOp*> displayListOps;
+};
 
 /**
  * Replays recorded drawing commands.
@@ -69,66 +82,13 @@
     DisplayList(const DisplayListRenderer& recorder);
     ANDROID_API ~DisplayList();
 
-    // IMPORTANT: Update the intialization of OP_NAMES in the .cpp file
-    //            when modifying this file
-    enum Op {
-        // Non-drawing operations
-        Save = 0,
-        Restore,
-        RestoreToCount,
-        SaveLayer,
-        SaveLayerAlpha,
-        Translate,
-        Rotate,
-        Scale,
-        Skew,
-        SetMatrix,
-        ConcatMatrix,
-        ClipRect,
-        ClipPath,
-        ClipRegion,
-        // Drawing operations
-        DrawDisplayList,
-        DrawLayer,
-        DrawBitmap,
-        DrawBitmapMatrix,
-        DrawBitmapRect,
-        DrawBitmapData,
-        DrawBitmapMesh,
-        DrawPatch,
-        DrawColor,
-        DrawRect,
-        DrawRoundRect,
-        DrawCircle,
-        DrawOval,
-        DrawArc,
-        DrawPath,
-        DrawLines,
-        DrawPoints,
-        DrawTextOnPath,
-        DrawPosText,
-        DrawText,
-        DrawRects,
-        ResetShader,
-        SetupShader,
-        ResetColorFilter,
-        SetupColorFilter,
-        ResetShadow,
-        SetupShadow,
-        ResetPaintFilter,
-        SetupPaintFilter,
-        DrawGLFunction,
-    };
-
     // See flags defined in DisplayList.java
     enum ReplayFlag {
         kReplayFlag_ClipChildren = 0x1
     };
 
-    static const char* OP_NAMES[];
-
     void setViewProperties(OpenGLRenderer& renderer, uint32_t level);
-    void outputViewProperties(OpenGLRenderer& renderer, char* indent);
+    void outputViewProperties(uint32_t level);
 
     ANDROID_API size_t getSize();
     ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
@@ -138,7 +98,7 @@
 
     status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
 
-    void output(OpenGLRenderer& renderer, uint32_t level = 0);
+    void output(uint32_t level = 0);
 
     ANDROID_API void reset();
 
@@ -423,78 +383,6 @@
         const char* mText;
     };
 
-    SkBitmap* getBitmap() {
-        return (SkBitmap*) getInt();
-    }
-
-    SkBitmap* getBitmapData() {
-        return (SkBitmap*) getInt();
-    }
-
-    SkiaShader* getShader() {
-        return (SkiaShader*) getInt();
-    }
-
-    SkiaColorFilter* getColorFilter() {
-        return (SkiaColorFilter*) getInt();
-    }
-
-    inline int32_t getIndex() {
-        return mReader.readInt();
-    }
-
-    inline int32_t getInt() {
-        return mReader.readInt();
-    }
-
-    inline uint32_t getUInt() {
-        return mReader.readU32();
-    }
-
-    SkMatrix* getMatrix() {
-        return (SkMatrix*) getInt();
-    }
-
-    SkPath* getPath() {
-        return (SkPath*) getInt();
-    }
-
-    SkRegion* getRegion() {
-        return (SkRegion*) getInt();
-    }
-
-    SkPaint* getPaint(OpenGLRenderer& renderer) {
-        return renderer.filterPaint((SkPaint*) getInt());
-    }
-
-    DisplayList* getDisplayList() {
-        return (DisplayList*) getInt();
-    }
-
-    inline float getFloat() {
-        return mReader.readScalar();
-    }
-
-    int32_t* getInts(uint32_t& count) {
-        count = getInt();
-        return (int32_t*) mReader.skip(count * sizeof(int32_t));
-    }
-
-    uint32_t* getUInts(int8_t& count) {
-        count = getInt();
-        return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
-    }
-
-    float* getFloats(int32_t& count) {
-        count = getInt();
-        return (float*) mReader.skip(count * sizeof(float));
-    }
-
-    void getText(TextContainer* text) {
-        size_t length = text->mByteLength = getInt();
-        text->mText = (const char*) mReader.skip(length);
-    }
-
     Vector<SkBitmap*> mBitmapResources;
     Vector<SkBitmap*> mOwnedBitmapResources;
     Vector<SkiaColorFilter*> mFilterResources;
@@ -507,7 +395,7 @@
     Vector<SkiaShader*> mShaders;
     Vector<Layer*> mLayers;
 
-    mutable SkFlattenableReadBuffer mReader;
+    sp<DisplayListData> mDisplayListData;
 
     size_t mSize;
 
@@ -634,8 +522,8 @@
 
     ANDROID_API void reset();
 
-    const SkWriter32& writeStream() const {
-        return mWriter;
+    sp<DisplayListData> getDisplayListData() const {
+        return mDisplayListData;
     }
 
     const Vector<SkBitmap*>& getBitmapResources() const {
@@ -683,102 +571,32 @@
     }
 
 private:
-    void insertRestoreToCount() {
-        if (mRestoreSaveCount >= 0) {
-            mWriter.writeInt(DisplayList::RestoreToCount);
-            addInt(mRestoreSaveCount);
-            mRestoreSaveCount = -1;
-        }
-    }
+    void insertRestoreToCount();
+    void insertTranslate();
 
-    void insertTranlate() {
-        if (mHasTranslate) {
-            if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
-                mWriter.writeInt(DisplayList::Translate);
-                addPoint(mTranslateX, mTranslateY);
-                mTranslateX = mTranslateY = 0.0f;
-            }
-            mHasTranslate = false;
-        }
-    }
-
-    inline void addOp(const DisplayList::Op drawOp) {
+    LinearAllocator& alloc() { return mDisplayListData->allocator; }
+    void addStateOp(StateOp* op);
+    bool addDrawOp(DrawOp* op); // returns true if op not rejected
+    void addOpInternal(DisplayListOp* op) {
         insertRestoreToCount();
-        insertTranlate();
-        mWriter.writeInt(drawOp);
-        mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
+        insertTranslate();
+        mDisplayListData->displayListOps.add(op);
     }
 
-    uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) {
-        insertRestoreToCount();
-        insertTranlate();
-        mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
-        if (reject) {
-            mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp);
-            mWriter.writeInt(0xdeaddead);
-            mBufferSize = mWriter.size();
-            return mWriter.peek32(mBufferSize - sizeof(int32_t));
-        }
-        mWriter.writeInt(drawOp);
-        return NULL;
+    template<class T>
+    inline T* refBuffer(const T* srcBuffer, int32_t count) {
+        if (srcBuffer == NULL) return NULL;
+        T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
+        memcpy(dstBuffer, srcBuffer, count * sizeof(T));
+        return dstBuffer;
     }
 
-    inline void addSkip(uint32_t* location) {
-        if (location) {
-            *location = (int32_t) (mWriter.size() - mBufferSize);
-        }
+    inline char* refText(const char* text, size_t byteLength) {
+        return (char*) refBuffer<uint8_t>((uint8_t*)text, byteLength);
     }
 
-    inline void addInt(int32_t value) {
-        mWriter.writeInt(value);
-    }
-
-    inline void addSize(uint32_t w, uint32_t h) {
-        mWriter.writeInt(w);
-        mWriter.writeInt(h);
-    }
-
-    void addInts(const int32_t* values, uint32_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(int32_t));
-    }
-
-    void addUInts(const uint32_t* values, int8_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(uint32_t));
-    }
-
-    inline void addFloat(float value) {
-        mWriter.writeScalar(value);
-    }
-
-    void addFloats(const float* values, int32_t count) {
-        mWriter.writeInt(count);
-        mWriter.write(values, count * sizeof(float));
-    }
-
-    inline void addPoint(float x, float y) {
-        mWriter.writeScalar(x);
-        mWriter.writeScalar(y);
-    }
-
-    inline void addBounds(float left, float top, float right, float bottom) {
-        mWriter.writeScalar(left);
-        mWriter.writeScalar(top);
-        mWriter.writeScalar(right);
-        mWriter.writeScalar(bottom);
-    }
-
-    inline void addText(const void* text, size_t byteLength) {
-        mWriter.writeInt(byteLength);
-        mWriter.writePad(text, byteLength);
-    }
-
-    inline void addPath(SkPath* path) {
-        if (!path) {
-            addInt((int) NULL);
-            return;
-        }
+    inline SkPath* refPath(SkPath* path) {
+        if (!path) return NULL;
 
         SkPath* pathCopy = mPathMap.valueFor(path);
         if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
@@ -792,13 +610,11 @@
             mCaches.resourceCache.incrementRefcount(path);
             mSourcePaths.add(path);
         }
-
-        addInt((int) pathCopy);
+        return pathCopy;
     }
 
-    inline SkPaint* addPaint(SkPaint* paint) {
+    inline SkPaint* refPaint(SkPaint* paint) {
         if (!paint) {
-            addInt((int) NULL);
             return paint;
         }
 
@@ -810,14 +626,11 @@
             mPaints.add(paintCopy);
         }
 
-        addInt((int) paintCopy);
-
         return paintCopy;
     }
 
-    inline SkRegion* addRegion(SkRegion* region) {
+    inline SkRegion* refRegion(SkRegion* region) {
         if (!region) {
-            addInt((int) NULL);
             return region;
         }
 
@@ -830,53 +643,35 @@
             mRegions.add(regionCopy);
         }
 
-        addInt((int) regionCopy);
-
         return regionCopy;
     }
 
-    inline void addDisplayList(DisplayList* displayList) {
-        // TODO: To be safe, the display list should be ref-counted in the
-        //       resources cache, but we rely on the caller (UI toolkit) to
-        //       do the right thing for now
-        addInt((int) displayList);
-    }
-
-    inline void addMatrix(SkMatrix* matrix) {
+    inline SkMatrix* refMatrix(SkMatrix* matrix) {
         // Copying the matrix is cheap and prevents against the user changing the original
         // matrix before the operation that uses it
         SkMatrix* copy = new SkMatrix(*matrix);
-        addInt((int) copy);
         mMatrices.add(copy);
+        return copy;
     }
 
-    inline void addLayer(Layer* layer) {
-        addInt((int) layer);
-        mLayers.add(layer);
-        mCaches.resourceCache.incrementRefcount(layer);
-    }
-
-    inline void addBitmap(SkBitmap* bitmap) {
+    inline SkBitmap* refBitmap(SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
         // contents, and drawing again. The only fix would be to always copy it the first time,
         // which doesn't seem worth the extra cycles for this unlikely case.
-        addInt((int) bitmap);
         mBitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
+        return bitmap;
     }
 
-    void addBitmapData(SkBitmap* bitmap) {
-        addInt((int) bitmap);
+    inline SkBitmap* refBitmapData(SkBitmap* bitmap) {
         mOwnedBitmapResources.add(bitmap);
         mCaches.resourceCache.incrementRefcount(bitmap);
+        return bitmap;
     }
 
-    inline void addShader(SkiaShader* shader) {
-        if (!shader) {
-            addInt((int) NULL);
-            return;
-        }
+    inline SkiaShader* refShader(SkiaShader* shader) {
+        if (!shader) return NULL;
 
         SkiaShader* shaderCopy = mShaderMap.valueFor(shader);
         // TODO: We also need to handle generation ID changes in compose shaders
@@ -887,14 +682,13 @@
             mShaders.add(shaderCopy);
             mCaches.resourceCache.incrementRefcount(shaderCopy);
         }
-
-        addInt((int) shaderCopy);
+        return shaderCopy;
     }
 
-    inline void addColorFilter(SkiaColorFilter* colorFilter) {
-        addInt((int) colorFilter);
+    inline SkiaColorFilter* refColorFilter(SkiaColorFilter* colorFilter) {
         mFilterResources.add(colorFilter);
         mCaches.resourceCache.incrementRefcount(colorFilter);
+        return colorFilter;
     }
 
     Vector<SkBitmap*> mBitmapResources;
@@ -919,12 +713,10 @@
 
     Vector<Layer*> mLayers;
 
-    uint32_t mBufferSize;
-
     int mRestoreSaveCount;
 
     Caches& mCaches;
-    SkWriter32 mWriter;
+    sp<DisplayListData> mDisplayListData;
 
     float mTranslateX;
     float mTranslateY;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f55bc9d..c9e51bb 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1096,7 +1096,7 @@
         rects.push(r.fTop);
         rects.push(r.fRight);
         rects.push(r.fBottom);
-        count++;
+        count += 4;
         it.next();
     }
 
@@ -1732,7 +1732,7 @@
 
 void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
     if (displayList) {
-        displayList->output(*this, level);
+        displayList->output(level);
     }
 }
 
@@ -2082,7 +2082,6 @@
  */
 void OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) {
     int color = paint->getColor();
-    SkPaint::Style style = paint->getStyle();
     SkXfermode::Mode mode = getXfermode(paint->getXfermode());
     bool isAA = paint->isAntiAlias();
 
@@ -3193,8 +3192,7 @@
     Vertex mesh[count * 6];
     Vertex* vertex = mesh;
 
-    for (int i = 0; i < count; i++) {
-        int index = i * 4;
+    for (int index = 0; index < count; index += 4) {
         float l = rects[index + 0];
         float t = rects[index + 1];
         float r = rects[index + 2];
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index e490151..45c619e 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -122,8 +122,6 @@
     float rescaleX = 1.0f;
     float rescaleY = 1.0f;
 
-    const float meshWidth = right - left;
-
     if (xStretchCount > 0) {
         uint32_t stretchSize = 0;
         for (uint32_t i = 1; i < mXCount; i += 2) {
diff --git a/libs/hwui/PathRenderer.cpp b/libs/hwui/PathRenderer.cpp
index dd13d79..d59e36f 100644
--- a/libs/hwui/PathRenderer.cpp
+++ b/libs/hwui/PathRenderer.cpp
@@ -596,7 +596,6 @@
     SkPath::Iter iter(path, forceClose);
     SkPoint pts[4];
     SkPath::Verb v;
-    Vertex* newVertex = 0;
     while (SkPath::kDone_Verb != (v = iter.next(pts))) {
             switch (v) {
                 case SkPath::kMove_Verb:
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 80f39ff90..5f4bb5a 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -171,22 +171,19 @@
     }
 
 private:
-    static inline float min(float a, float b) { return (a < b) ? a : b; }
-    static inline float max(float a, float b) { return (a > b) ? a : b; }
-
     void intersectWith(Rect& tmp) const {
-        tmp.left = max(left, tmp.left);
-        tmp.top = max(top, tmp.top);
-        tmp.right = min(right, tmp.right);
-        tmp.bottom = min(bottom, tmp.bottom);
+        tmp.left = fmaxf(left, tmp.left);
+        tmp.top = fmaxf(top, tmp.top);
+        tmp.right = fminf(right, tmp.right);
+        tmp.bottom = fminf(bottom, tmp.bottom);
     }
 
     Rect intersectWith(float l, float t, float r, float b) const {
         Rect tmp;
-        tmp.left = max(left, l);
-        tmp.top = max(top, t);
-        tmp.right = min(right, r);
-        tmp.bottom = min(bottom, b);
+        tmp.left = fmaxf(left, l);
+        tmp.top = fmaxf(top, t);
+        tmp.right = fminf(right, r);
+        tmp.bottom = fminf(bottom, b);
         return tmp;
     }