This is just the first version and shows how I intend to orchestrate this. Future...
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 7 Mar 2014 15:53:01 +0000 (15:53 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 7 Mar 2014 15:53:01 +0000 (15:53 +0000)
track the portion of the bitmap required
track any resizing that might be required
actually preload something

R=bsalomon@google.com, mtklein@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/187833003

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

gyp/core.gypi
src/core/SkOffsetTable.h [new file with mode: 0644]
src/core/SkPicturePlayback.cpp
src/core/SkPicturePlayback.h
src/core/SkPictureRecord.cpp
src/core/SkPictureRecord.h

index e4f73e3d081f651cad35fdf442444509626c12d2..a1eed0a72989e03042aebd6a15adb897aa00b45b 100644 (file)
         '<(skia_src_path)/core/SkMessageBus.h',
         '<(skia_src_path)/core/SkMetaData.cpp',
         '<(skia_src_path)/core/SkMipMap.cpp',
-        '<(skia_src_path)/core/SkReadBuffer.cpp',
-        '<(skia_src_path)/core/SkWriteBuffer.cpp',
+        '<(skia_src_path)/core/SkOffsetTable.h',
         '<(skia_src_path)/core/SkPackBits.cpp',
         '<(skia_src_path)/core/SkPaint.cpp',
         '<(skia_src_path)/core/SkPaintOptionsAndroid.cpp',
         '<(skia_src_path)/core/SkQuadTreePicture.h',
         '<(skia_src_path)/core/SkRasterClip.cpp',
         '<(skia_src_path)/core/SkRasterizer.cpp',
+        '<(skia_src_path)/core/SkReadBuffer.cpp',
         '<(skia_src_path)/core/SkRect.cpp',
         '<(skia_src_path)/core/SkRefDict.cpp',
         '<(skia_src_path)/core/SkRegion.cpp',
         '<(skia_src_path)/core/SkUnPreMultiply.cpp',
         '<(skia_src_path)/core/SkUtils.cpp',
         '<(skia_src_path)/core/SkValidatingReadBuffer.cpp',
+        '<(skia_src_path)/core/SkWriteBuffer.cpp',
         '<(skia_src_path)/core/SkWriter32.cpp',
         '<(skia_src_path)/core/SkXfermode.cpp',
 
diff --git a/src/core/SkOffsetTable.h b/src/core/SkOffsetTable.h
new file mode 100644 (file)
index 0000000..60c6264
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkOffsetTable_DEFINED
+#define SkOffsetTable_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkTDArray.h"
+
+// A 2D table of skp offsets. Each row is indexed by an int. This is used
+// to store the command offsets that reference a particular bitmap using
+// the bitmap's index in the bitmap heap as the 'id' here. It has to be
+// ref-countable so SkPicturePlayback can take ownership of it.
+// Note that this class assumes that the ids are densely packed.
+
+// TODO: This needs to be sped up. We could replace the offset table with
+// a hash table.
+class SkOffsetTable : public SkRefCnt {
+public:
+    SkOffsetTable() {}
+    ~SkOffsetTable() {
+        fOffsetArrays.deleteAll();
+    }
+
+    // Record that this 'id' is used by the command starting at this 'offset'.
+    // Offsets for a given 'id' should always be added in increasing order.
+    void add(int id, size_t offset) {
+        if (id >= fOffsetArrays.count()) {
+            int oldCount = fOffsetArrays.count();
+            fOffsetArrays.setCount(id+1);
+            for (int i = oldCount; i <= id; ++i) {
+                fOffsetArrays[i] = NULL;
+            }
+        }
+
+        if (NULL == fOffsetArrays[id]) {
+            fOffsetArrays[id] = SkNEW(OffsetArray);
+        }
+        fOffsetArrays[id]->add(offset);
+    }
+
+    int numIDs() const {
+        return fOffsetArrays.count(); 
+    }
+
+    // Do the offsets of any commands referencing this ID fall in the 
+    // range [min, max] (both inclusive)
+    bool overlap(int id, size_t min, size_t max) {
+        SkASSERT(id < fOffsetArrays.count());
+
+        if (NULL == fOffsetArrays[id]) {
+            return false;
+        }
+
+        // If this id has an offset array it should have at least one use
+        SkASSERT(fOffsetArrays[id]->count() > 0);
+        if (max < fOffsetArrays[id]->min() || min > fOffsetArrays[id]->max()) {
+            return false;
+        }
+
+        return true;
+    }
+
+    bool includes(int id, size_t offset) {
+        SkASSERT(id < fOffsetArrays.count());
+
+        OffsetArray* array = fOffsetArrays[id];
+
+        for (int i = 0; i < array->fOffsets.count(); ++i) {
+            if (array->fOffsets[i] == offset) {
+                return true;
+            } else if (array->fOffsets[i] > offset) {
+                return false;
+            }
+        }
+
+        // Calls to 'includes' should be gaurded by an overlap() call, so we
+        // should always find something.
+        SkASSERT(0);
+        return false;
+    }
+
+protected:
+    class OffsetArray {
+    public:
+        void add(size_t offset) { 
+            SkASSERT(fOffsets.count() == 0 || offset > this->max());
+            *fOffsets.append() = offset;  
+        }
+        size_t min() const { 
+            SkASSERT(fOffsets.count() > 0);
+            return fOffsets[0]; 
+        }
+        size_t max() const { 
+            SkASSERT(fOffsets.count() > 0);
+            return fOffsets[fOffsets.count()-1]; 
+        }
+        int count() const {
+            return fOffsets.count();
+        }
+
+        SkTDArray<size_t> fOffsets;
+    };
+
+    SkTDArray<OffsetArray*> fOffsetArrays;
+
+private:
+    typedef SkRefCnt INHERITED;
+};
+
+#endif
index 967dfeea504d32063452fc80c97ba10eab00dbe1..ab315c11489b505dc630227ca22f35fbfe1d60bf 100644 (file)
@@ -5,15 +5,16 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "SkPicturePlayback.h"
-#include "SkPictureRecord.h"
-#include "SkTypeface.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
 #include <new>
 #include "SkBBoxHierarchy.h"
+#include "SkOffsetTable.h"
+#include "SkPicturePlayback.h"
+#include "SkPictureRecord.h"
 #include "SkPictureStateTree.h"
+#include "SkReadBuffer.h"
+#include "SkTypeface.h"
 #include "SkTSort.h"
+#include "SkWriteBuffer.h"
 
 template <typename T> int SafeCount(const T* obj) {
     return obj ? obj->count() : 0;
@@ -101,6 +102,8 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCop
     fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap));
     fPathHeap.reset(SkSafeRef(record.fPathHeap));
 
+    fBitmapUseOffsets.reset(SkSafeRef(record.fBitmapUseOffsets.get()));
+
     // ensure that the paths bounds are pre-computed
     if (fPathHeap.get()) {
         for (int i = 0; i < fPathHeap->count(); i++) {
@@ -719,6 +722,50 @@ static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) {
     return (DrawType) op;
 }
 
+// The activeOps parameter is actually "const SkTDArray<SkPictureStateTree::Draw*>&".
+// It represents the operations about to be drawn, as generated by some spatial
+// subdivision helper class. It should already be in 'fOffset' sorted order.
+void SkPicturePlayback::preLoadBitmaps(const SkTDArray<void*>& activeOps) {
+    if (0 == activeOps.count() || NULL == fBitmapUseOffsets) {
+        return;
+    }
+
+    SkTDArray<int> active;
+
+    SkAutoTDeleteArray<bool> needToCheck(new bool[fBitmapUseOffsets->numIDs()]);
+    for (int i = 0; i < fBitmapUseOffsets->numIDs(); ++i) {
+        needToCheck.get()[i] = true;
+    }
+
+    uint32_t max = ((SkPictureStateTree::Draw*)activeOps[activeOps.count()-1])->fOffset;
+
+    for (int i = 0; i < activeOps.count(); ++i) {
+        SkPictureStateTree::Draw* draw = (SkPictureStateTree::Draw*) activeOps[i];
+
+        for (int j = 0; j < fBitmapUseOffsets->numIDs(); ++j) {
+            if (!needToCheck.get()[j]) {
+                continue;
+            }
+
+            if (!fBitmapUseOffsets->overlap(j, draw->fOffset, max)) {
+                needToCheck.get()[j] = false;
+                continue;
+            }
+
+            if (!fBitmapUseOffsets->includes(j, draw->fOffset)) {
+                continue;
+            }
+
+            *active.append() = j;
+            needToCheck.get()[j] = false;
+        }
+    }
+
+    for (int i = 0; i < active.count(); ++i) {
+        SkDebugf("preload texture %d\n", active[i]);
+    }
+}
+
 void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) {
 #ifdef ENABLE_TIME_DRAW
     SkAutoTime  at("SkPicture::draw", 50);
@@ -739,26 +786,26 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
 
     SkReader32 reader(fOpData->bytes(), fOpData->size());
     TextContainer text;
-    SkTDArray<void*> results;
+    SkTDArray<void*> activeOps;
 
     if (NULL != fStateTree && NULL != fBoundingHierarchy) {
         SkRect clipBounds;
         if (canvas.getClipBounds(&clipBounds)) {
             SkIRect query;
             clipBounds.roundOut(&query);
-            fBoundingHierarchy->search(query, &results);
-            if (results.count() == 0) {
+            fBoundingHierarchy->search(query, &activeOps);
+            if (activeOps.count() == 0) {
                 return;
             }
             SkTQSort<SkPictureStateTree::Draw>(
-                reinterpret_cast<SkPictureStateTree::Draw**>(results.begin()),
-                reinterpret_cast<SkPictureStateTree::Draw**>(results.end()-1));
+                reinterpret_cast<SkPictureStateTree::Draw**>(activeOps.begin()),
+                reinterpret_cast<SkPictureStateTree::Draw**>(activeOps.end()-1));
         }
     }
 
     SkPictureStateTree::Iterator it = (NULL == fStateTree) ?
         SkPictureStateTree::Iterator() :
-        fStateTree->getIterator(results, &canvas);
+        fStateTree->getIterator(activeOps, &canvas);
 
     if (it.isValid()) {
         uint32_t skipTo = it.draw();
@@ -768,6 +815,8 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback)
         reader.setOffset(skipTo);
     }
 
+    this->preLoadBitmaps(activeOps);
+
     // Record this, so we can concat w/ it if we encounter a setMatrix()
     SkMatrix initialMatrix = canvas.getTotalMatrix();
     int originalSaveCount = canvas.getSaveCount();
index 48d782696d3732c0c4b14f86df90489136e8f36d..178a408aee6e138f44667849a8f77f29c01f00e3 100644 (file)
@@ -31,6 +31,7 @@ class SkStream;
 class SkWStream;
 class SkBBoxHierarchy;
 class SkPictureStateTree;
+class SkOffsetTable;
 
 struct SkPictInfo {
     enum Flags {
@@ -107,6 +108,8 @@ protected:
     virtual void postDraw(int opIndex);
 #endif
 
+    void preLoadBitmaps(const SkTDArray<void*>& results);
+
 private:
     class TextContainer {
     public:
@@ -225,6 +228,7 @@ private:
     SkTRefArray<SkPaint>* fPaints;
 
     SkData* fOpData;    // opcodes and parameters
+    SkAutoTUnref<SkOffsetTable> fBitmapUseOffsets;
 
     SkPicture** fPictureRefs;
     int fPictureCount;
index 213d1aa4544f8960a3337880d0c5b8b0763901e4..b9e8b93843e2415914efacea1d465ecae3ea45e5 100644 (file)
@@ -11,6 +11,7 @@
 #include "SkRRect.h"
 #include "SkBBoxHierarchy.h"
 #include "SkDevice.h"
+#include "SkOffsetTable.h"
 #include "SkPictureStateTree.h"
 #include "SkSurface.h"
 
@@ -44,6 +45,7 @@ SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
     fBitmapHeap = SkNEW(SkBitmapHeap);
     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
     fPathHeap = NULL;   // lazy allocate
+
 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
     fFirstSavedLayerIndex = kNoSavedLayerIndex;
 #endif
@@ -1125,10 +1127,11 @@ void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar
     size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
     this->addPaintPtr(paint);
-    this->addBitmap(bitmap);
+    int bitmapID = this->addBitmap(bitmap);
     this->addScalar(left);
     this->addScalar(top);
     this->validate(initialOffset, size);
+    this->trackBitmapUse(bitmapID, initialOffset);
 }
 
 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
@@ -1152,11 +1155,12 @@ void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect*
     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
              == fWriter.bytesWritten());
     this->addPaintPtr(paint);
-    this->addBitmap(bitmap);
+    int bitmapID = this->addBitmap(bitmap);
     this->addRectPtr(src);  // may be null
     this->addRect(dst);
     this->addInt(flags);
     this->validate(initialOffset, size);
+    this->trackBitmapUse(bitmapID, initialOffset);
 }
 
 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
@@ -1174,9 +1178,10 @@ void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m
     size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
     this->addPaintPtr(paint);
-    this->addBitmap(bitmap);
+    int bitmapID = this->addBitmap(bitmap);
     this->addMatrix(matrix);
     this->validate(initialOffset, size);
+    this->trackBitmapUse(bitmapID, initialOffset);
 }
 
 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
@@ -1194,10 +1199,11 @@ void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& cent
     size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
     this->addPaintPtr(paint);
-    this->addBitmap(bitmap);
+    int bitmapID = this->addBitmap(bitmap);
     this->addIRect(center);
     this->addRect(dst);
     this->validate(initialOffset, size);
+    this->trackBitmapUse(bitmapID, initialOffset);
 }
 
 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
@@ -1215,10 +1221,11 @@ void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
     size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
     SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
     this->addPaintPtr(paint);
-    this->addBitmap(bitmap);
+    int bitmapID = this->addBitmap(bitmap);
     this->addInt(left);
     this->addInt(top);
     this->validate(initialOffset, size);
+    this->trackBitmapUse(bitmapID, initialOffset);
 }
 
 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
@@ -1612,13 +1619,34 @@ SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
     return SkSurface::NewPicture(info.fWidth, info.fHeight);
 }
 
-void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
+void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
+#ifndef SK_ALLOW_BITMAP_TRACKING
+    return;
+#endif
+
+    if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
+        return;
+    }
+
+    if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
+        return;
+    }
+
+    if (NULL == fBitmapUseOffsets) {
+        fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
+    }
+
+    fBitmapUseOffsets->add(bitmapID, offset);
+}
+
+int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
     const int index = fBitmapHeap->insert(bitmap);
     // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
     // release builds, the invalid value will be recorded so that the reader will know that there
     // was a problem.
     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
     this->addInt(index);
+    return index;
 }
 
 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
index e7c6d7f343760fab21e3dc0cb37fd2303715025d..e91c1c5c1229ffba2d71e2ee9258273f19c0d7c5 100644 (file)
@@ -19,8 +19,9 @@
 #include "SkTemplates.h"
 #include "SkWriter32.h"
 
-class SkPictureStateTree;
 class SkBBoxHierarchy;
+class SkOffsetTable;
+class SkPictureStateTree;
 
 // These macros help with packing and unpacking a single byte value and
 // a 3 byte value into/out of a uint32_t
@@ -164,7 +165,9 @@ private:
         fWriter.writeScalar(scalar);
     }
 
-    void addBitmap(const SkBitmap& bitmap);
+    // The command at 'offset' in the skp uses the specified bitmap
+    void trackBitmapUse(int bitmapID, size_t offset);
+    int addBitmap(const SkBitmap& bitmap);
     void addMatrix(const SkMatrix& matrix);
     const SkFlatData* addPaint(const SkPaint& paint) { return this->addPaintPtr(&paint); }
     const SkFlatData* addPaintPtr(const SkPaint* paint);
@@ -294,6 +297,8 @@ private:
     bool     fOptsEnabled;
     int      fInitialSaveCount;
 
+    SkAutoTUnref<SkOffsetTable> fBitmapUseOffsets;
+
     friend class SkPicturePlayback;
     friend class SkPictureTester; // for unit testing