Add SkChunkAlloc::unalloc() to undo the last allocation, useful if the caller wants...
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 30 Mar 2009 21:02:14 +0000 (21:02 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 30 Mar 2009 21:02:14 +0000 (21:02 +0000)
Call unalloc if a paint (or other cached object) is already in our list for picture recording
Use correct CompareType macro in SkCanvas::quickReject

git-svn-id: http://skia.googlecode.com/svn/trunk@138 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkChunkAlloc.h
samplecode/SampleApp.cpp
src/core/SkCanvas.cpp
src/core/SkChunkAlloc.cpp
src/core/SkPaint.cpp
src/core/SkPictureRecord.cpp
xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj

index 0e9ad18..810e7b6 100644 (file)
@@ -46,6 +46,14 @@ public:
         return this->alloc(bytes, kThrow_AllocFailType);
     }
     
+    /** Call this to unalloc the most-recently allocated ptr by alloc(). On
+        success, the number of bytes freed is returned, or 0 if the block could
+        not be unallocated. This is a hint to the underlying allocator that
+        the previous allocation may be reused, but the implementation is free
+        to ignore this call (and return 0).
+     */
+    size_t unalloc(void* ptr);
+    
     size_t totalCapacity() const { return fTotalCapacity; }
     
 private:
index 3a81902..635fde1 100644 (file)
@@ -299,12 +299,12 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
         case kRaster_CanvasType:
             break;
         case kPicture_CanvasType:
-            if (false) {
+            if (true) {
                 SkPicture* pict = new SkPicture(*fPicture);
                 fPicture->unref();
                 orig->drawPicture(*pict);
                 pict->unref();
-            } if (true) {
+            } else if (true) {
                 SkDynamicMemoryWStream ostream;
                 fPicture->serialize(&ostream);
                 fPicture->unref();
index 00461b0..16c94c2 100644 (file)
@@ -943,8 +943,8 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
         return true;
     }
     
-    SkScalarCompareType userT = SkScalarAs2sCompliment(top);
-    SkScalarCompareType userB = SkScalarAs2sCompliment(bottom);
+    SkScalarCompareType userT = SkScalarToCompareType(top);
+    SkScalarCompareType userB = SkScalarToCompareType(bottom);
     
     // check for invalid user Y coordinates (i.e. empty)
     if (userT >= userB) {
index ae37ec0..83272c5 100644 (file)
@@ -23,6 +23,10 @@ struct SkChunkAlloc::Block {
     char*   fFreePtr;
     // data[] follows
     
+    char* startOfData() {
+        return reinterpret_cast<char*>(this + 1);
+    }
+
     void freeChain() {    // this can be null
         Block* block = this;
         while (block) {
@@ -89,7 +93,7 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) {
     if (block) {
         //    block->fNext = fBlock;
         block->fFreeSize = size;
-        block->fFreePtr = (char*)block + sizeof(Block);
+        block->fFreePtr = block->startOfData();
         
         fTotalCapacity += size;
     }
@@ -118,3 +122,18 @@ void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) {
     return ptr;
 }
 
+size_t SkChunkAlloc::unalloc(void* ptr) {
+    size_t bytes = 0;
+    Block* block = fBlock;
+    if (block) {
+        char* cPtr = reinterpret_cast<char*>(ptr);
+        char* start = block->startOfData();
+        if (start <= cPtr && cPtr < block->fFreePtr) {
+            bytes = block->fFreePtr - cPtr;
+            block->fFreeSize += bytes;
+            block->fFreePtr = cPtr;
+        }
+    }
+    return bytes;
+}
+
index 691da41..da70c74 100644 (file)
@@ -1278,50 +1278,143 @@ SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const
 
 #include "SkStream.h"
 
+static uintptr_t asint(const void* p) {
+    return reinterpret_cast<uintptr_t>(p);
+}
+
+union Scalar32 {
+    SkScalar    fScalar;
+    uint32_t    f32;
+};
+
+static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) {
+    SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
+    Scalar32 tmp;
+    tmp.fScalar = value;
+    *ptr = tmp.f32;
+    return ptr + 1;
+}
+
+static SkScalar read_scalar(const uint32_t*& ptr) {
+    SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
+    Scalar32 tmp;
+    tmp.f32 = *ptr++;
+    return tmp.fScalar;
+}
+
+static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
+    SkASSERT(a == (uint8_t)a);
+    SkASSERT(b == (uint8_t)b);
+    SkASSERT(c == (uint8_t)c);
+    SkASSERT(d == (uint8_t)d);
+    return (a << 24) | (b << 16) | (c << 8) | d;
+}
+
+enum FlatFlags {
+    kHasTypeface_FlatFlag   = 0x01,
+    kHasEffects_FlatFlag    = 0x02
+};
+
+// The size of a flat paint's POD fields
+static const uint32_t kPODPaintSize =   5 * sizeof(SkScalar) +
+                                        1 * sizeof(SkColor) +
+                                        1 * sizeof(uint16_t) +
+                                        6 * sizeof(uint8_t);
+
+/*  To save space/time, we analyze the paint, and write a truncated version of
+    it if there are not tricky elements like shaders, etc.
+ */
 void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
-    buffer.writeTypeface(this->getTypeface());
-    buffer.writeScalar(this->getTextSize());
-    buffer.writeScalar(this->getTextScaleX());
-    buffer.writeScalar(this->getTextSkewX());
-    buffer.writeFlattenable(this->getPathEffect());
-    buffer.writeFlattenable(this->getShader());
-    buffer.writeFlattenable(this->getXfermode());
-    buffer.writeFlattenable(this->getMaskFilter());
-    buffer.writeFlattenable(this->getColorFilter());
-    buffer.writeFlattenable(this->getRasterizer());
-    buffer.writeFlattenable(this->getLooper());
-    buffer.write32(this->getColor());
-    buffer.writeScalar(this->getStrokeWidth());
-    buffer.writeScalar(this->getStrokeMiter());
-    buffer.write16(this->getFlags());
-    buffer.write8(this->getTextAlign());
-    buffer.write8(this->getStrokeCap());
-    buffer.write8(this->getStrokeJoin());
-    buffer.write8(this->getStyle());
-    buffer.write8(this->getTextEncoding());
+    uint8_t flatFlags = 0;
+    if (this->getTypeface()) {
+        flatFlags |= kHasTypeface_FlatFlag;
+    }
+    if (asint(this->getPathEffect()) |
+        asint(this->getShader()) |
+        asint(this->getXfermode()) |
+        asint(this->getMaskFilter()) |
+        asint(this->getColorFilter()) |
+        asint(this->getRasterizer()) |
+        asint(this->getLooper())) {
+        flatFlags |= kHasEffects_FlatFlag;
+    }
+    
+    SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
+    uint32_t* ptr = buffer.reserve(kPODPaintSize);
+
+    ptr = write_scalar(ptr, this->getTextSize());
+    ptr = write_scalar(ptr, this->getTextScaleX());
+    ptr = write_scalar(ptr, this->getTextSkewX());
+    ptr = write_scalar(ptr, this->getStrokeWidth());
+    ptr = write_scalar(ptr, this->getStrokeMiter());
+    *ptr++ = this->getColor();
+    *ptr++ = (this->getFlags() << 16) | (this->getTextAlign() << 8) | flatFlags;
+    *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
+                    this->getStyle(), this->getTextEncoding());
+
+    // now we're done with ptr and the (pre)reserved space. If we need to write
+    // additional fields, use the buffer directly
+    if (flatFlags & kHasTypeface_FlatFlag) {
+        buffer.writeTypeface(this->getTypeface());
+    }
+    if (flatFlags & kHasEffects_FlatFlag) {
+        buffer.writeFlattenable(this->getPathEffect());
+        buffer.writeFlattenable(this->getShader());
+        buffer.writeFlattenable(this->getXfermode());
+        buffer.writeFlattenable(this->getMaskFilter());
+        buffer.writeFlattenable(this->getColorFilter());
+        buffer.writeFlattenable(this->getRasterizer());
+        buffer.writeFlattenable(this->getLooper());
+    }
 }
 
 void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
-    this->setTypeface(buffer.readTypeface());
-    this->setTextSize(buffer.readScalar());
-    this->setTextScaleX(buffer.readScalar());
-    this->setTextSkewX(buffer.readScalar());
-    this->setPathEffect((SkPathEffect*) buffer.readFlattenable())->safeUnref();
-    this->setShader((SkShader*) buffer.readFlattenable())->safeUnref();
-    this->setXfermode((SkXfermode*) buffer.readFlattenable())->safeUnref();
-    this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable())->safeUnref();
-    this->setColorFilter((SkColorFilter*) buffer.readFlattenable())->safeUnref();
-    this->setRasterizer((SkRasterizer*) buffer.readFlattenable())->safeUnref();
-    this->setLooper((SkDrawLooper*) buffer.readFlattenable())->safeUnref();
-    this->setColor(buffer.readU32());
-    this->setStrokeWidth(buffer.readScalar());
-    this->setStrokeMiter(buffer.readScalar());
-    this->setFlags(buffer.readU16());
-    this->setTextAlign((SkPaint::Align) buffer.readU8());
-    this->setStrokeCap((SkPaint::Cap) buffer.readU8());
-    this->setStrokeJoin((SkPaint::Join) buffer.readU8());
-    this->setStyle((SkPaint::Style) buffer.readU8());
-    this->setTextEncoding((SkPaint::TextEncoding) buffer.readU8());
+    SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
+    const void* podData = buffer.skip(kPODPaintSize);
+    const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
+    
+    // the order we read must match the order we wrote in flatten()
+    this->setTextSize(read_scalar(pod));
+    this->setTextScaleX(read_scalar(pod));
+    this->setTextSkewX(read_scalar(pod));
+    this->setStrokeWidth(read_scalar(pod));
+    this->setStrokeMiter(read_scalar(pod));    
+    this->setColor(*pod++);
+
+    uint32_t tmp = *pod++;
+    this->setFlags(tmp >> 16);
+    this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xFF));
+    uint8_t flatFlags = tmp & 0xFF;
+
+    tmp = *pod++;
+    this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
+    this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
+    this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
+    this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
+
+    if (flatFlags & kHasTypeface_FlatFlag) {
+        this->setTypeface(buffer.readTypeface());
+    } else {
+        this->setTypeface(NULL);
+    }
+
+    if (flatFlags & kHasEffects_FlatFlag) {
+        this->setPathEffect((SkPathEffect*) buffer.readFlattenable())->safeUnref();
+        this->setShader((SkShader*) buffer.readFlattenable())->safeUnref();
+        this->setXfermode((SkXfermode*) buffer.readFlattenable())->safeUnref();
+        this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable())->safeUnref();
+        this->setColorFilter((SkColorFilter*) buffer.readFlattenable())->safeUnref();
+        this->setRasterizer((SkRasterizer*) buffer.readFlattenable())->safeUnref();
+        this->setLooper((SkDrawLooper*) buffer.readFlattenable())->safeUnref();
+    } else {
+        this->setPathEffect(NULL);
+        this->setShader(NULL);
+        this->setXfermode(NULL);
+        this->setMaskFilter(NULL);
+        this->setColorFilter(NULL);
+        this->setRasterizer(NULL);
+        this->setLooper(NULL);
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index c1fadc6..ed47d64 100644 (file)
@@ -514,8 +514,7 @@ int SkPictureRecord::find(SkTDArray<const SkFlatBitmap* >& bitmaps, const SkBitm
     int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(), 
         bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
     if (index >= 0) {
-//        SkBitmap bitmap;
-//        flat->unflatten(&bitmap); // balance ref count
+        (void)fHeap.unalloc(flat);
         return bitmaps[index]->index();
     }
     index = ~index;
@@ -529,8 +528,10 @@ int SkPictureRecord::find(SkTDArray<const SkFlatMatrix* >& matrices, const SkMat
     SkFlatMatrix* flat = SkFlatMatrix::Flatten(&fHeap, *matrix, fMatrixIndex);
     int index = SkTSearch<SkFlatData>((const SkFlatData**) matrices.begin(), 
         matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
-    if (index >= 0)
+    if (index >= 0) {
+        (void)fHeap.unalloc(flat);
         return matrices[index]->index();
+    }
     index = ~index;
     *matrices.insert(index) = flat;
     return fMatrixIndex++;
@@ -546,6 +547,7 @@ int SkPictureRecord::find(SkTDArray<const SkFlatPaint* >& paints, const SkPaint*
     int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(), 
         paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
     if (index >= 0) {
+        (void)fHeap.unalloc(flat);
         return paints[index]->index();
     }
 
@@ -558,8 +560,10 @@ int SkPictureRecord::find(SkTDArray<const SkFlatRegion* >& regions, const SkRegi
     SkFlatRegion* flat = SkFlatRegion::Flatten(&fHeap, region, fRegionIndex);
     int index = SkTSearch<SkFlatData>((const SkFlatData**) regions.begin(), 
         regions.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
-    if (index >= 0)
+    if (index >= 0) {
+        (void)fHeap.unalloc(flat);
         return regions[index]->index();
+    }
     index = ~index;
     *regions.insert(index) = flat;
     return fRegionIndex++;
index 24777c7..813856b 100644 (file)
@@ -68,6 +68,8 @@
                008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008C4D970F77DAEE0056981C /* SampleHairline.cpp */; };
                009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */; };
                00A41E4B0EFC312F00C9CBEB /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; };
+               00FACE3C0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */; };
+               00FACE680F7D23DD00F8A7FF /* SkWriter32_largeBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */; };
                0156F80407C56A3000C6122B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0156F80307C56A3000C6122B /* Foundation.framework */; };
                01FC44D507BD3BB800D228F4 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01FC44D407BD3BB800D228F4 /* Quartz.framework */; };
                8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
                009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFontScalerTest.cpp; path = ../../samplecode/SampleFontScalerTest.cpp; sourceTree = SOURCE_ROOT; };
                00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleArc.cpp; path = ../../samplecode/SampleArc.cpp; sourceTree = SOURCE_ROOT; };
                00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; };
+               00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLargeBlock_malloc.cpp; path = ../../src/utils/SkLargeBlock_malloc.cpp; sourceTree = SOURCE_ROOT; };
+               00FACE3F0F7D167400F8A7FF /* SkLargeBlock_remap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLargeBlock_remap.cpp; path = ../../src/utils/SkLargeBlock_remap.cpp; sourceTree = SOURCE_ROOT; };
+               00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkWriter32_largeBlock.cpp; path = ../../src/utils/SkWriter32_largeBlock.cpp; sourceTree = SOURCE_ROOT; };
+               00FACE600F7D22CF00F8A7FF /* SkWriter32_noLargeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkWriter32_noLargeBlock.cpp; path = ../../src/utils/SkWriter32_noLargeBlock.cpp; sourceTree = SOURCE_ROOT; };
                0156F80307C56A3000C6122B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
                01FC44D407BD3BB800D228F4 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = /System/Library/Frameworks/Quartz.framework; sourceTree = "<absolute>"; };
                0867D6ABFE840B52C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
                                002884490EFAA35C0083E387 /* core.xcodeproj */,
                                002884B40EFAB69F0083E387 /* maccore.xcodeproj */,
                                00003C8C0EFC230E000FF73A /* effects.xcodeproj */,
+                               00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */,
+                               00FACE3F0F7D167400F8A7FF /* SkLargeBlock_remap.cpp */,
+                               00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */,
+                               00FACE600F7D22CF00F8A7FF /* SkWriter32_noLargeBlock.cpp */,
                        );
                        name = CICarbonSample;
                        sourceTree = "<group>";
                                007A7CB30F01658C00A2D6EE /* SamplePicture.cpp in Sources */,
                                0041CE440F00A12400695E8C /* SampleLines.cpp in Sources */,
                                008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */,
+                               00FACE3C0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp in Sources */,
+                               00FACE680F7D23DD00F8A7FF /* SkWriter32_largeBlock.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };