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
This commit is contained in:
junov@chromium.org 2012-07-18 17:54:45 +00:00
parent 9d250762cb
commit 77eec248cb
5 changed files with 183 additions and 16 deletions

View File

@ -6,11 +6,12 @@
'include_dirs': [
'../include/config',
'../include/core',
'../include/effects',
'../include/pipe',
'../include/utils',
'../include/utils/mac',
'../include/utils/unix',
'../include/utils/win',
'../include/effects',
'../include/xml',
],
'sources': [

View File

@ -98,6 +98,14 @@ public:
// should be no more drawing calls made into the recording canvas.
void endRecording();
/**
* Tells the writer to commit all recorded draw commands to the
* controller immediately.
* @param detachCurrentBlock Set to true to request that the next draw
* command be recorded in a new block.
*/
void flushRecording(bool detachCurrentBlock);
private:
class SkGPipeCanvas* fCanvas;
SkGPipeController* fController;

View File

@ -8,16 +8,26 @@
#ifndef SkDeferredCanvas_DEFINED
#define SkDeferredCanvas_DEFINED
#ifndef SK_DEFERRED_CANVAS_USES_GPIPE
#define SK_DEFERRED_CANVAS_USES_GPIPE 0
#endif
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPicture.h"
#include "SkPixelRef.h"
#if SK_DEFERRED_CANVAS_USES_GPIPE
#include "SkGPipe.h"
#include "SkChunkAlloc.h"
#else
#include "SkPicture.h"
#endif
/** \class SkDeferredCanvas
Subclass of SkCanvas that encapsulates an SkPicture for deferred drawing.
The main difference between this class and SkPictureRecord (the canvas
provided by SkPicture) is that this is a full drop-in replacement for
SkCanvas, while SkPictureRecord only supports draw operations.
Subclass of SkCanvas that encapsulates an SkPicture or SkGPipe for deferred
drawing. The main difference between this class and SkPictureRecord (the
canvas provided by SkPicture) is that this is a full drop-in replacement
for SkCanvas, while SkPictureRecord only supports draw operations.
SkDeferredCanvas will transparently trigger the flushing of deferred
draw operations when an attempt is made to access the pixel data.
*/
@ -149,6 +159,35 @@ public:
typedef SkRefCnt INHERITED;
};
#if SK_DEFERRED_CANVAS_USES_GPIPE
protected:
class DeferredPipeController : public SkGPipeController {
public:
DeferredPipeController();
void setPlaybackCanvas(SkCanvas*);
virtual ~DeferredPipeController();
virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE;
virtual void notifyWritten(size_t bytes) SK_OVERRIDE;
void playback();
void reset();
bool hasRecorded() {return fAllocator.blockCount() != 0;}
private:
enum {
kMinBlockSize = 4096
};
struct PipeBlock {
PipeBlock(void* block, size_t size) { fBlock = block, fSize = size; }
void* fBlock;
size_t fSize;
};
void* fBlock;
size_t fBytesWritten;
SkChunkAlloc fAllocator;
SkTDArray<PipeBlock> fBlockList;
SkGPipeReader fReader;
};
#endif
public:
class DeferredDevice : public SkDevice {
public:
@ -277,7 +316,15 @@ public:
private:
virtual void flush();
void endRecording();
void beginRecording();
#if SK_DEFERRED_CANVAS_USES_GPIPE
SkGPipeWriter fPipeWriter;
DeferredPipeController fPipeController;
#else
SkPicture fPicture;
#endif
SkDevice* fImmediateDevice;
SkCanvas* fImmediateCanvas;
SkCanvas* fRecordingCanvas;

View File

@ -350,6 +350,8 @@ public:
}
}
void flushRecording(bool detachCurrentBlock);
// overrides from SkCanvas
virtual int save(SaveFlags) SK_OVERRIDE;
virtual int saveLayer(const SkRect* bounds, const SkPaint*,
@ -1077,6 +1079,14 @@ void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
}
}
void SkGPipeCanvas::flushRecording(bool detachCurrentBlock) {
doNotify();
if (detachCurrentBlock) {
// force a new block to be requested for the next recorded command
fBlockSize = 0;
}
}
///////////////////////////////////////////////////////////////////////////////
template <typename T> uint32_t castToU32(T value) {
@ -1219,3 +1229,7 @@ void SkGPipeWriter::endRecording() {
}
}
void SkGPipeWriter::flushRecording(bool detachCurrentBlock){
fCanvas->flushRecording(detachCurrentBlock);
}

View File

@ -438,6 +438,66 @@ SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
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 @@ SkDeferredCanvas::DeferredDevice::DeferredDevice(
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 @@ void SkDeferredCanvas::DeferredDevice::contentsCleared() {
// 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 @@ bool SkDeferredCanvas::DeferredDevice::isFreshFrame() {
}
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::flush() {
}
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