Perform multi core rendering in bench_pictures.
Add a flag in SkGPipeWriter for threadsafe drawing.
Add a deferred pipe controller to SamplePipeControllers, which can
be called to play back in multiple threads.
Depends on http://codereview.appspot.com/6459105/
Review URL: https://codereview.appspot.com/6482068
git-svn-id: http://skia.googlecode.com/svn/trunk@5371 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index ce83c83..803685a 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -426,17 +426,32 @@
private:
SkBitmapHeapEntry* fHeapEntry;
const SkBitmap* fBitmap;
+ SkBitmap fBitmapStorage;
};
BitmapHolder::BitmapHolder(SkReader32* reader, uint32_t op32,
SkGPipeState* state) {
- unsigned index = DrawOp_unpackData(op32);
- if (shouldFlattenBitmaps(state->getFlags())) {
+ const unsigned flags = state->getFlags();
+ const unsigned index = DrawOp_unpackData(op32);
+ if (shouldFlattenBitmaps(flags)) {
fHeapEntry = NULL;
fBitmap = state->getBitmap(index);
} else {
- fHeapEntry = state->getSharedHeap()->getEntry(index);
- fBitmap = fHeapEntry->getBitmap();
+ SkBitmapHeapEntry* entry = state->getSharedHeap()->getEntry(index);
+ if (SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag)) {
+ // Make a shallow copy for thread safety. Each thread will point to the same SkPixelRef,
+ // which is thread safe.
+ fBitmapStorage = *entry->getBitmap();
+ fBitmap = &fBitmapStorage;
+ // Release the ref on the bitmap now, since we made our own copy.
+ entry->releaseRef();
+ fHeapEntry = NULL;
+ } else {
+ SkASSERT(!shouldFlattenBitmaps(flags));
+ SkASSERT(!SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag));
+ fHeapEntry = entry;
+ fBitmap = fHeapEntry->getBitmap();
+ }
}
}
diff --git a/src/pipe/utils/SamplePipeControllers.cpp b/src/pipe/utils/SamplePipeControllers.cpp
index 740d1b8..c54bd13 100644
--- a/src/pipe/utils/SamplePipeControllers.cpp
+++ b/src/pipe/utils/SamplePipeControllers.cpp
@@ -76,3 +76,40 @@
}
this->INHERITED::notifyWritten(bytes);
}
+
+////////////////////////////////////////////////////////////////////////////////
+
+DeferredPipeController::DeferredPipeController(int numberOfReaders)
+: fAllocator(kMinBlockSize)
+, fNumberOfReaders(numberOfReaders) {
+ fBlock = NULL;
+ fBytesWritten = 0;
+}
+
+void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) {
+ if (fBlock) {
+ // Save the previous block for later
+ PipeBlock previousBloc(fBlock, fBytesWritten);
+ fBlockList.push(previousBloc);
+ }
+ int32_t blockSize = SkMax32(minRequest, kMinBlockSize);
+ fBlock = fAllocator.allocThrow(blockSize);
+ fBytesWritten = 0;
+ *actual = blockSize;
+ return fBlock;
+}
+
+void DeferredPipeController::notifyWritten(size_t bytes) {
+ fBytesWritten += bytes;
+}
+
+void DeferredPipeController::playback(SkCanvas* target) {
+ SkGPipeReader reader(target);
+ for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
+ reader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fBytes);
+ }
+
+ if (fBlock) {
+ reader.playback(fBlock, fBytesWritten);
+ }
+}
diff --git a/src/pipe/utils/SamplePipeControllers.h b/src/pipe/utils/SamplePipeControllers.h
index 715693c..bbd8024 100644
--- a/src/pipe/utils/SamplePipeControllers.h
+++ b/src/pipe/utils/SamplePipeControllers.h
@@ -6,7 +6,9 @@
*/
#include "SkBitmap.h"
+#include "SkChunkAlloc.h"
#include "SkGPipe.h"
+#include "SkTDArray.h"
class SkCanvas;
class SkMatrix;
@@ -43,3 +45,41 @@
SkBitmap fBitmaps[NumberOfTiles];
typedef PipeController INHERITED;
};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Borrowed (and modified) from SkDeferredCanvas.cpp::DeferredPipeController.
+ * Allows playing back from multiple threads.
+ */
+class DeferredPipeController : public SkGPipeController {
+public:
+ DeferredPipeController(int numberOfReaders);
+ virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
+ virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
+ virtual int numberOfReaders() const SK_OVERRIDE { return fNumberOfReaders; }
+
+ /**
+ * Play the stored drawing commands to the specified canvas. If SkGPipeWriter::startRecording
+ * used the flag SkGPipeWriter::kSimultaneousReaders_Flag, this can be called from different
+ * threads simultaneously.
+ */
+ void playback(SkCanvas*);
+private:
+ enum {
+ kMinBlockSize = 4096
+ };
+ struct PipeBlock {
+ PipeBlock(void* block, size_t bytes) { fBlock = block, fBytes = bytes; }
+ // Stream of draw commands written by the SkGPipeWriter. Allocated by fAllocator, which will
+ // handle freeing it.
+ void* fBlock;
+ // Number of bytes that were written to fBlock.
+ size_t fBytes;
+ };
+ void* fBlock;
+ size_t fBytesWritten;
+ SkChunkAlloc fAllocator;
+ SkTDArray<PipeBlock> fBlockList;
+ int fNumberOfReaders;
+};