check-point for pipe: flatten/unflatten objects for single paint
still need replacement policy



git-svn-id: http://skia.googlecode.com/svn/trunk@1294 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index d2bf3af..04625b7 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -21,8 +21,27 @@
 #include "SkGPipe.h"
 #include "SkGPipePriv.h"
 #include "SkStream.h"
+#include "SkTSearch.h"
 #include "SkTypeface.h"
 #include "SkWriter32.h"
+#include "SkColorFilter.h"
+#include "SkMaskFilter.h"
+#include "SkRasterizer.h"
+#include "SkShader.h"
+
+static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
+    SkASSERT(paintFlat < kCount_PaintFlats);
+    switch (paintFlat) {
+        case kColorFilter_PaintFlat:    return paint.getColorFilter();
+        case kMaskFilter_PaintFlat:     return paint.getMaskFilter();
+        case kPathEffect_PaintFlat:     return paint.getPathEffect();
+        case kRasterizer_PaintFlat:     return paint.getRasterizer();
+        case kShader_PaintFlat:         return paint.getShader();
+        case kXfermode_PaintFlat:       return paint.getXfermode();
+    }
+    SkASSERT(!"never gets here");
+    return NULL;
+}
 
 static size_t estimateFlattenSize(const SkPath& path) {
     int n = path.countPoints();
@@ -40,18 +59,6 @@
     return bytes;
 }
 
-static void writeRegion(SkWriter32* writer, const SkRegion& rgn) {
-    size_t size = rgn.flatten(NULL);
-    SkASSERT(SkAlign4(size) == size);
-    rgn.flatten(writer->reserve(size));
-}
-
-static void writeMatrix(SkWriter32* writer, const SkMatrix& matrix) {
-    size_t size = matrix.flatten(NULL);
-    SkASSERT(SkAlign4(size) == size);
-    matrix.flatten(writer->reserve(size));
-}
-
 static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
     SkASSERT(typeface);
     SkDynamicMemoryWStream stream;
@@ -151,7 +158,21 @@
             fBytesNotified += bytes;
         }
     }
-    
+
+    struct FlatData {
+        uint32_t    fIndex; // always > 0
+        uint32_t    fSize;
+
+        void*       data() { return (char*)this + sizeof(*this); }
+        
+        static int Compare(const FlatData* a, const FlatData* b) {
+            return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize));
+        }
+    };
+    SkTDArray<FlatData*> fFlatArray;
+    int fCurrFlatIndex[kCount_PaintFlats];
+    int flattenToIndex(SkFlattenable* obj, PaintFlats);
+
     SkTDArray<SkPaint*> fPaints;
     unsigned writePaint(const SkPaint&);
 
@@ -167,6 +188,47 @@
     typedef SkCanvas INHERITED;
 };
 
+// return 0 for NULL (or unflattenable obj), or index-base-1
+int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
+    if (NULL == obj) {
+        return 0;
+    }
+    
+    SkFlattenable::Factory fact = obj->getFactory();
+    if (NULL == fact) {
+        return 0;
+    }
+
+    SkFlattenableWriteBuffer tmpWriter(1024);
+    tmpWriter.writeFlattenable(obj);
+    size_t len = tmpWriter.size();
+    size_t allocSize = len + sizeof(FlatData);
+
+    SkAutoSMalloc<1024> storage(allocSize);
+    FlatData* flat = (FlatData*)storage.get();
+    flat->fSize = len;
+    tmpWriter.flatten(flat->data());
+
+    int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(),
+                                    fFlatArray.count(), flat, sizeof(flat),
+                                    &FlatData::Compare);
+    if (index < 0) {
+        index = ~index;
+        FlatData* copy = (FlatData*)sk_malloc_throw(allocSize);
+        memcpy(copy, flat, allocSize);
+        *fFlatArray.insert(index) = copy;
+        // call this after the insert, so that count() will have been grown
+        copy->fIndex = fFlatArray.count();
+//        SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex);
+
+        if (this->needOpBytes(len)) {
+            this->writeOp(kDef_PaintFlat_DrawOp, paintflat, copy->fIndex);
+            fWriter.write(copy->data(), len);
+        }
+    }
+    return fFlatArray[index]->fIndex;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #define MIN_BLOCK_SIZE  (16 * 1024)
@@ -176,6 +238,7 @@
     fController = controller;
     fDone = false;
     fBlockSize = 0; // need first block from controller
+    sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex));
 
     // always begin with 1 default paint
     *fPaints.append() = SkNEW(SkPaint);
@@ -192,6 +255,7 @@
     this->finish();
 
     fPaints.deleteAll();
+    fFlatArray.freeAll();
 }
 
 bool SkGPipeCanvas::needOpBytes(size_t needed) {
@@ -332,7 +396,7 @@
         NOTIFY_SETUP(this);
         if (this->needOpBytes(matrix.flatten(NULL))) {
             this->writeOp(kConcat_DrawOp);
-            writeMatrix(&fWriter, matrix);
+            SkWriteMatrix(&fWriter, matrix);
         }
     }
     return this->INHERITED::concat(matrix);
@@ -342,7 +406,7 @@
     NOTIFY_SETUP(this);
     if (this->needOpBytes(matrix.flatten(NULL))) {
         this->writeOp(kSetMatrix_DrawOp);
-        writeMatrix(&fWriter, matrix);
+        SkWriteMatrix(&fWriter, matrix);
     }
     this->INHERITED::setMatrix(matrix);
 }
@@ -370,7 +434,7 @@
     NOTIFY_SETUP(this);
     if (this->needOpBytes(region.flatten(NULL))) {
         this->writeOp(kClipRegion_DrawOp, 0, rgnOp);
-        writeRegion(&fWriter, region);
+        SkWriteRegion(&fWriter, region);
     }
     return this->INHERITED::clipRegion(region, rgnOp);
 }
@@ -519,7 +583,7 @@
 
             path.flatten(fWriter);
             if (matrix) {
-                writeMatrix(&fWriter, *matrix);
+                SkWriteMatrix(&fWriter, *matrix);
             }
         }
     }
@@ -693,14 +757,23 @@
         base.setTypeface(paint.getTypeface());
     }
 
+    for (int i = 0; i < kCount_PaintFlats; i++) {
+        int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i);
+        SkASSERT(index >= 0 && index <= fFlatArray.count());
+        if (index != fCurrFlatIndex[i]) {
+            last = ptr;
+            *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index);
+            fCurrFlatIndex[i] = index;
+        }
+    }
+
     size_t size = (char*)ptr - (char*)storage;
     if (size && this->needOpBytes(size)) {
-        this->writeOp(kPaintOp_DrawOp, 0, 0);
-        size_t size = (char*)ptr - (char*)storage;
-        *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS;
-        fWriter.write(storage, (char*)ptr - (char*)storage);
+        this->writeOp(kPaintOp_DrawOp, 0, size);
+//        *last |= kLastOp_PaintOpFlag << PAINTOPS_DATA_BITS;
+        fWriter.write(storage, size);
         for (size_t i = 0; i < size/4; i++) {
-            SkDebugf("[%d] %08X\n", i, storage[i]);
+//            SkDebugf("[%d] %08X\n", i, storage[i]);
         }
     }
     return 0;