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:
parent
9d250762cb
commit
77eec248cb
@ -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': [
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user