Refactoring SkDeferredCanvas to use SkGPipe.
Keeping the refactor hidden behind a config macro for now.
TEST=covered by existing skia gm tests
BUG=https://code.google.com/p/chromium/issues/detail?id=133432
Review URL: https://codereview.appspot.com/6405054
git-svn-id: http://skia.googlecode.com/svn/trunk@4656 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 9afd580..568f9a7 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -438,6 +438,66 @@
return drawingCanvas();
}
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+
+// SkDeferredCanvas::DeferredPipeController
+//-------------------------------------------
+
+SkDeferredCanvas::DeferredPipeController::DeferredPipeController() :
+ fAllocator(kMinBlockSize) {
+ fBlock = NULL;
+ fBytesWritten = 0;
+}
+
+SkDeferredCanvas::DeferredPipeController::~DeferredPipeController() {
+ fAllocator.reset();
+}
+
+void SkDeferredCanvas::DeferredPipeController::setPlaybackCanvas(SkCanvas* canvas) {
+ fReader.setCanvas(canvas);
+}
+
+void* SkDeferredCanvas::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 SkDeferredCanvas::DeferredPipeController::notifyWritten(size_t bytes) {
+ fBytesWritten += bytes;
+}
+
+void SkDeferredCanvas::DeferredPipeController::playback() {
+
+ for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) {
+ fReader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fSize);
+ }
+ fBlockList.reset();
+
+ if (fBlock) {
+ fReader.playback(fBlock,fBytesWritten);
+ fBlock = NULL;
+ }
+
+ // Release all allocated blocks
+ fAllocator.reset();
+}
+
+void SkDeferredCanvas::DeferredPipeController::reset() {
+ fBlockList.reset();
+ fBlock = NULL;
+ fAllocator.reset();
+}
+
+#endif // SK_DEFERRED_CANVAS_USES_GPIPE
+
// SkDeferredCanvas::DeferredDevice
//------------------------------------
@@ -451,15 +511,37 @@
SkSafeRef(fDeviceContext);
fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
- fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
- fImmediateDevice->height(),
- SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ fPipeController.setPlaybackCanvas(fImmediateCanvas);
+#endif
+ beginRecording();
}
SkDeferredCanvas::DeferredDevice::~DeferredDevice() {
SkSafeUnref(fImmediateCanvas);
SkSafeUnref(fDeviceContext);
}
+
+
+void SkDeferredCanvas::DeferredDevice::endRecording() {
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ fPipeWriter.endRecording();
+ fPipeController.reset();
+#else
+ fPicture.endRecording();
+#endif
+ fRecordingCanvas = NULL;
+}
+
+void SkDeferredCanvas::DeferredDevice::beginRecording() {
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
+#else
+ fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
+ fImmediateDevice->height(),
+ SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
+#endif
+}
void SkDeferredCanvas::DeferredDevice::setDeviceContext(
DeviceContext* deviceContext) {
@@ -483,10 +565,8 @@
// beginRecording creates a new recording canvas and discards the
// old one, hence purging deferred draw ops.
- fRecordingCanvas = fPicture.beginRecording(
- fImmediateDevice->width(),
- fImmediateDevice->height(),
- SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
+ this->endRecording();
+ this->beginRecording();
// Restore pre-purge state
if (!clipRegion.isEmpty()) {
@@ -510,16 +590,26 @@
}
void SkDeferredCanvas::DeferredDevice::flushPending() {
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ if (!fPipeController.hasRecorded()) {
+ return;
+ }
+#else
if (!fPicture.hasRecorded()) {
return;
}
+#endif
if (fDeviceContext) {
fDeviceContext->prepareForDraw();
}
+
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ fPipeWriter.flushRecording(true);
+ fPipeController.playback();
+#else
fPicture.draw(fImmediateCanvas);
- fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
- fImmediateDevice->height(),
- SkPicture::kFlattenMutableNonTexturePixelRefs_RecordingFlag);
+ this->beginRecording();
+#endif
}
void SkDeferredCanvas::DeferredDevice::flush() {
@@ -528,9 +618,16 @@
}
void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap) {
+#if SK_DEFERRED_CANVAS_USES_GPIPE
+ if (bitmap.isImmutable()) {
+ // FIXME: Make SkGPipe flatten software-backed non-immutable bitmaps
+ return;
+ }
+#else
if (bitmap.isImmutable() || fPicture.willFlattenPixelsOnRecord(bitmap)) {
return; // safe to defer.
}
+#endif
// For now, drawing a writable bitmap triggers a flush
// TODO: implement read-only semantics and auto buffer duplication on write