Adding class SkDeferredCanvas for deferred rendering.
TEST=added a new pass to gm, so all gm tests are run through SkDeferredCanvas REVIEW=http://codereview.appspot.com/5430058/ git-svn-id: http://skia.googlecode.com/svn/trunk@3059 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
20ad5ac8f6
commit
4370aedf7f
@ -11,6 +11,7 @@
|
||||
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkData.h"
|
||||
#include "SkDeferredCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkGpuCanvas.h"
|
||||
#include "SkGpuDevice.h"
|
||||
@ -268,26 +269,43 @@ static void invokeGM(GM* gm, SkCanvas* canvas) {
|
||||
static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec,
|
||||
GrContext* context,
|
||||
GrRenderTarget* rt,
|
||||
SkBitmap* bitmap) {
|
||||
SkBitmap* bitmap,
|
||||
bool deferred) {
|
||||
SkISize size (gm->getISize());
|
||||
setup_bitmap(gRec, size, bitmap);
|
||||
SkCanvas canvas(*bitmap);
|
||||
|
||||
if (gRec.fBackend == kRaster_Backend) {
|
||||
invokeGM(gm, &canvas);
|
||||
SkCanvas* canvas;
|
||||
if (deferred) {
|
||||
canvas = new SkDeferredCanvas;
|
||||
canvas->setDevice(new SkDevice(*bitmap))->unref();
|
||||
} else {
|
||||
canvas = new SkCanvas(*bitmap);
|
||||
}
|
||||
SkAutoUnref canvasUnref(canvas);
|
||||
invokeGM(gm, canvas);
|
||||
if (deferred) {
|
||||
canvas->getDevice()->accessBitmap(false); // trigger a flush
|
||||
}
|
||||
} else { // GPU
|
||||
if (NULL == context) {
|
||||
return ERROR_NO_GPU_CONTEXT;
|
||||
}
|
||||
SkGpuCanvas gc(context, rt);
|
||||
gc.setDevice(new SkGpuDevice(context, rt))->unref();
|
||||
invokeGM(gm, &gc);
|
||||
SkCanvas* gc;
|
||||
if (deferred) {
|
||||
gc = new SkDeferredCanvas;
|
||||
} else {
|
||||
gc = new SkGpuCanvas(context, rt);
|
||||
}
|
||||
SkAutoUnref gcUnref(gc);
|
||||
gc->setDevice(new SkGpuDevice(context, rt))->unref();
|
||||
invokeGM(gm, gc);
|
||||
// the device is as large as the current rendertarget, so we explicitly
|
||||
// only readback the amount we expect (in size)
|
||||
// overwrite our previous allocation
|
||||
bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
|
||||
size.fHeight);
|
||||
gc.readPixels(bitmap, 0, 0);
|
||||
gc->readPixels(bitmap, 0, 0);
|
||||
}
|
||||
return ERROR_NONE;
|
||||
}
|
||||
@ -488,7 +506,8 @@ static ErrorBitfield test_drawing(GM* gm,
|
||||
if (gRec.fBackend == kRaster_Backend ||
|
||||
gRec.fBackend == kGPU_Backend) {
|
||||
// Early exit if we can't generate the image.
|
||||
ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap);
|
||||
ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap,
|
||||
false);
|
||||
if (ERROR_NONE != errors) {
|
||||
return errors;
|
||||
}
|
||||
@ -506,6 +525,28 @@ static ErrorBitfield test_drawing(GM* gm,
|
||||
"", *bitmap, &document, NULL);
|
||||
}
|
||||
|
||||
static ErrorBitfield test_deferred_drawing(GM* gm,
|
||||
const ConfigData& gRec,
|
||||
const SkBitmap& comparisonBitmap,
|
||||
const char diffPath [],
|
||||
GrContext* context,
|
||||
GrRenderTarget* rt) {
|
||||
SkDynamicMemoryWStream document;
|
||||
|
||||
if (gRec.fBackend == kRaster_Backend ||
|
||||
gRec.fBackend == kGPU_Backend) {
|
||||
SkBitmap bitmap;
|
||||
// Early exit if we can't generate the image, but this is
|
||||
// expected in some cases, so don't report a test failure.
|
||||
if (!generate_image(gm, gRec, context, rt, &bitmap, true)) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
return handle_test_results(gm, gRec, NULL, NULL, diffPath,
|
||||
"-deferred", bitmap, NULL, &comparisonBitmap);
|
||||
}
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static ErrorBitfield test_picture_playback(GM* gm,
|
||||
const ConfigData& gRec,
|
||||
const SkBitmap& comparisonBitmap,
|
||||
@ -612,6 +653,7 @@ int main(int argc, char * const argv[]) {
|
||||
bool doReplay = true;
|
||||
bool doSerialize = false;
|
||||
bool useMesa = false;
|
||||
bool doDeferred = true;
|
||||
|
||||
const char* const commandName = argv[0];
|
||||
char* const* stop = argv + argc;
|
||||
@ -637,6 +679,8 @@ int main(int argc, char * const argv[]) {
|
||||
doReplay = false;
|
||||
} else if (strcmp(*argv, "--nopdf") == 0) {
|
||||
doPDF = false;
|
||||
} else if (strcmp(*argv, "--nodeferred") == 0) {
|
||||
doDeferred = false;
|
||||
} else if (strcmp(*argv, "--serialize") == 0) {
|
||||
doSerialize = true;
|
||||
} else if (strcmp(*argv, "--match") == 0) {
|
||||
@ -758,6 +802,14 @@ int main(int argc, char * const argv[]) {
|
||||
rt.get(), &forwardRenderedBitmap);
|
||||
}
|
||||
|
||||
if (doDeferred && !testErrors &&
|
||||
(kGPU_Backend == gRec[i].fBackend ||
|
||||
kRaster_Backend == gRec[i].fBackend)) {
|
||||
testErrors |= test_deferred_drawing(gm, gRec[i],
|
||||
forwardRenderedBitmap,
|
||||
diffPath, gGrContext, rt.get());
|
||||
}
|
||||
|
||||
if ((ERROR_NONE == testErrors) && doReplay &&
|
||||
!(gmFlags & GM::kSkipPicture_Flag)) {
|
||||
testErrors |= test_picture_playback(gm, gRec[i],
|
||||
|
@ -22,6 +22,7 @@
|
||||
'../include/utils/SkCamera.h',
|
||||
'../include/utils/SkCubicInterval.h',
|
||||
'../include/utils/SkCullPoints.h',
|
||||
'../include/utils/SkDeferredCanvas.h',
|
||||
'../include/utils/SkDumpCanvas.h',
|
||||
'../include/utils/SkInterpolator.h',
|
||||
'../include/utils/SkLayer.h',
|
||||
@ -43,6 +44,7 @@
|
||||
'../src/utils/SkColorMatrix.cpp',
|
||||
'../src/utils/SkCubicInterval.cpp',
|
||||
'../src/utils/SkCullPoints.cpp',
|
||||
'../src/utils/SkDeferredCanvas.cpp',
|
||||
'../src/utils/SkDumpCanvas.cpp',
|
||||
'../src/utils/SkInterpolator.cpp',
|
||||
'../src/utils/SkLayer.cpp',
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
reference count is incremented. If the canvas was already holding a
|
||||
device, its reference count is decremented. The new device is returned.
|
||||
*/
|
||||
SkDevice* setDevice(SkDevice* device);
|
||||
virtual SkDevice* setDevice(SkDevice* device);
|
||||
|
||||
/**
|
||||
* saveLayer() can create another device (which is later drawn onto
|
||||
@ -278,7 +278,7 @@ public:
|
||||
/** Returns the number of matrix/clip states on the SkCanvas' private stack.
|
||||
This will equal # save() calls - # restore() calls.
|
||||
*/
|
||||
int getSaveCount() const;
|
||||
virtual int getSaveCount() const;
|
||||
|
||||
/** Efficient way to pop any calls to save() that happened after the save
|
||||
count reached saveCount. It is an error for saveCount to be less than
|
||||
@ -845,7 +845,7 @@ public:
|
||||
This does not account for the translate in any of the devices.
|
||||
@return The current matrix on the canvas.
|
||||
*/
|
||||
const SkMatrix& getTotalMatrix() const;
|
||||
virtual const SkMatrix& getTotalMatrix() const;
|
||||
|
||||
enum ClipType {
|
||||
kEmpty_ClipType = 0,
|
||||
@ -921,6 +921,12 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
// Returns the canvas to be used by DrawIter. Default implementation
|
||||
// returns this. Subclasses that encapsulate an indirect canvas may
|
||||
// need to overload this method. The impl must keep track of this, as it
|
||||
// is not released or deleted by the caller.
|
||||
virtual SkCanvas* canvasForDrawIter();
|
||||
|
||||
// all of the drawBitmap variants call this guy
|
||||
virtual void commonDrawBitmap(const SkBitmap&, const SkIRect*,
|
||||
const SkMatrix&, const SkPaint& paint);
|
||||
|
298
include/utils/SkDeferredCanvas.h
Normal file
298
include/utils/SkDeferredCanvas.h
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDeferredCanvas_DEFINED
|
||||
#define SkDeferredCanvas_DEFINED
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkPixelRef.h"
|
||||
|
||||
/** \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.
|
||||
SkDeferredCanvas will transparently trigger the flushing of deferred
|
||||
draw operations when an attempt is made to access the pixel data.
|
||||
*/
|
||||
class SK_API SkDeferredCanvas : public SkCanvas {
|
||||
public:
|
||||
class DeviceContext;
|
||||
|
||||
SkDeferredCanvas();
|
||||
|
||||
/** Construct a canvas with the specified device to draw into.
|
||||
Equivalent to calling default constructor, then setDevice.
|
||||
@param device Specifies a device for the canvas to draw into.
|
||||
*/
|
||||
explicit SkDeferredCanvas(SkDevice* device);
|
||||
|
||||
/** Construct a canvas with the specified device to draw into, and
|
||||
* a device context. Equivalent to calling default constructor, then
|
||||
* setDevice.
|
||||
* @param device Specifies a device for the canvas to draw into.
|
||||
* @param deviceContext interface for the device's the graphics context
|
||||
*/
|
||||
explicit SkDeferredCanvas(SkDevice* device, DeviceContext* deviceContext);
|
||||
|
||||
virtual ~SkDeferredCanvas();
|
||||
|
||||
/**
|
||||
* Specify a device to be used by this canvas. Calling setDevice will
|
||||
* release the previously set device, if any.
|
||||
*
|
||||
* @param device The device that the canvas will raw into
|
||||
* @return The device argument, for convenience.
|
||||
*/
|
||||
virtual SkDevice* setDevice(SkDevice* device);
|
||||
|
||||
/**
|
||||
* Specify a deviceContext to be used by this canvas. Calling
|
||||
* setDeviceContext will release the previously set deviceContext, if any.
|
||||
* A deviceContext must be specified if the device uses a graphics context
|
||||
* that requires some form of state initialization prior to drawing
|
||||
* and/or explicit flushing to synchronize the execution of rendering
|
||||
* operations.
|
||||
* Note: Must be called after the device is set with setDevice.
|
||||
*
|
||||
* @deviceContext interface for the device's the graphics context
|
||||
* @return The deviceContext argument, for convenience.
|
||||
*/
|
||||
DeviceContext* setDeviceContext(DeviceContext* deviceContext);
|
||||
|
||||
/**
|
||||
* Enable or disable deferred drawing. When deferral is disabled,
|
||||
* pending draw operations are immediately flushed and from then on,
|
||||
* the SkDeferredCanvas behaves just like a regular SkCanvas.
|
||||
* This method must not be called while the save/restore stack is in use.
|
||||
* @param deferred true/false
|
||||
*/
|
||||
void setDeferredDrawing(bool deferred);
|
||||
|
||||
// Overrides of the SkCanvas interface
|
||||
virtual int save(SaveFlags flags) SK_OVERRIDE;
|
||||
virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
SaveFlags flags) SK_OVERRIDE;
|
||||
virtual void restore() SK_OVERRIDE;
|
||||
virtual int getSaveCount() const SK_OVERRIDE;
|
||||
virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
|
||||
virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
|
||||
virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
|
||||
virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
|
||||
virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
|
||||
virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
|
||||
virtual const SkMatrix& getTotalMatrix() const SK_OVERRIDE;
|
||||
virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
|
||||
bool doAntiAlias) SK_OVERRIDE;
|
||||
virtual bool clipPath(const SkPath& path, SkRegion::Op op,
|
||||
bool doAntiAlias) SK_OVERRIDE;
|
||||
virtual bool clipRegion(const SkRegion& deviceRgn,
|
||||
SkRegion::Op op) SK_OVERRIDE;
|
||||
virtual void clear(SkColor) SK_OVERRIDE;
|
||||
virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
|
||||
const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual void drawRect(const SkRect& rect, const SkPaint& paint)
|
||||
SK_OVERRIDE;
|
||||
virtual void drawPath(const SkPath& path, const SkPaint& paint)
|
||||
SK_OVERRIDE;
|
||||
virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left,
|
||||
SkScalar top, const SkPaint* paint)
|
||||
SK_OVERRIDE;
|
||||
virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
|
||||
const SkRect& dst, const SkPaint* paint)
|
||||
SK_OVERRIDE;
|
||||
|
||||
virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
|
||||
const SkPaint* paint) SK_OVERRIDE;
|
||||
virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
|
||||
const SkRect& dst, const SkPaint* paint)
|
||||
SK_OVERRIDE;
|
||||
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
|
||||
const SkPaint* paint) SK_OVERRIDE;
|
||||
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
|
||||
SkScalar y, const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual void drawPosText(const void* text, size_t byteLength,
|
||||
const SkPoint pos[], const SkPaint& paint)
|
||||
SK_OVERRIDE;
|
||||
virtual void drawPosTextH(const void* text, size_t byteLength,
|
||||
const SkScalar xpos[], SkScalar constY,
|
||||
const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual void drawTextOnPath(const void* text, size_t byteLength,
|
||||
const SkPath& path, const SkMatrix* matrix,
|
||||
const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual void drawPicture(SkPicture& picture) SK_OVERRIDE;
|
||||
virtual void drawVertices(VertexMode vmode, int vertexCount,
|
||||
const SkPoint vertices[], const SkPoint texs[],
|
||||
const SkColor colors[], SkXfermode* xmode,
|
||||
const uint16_t indices[], int indexCount,
|
||||
const SkPaint& paint) SK_OVERRIDE;
|
||||
virtual SkBounder* setBounder(SkBounder* bounder) SK_OVERRIDE;
|
||||
virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
void flushIfNeeded(const SkBitmap& bitmap);
|
||||
|
||||
public:
|
||||
class DeviceContext : public SkRefCnt {
|
||||
public:
|
||||
virtual void prepareForDraw() {}
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
public:
|
||||
class DeferredDevice : public SkDevice {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* @param immediateDevice device to be drawn to when flushing
|
||||
* deferred operations
|
||||
* @param deviceContext callback interface for managing graphics
|
||||
* context state, can be NULL.
|
||||
*/
|
||||
DeferredDevice(SkDevice* immediateDevice,
|
||||
DeviceContext* deviceContext = NULL);
|
||||
~DeferredDevice();
|
||||
|
||||
/**
|
||||
* Sets the device context to be use with the device.
|
||||
* @param deviceContext callback interface for managing graphics
|
||||
* context state, can be NULL.
|
||||
*/
|
||||
void setDeviceContext(DeviceContext* deviceContext);
|
||||
|
||||
/**
|
||||
* Returns the recording canvas.
|
||||
*/
|
||||
SkCanvas* recordingCanvas() const {return fRecordingCanvas;}
|
||||
|
||||
/**
|
||||
* Returns the immediate (non deferred) canvas.
|
||||
*/
|
||||
SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
|
||||
|
||||
/**
|
||||
* Returns the immediate (non deferred) device.
|
||||
*/
|
||||
SkDevice* immediateDevice() const {return fImmediateDevice;}
|
||||
|
||||
void flushPending();
|
||||
void flushContext();
|
||||
void purgePending();
|
||||
void flushIfNeeded(const SkBitmap& bitmap);
|
||||
|
||||
virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
|
||||
virtual int width() const SK_OVERRIDE;
|
||||
virtual int height() const SK_OVERRIDE;
|
||||
virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
|
||||
|
||||
virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
|
||||
int width, int height,
|
||||
bool isOpaque,
|
||||
Usage usage) SK_OVERRIDE;
|
||||
|
||||
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
|
||||
SkCanvas::Config8888 config8888) SK_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void onAccessBitmap(SkBitmap*) SK_OVERRIDE;
|
||||
virtual bool onReadPixels(const SkBitmap& bitmap,
|
||||
int x, int y,
|
||||
SkCanvas::Config8888 config8888) SK_OVERRIDE;
|
||||
|
||||
// The following methods are no-ops on a deferred device
|
||||
virtual bool filterTextFlags(const SkPaint& paint, TextFlags*)
|
||||
SK_OVERRIDE
|
||||
{return false;}
|
||||
virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
|
||||
const SkClipStack&) SK_OVERRIDE
|
||||
{}
|
||||
virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
|
||||
const SkClipStack&) SK_OVERRIDE
|
||||
{}
|
||||
|
||||
// None of the following drawing methods should ever get called on the
|
||||
// deferred device
|
||||
virtual void clear(SkColor color)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawPaint(const SkDraw&, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
|
||||
size_t count, const SkPoint[],
|
||||
const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawRect(const SkDraw&, const SkRect& r,
|
||||
const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawPath(const SkDraw&, const SkPath& path,
|
||||
const SkPaint& paint,
|
||||
const SkMatrix* prePathMatrix = NULL,
|
||||
bool pathIsMutable = false)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
|
||||
const SkIRect* srcRectOrNull,
|
||||
const SkMatrix& matrix, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
|
||||
int x, int y, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawText(const SkDraw&, const void* text, size_t len,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
|
||||
const SkScalar pos[], SkScalar constY,
|
||||
int scalarsPerPos, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawTextOnPath(const SkDraw&, const void* text,
|
||||
size_t len, const SkPath& path,
|
||||
const SkMatrix* matrix,
|
||||
const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawPosTextOnPath(const SkDraw& draw, const void* text,
|
||||
size_t len, const SkPoint pos[],
|
||||
const SkPaint& paint,
|
||||
const SkPath& path,
|
||||
const SkMatrix* matrix)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
|
||||
int vertexCount, const SkPoint verts[],
|
||||
const SkPoint texs[], const SkColor colors[],
|
||||
SkXfermode* xmode, const uint16_t indices[],
|
||||
int indexCount, const SkPaint& paint)
|
||||
{SkASSERT(0);}
|
||||
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
|
||||
const SkPaint&)
|
||||
{SkASSERT(0);}
|
||||
private:
|
||||
virtual void flush();
|
||||
|
||||
SkPicture fPicture;
|
||||
SkDevice* fImmediateDevice;
|
||||
SkCanvas* fImmediateCanvas;
|
||||
SkCanvas* fRecordingCanvas;
|
||||
DeviceContext* fDeviceContext;
|
||||
};
|
||||
|
||||
DeferredDevice* getDeferredDevice() const;
|
||||
|
||||
protected:
|
||||
virtual SkCanvas* canvasForDrawIter();
|
||||
|
||||
private:
|
||||
SkCanvas* drawingCanvas() const;
|
||||
bool isFullFrame(const SkRect*, const SkPaint*) const;
|
||||
void validate() const;
|
||||
void init();
|
||||
bool fDeferredDrawing;
|
||||
|
||||
typedef SkCanvas INHERITED;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -214,6 +214,7 @@ private:
|
||||
class SkDrawIter : public SkDraw {
|
||||
public:
|
||||
SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
|
||||
canvas = canvas->canvasForDrawIter();
|
||||
fCanvas = canvas;
|
||||
canvas->updateDeviceCMCache();
|
||||
|
||||
@ -591,6 +592,10 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
|
||||
}
|
||||
}
|
||||
|
||||
SkCanvas* SkCanvas::canvasForDrawIter() {
|
||||
return this;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkCanvas::updateDeviceCMCache() {
|
||||
|
625
src/utils/SkDeferredCanvas.cpp
Normal file
625
src/utils/SkDeferredCanvas.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkDeferredCanvas.h"
|
||||
|
||||
#include "SkPaint.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkDrawFilter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool isPaintOpaque(const SkPaint& paint, const SkBitmap* bmpReplacesShader = NULL) {
|
||||
// TODO: SkXfermode should have a virtual isOpaque method, which would
|
||||
// make it possible to test modes that do not have a Coeff representation.
|
||||
SkXfermode::Coeff srcCoeff, dstCoeff;
|
||||
if (SkXfermode::AsCoeff(paint.getXfermode(), &srcCoeff, &dstCoeff)){
|
||||
switch (dstCoeff) {
|
||||
case SkXfermode::kZero_Coeff:
|
||||
return true;
|
||||
case SkXfermode::kISA_Coeff:
|
||||
if (paint.getAlpha() != 255) {
|
||||
break;
|
||||
}
|
||||
if (bmpReplacesShader) {
|
||||
if (!bmpReplacesShader->isOpaque()) {
|
||||
break;
|
||||
}
|
||||
} else if (paint.getShader() && !paint.getShader()->isOpaque()) {
|
||||
break;
|
||||
}
|
||||
if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
|
||||
SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
case SkXfermode::kSA_Coeff:
|
||||
if (paint.getAlpha() != 0) {
|
||||
break;
|
||||
}
|
||||
if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
|
||||
SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
case SkXfermode::kSC_Coeff:
|
||||
if (paint.getColor() != 0) { // all components must be 0
|
||||
break;
|
||||
}
|
||||
if (bmpReplacesShader || paint.getShader()) {
|
||||
break;
|
||||
}
|
||||
if (paint.getColorFilter() && ((paint.getColorFilter()->getFlags() &
|
||||
SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
SkDeferredCanvas::SkDeferredCanvas()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
SkDeferredCanvas::SkDeferredCanvas(SkDevice* device)
|
||||
{
|
||||
init();
|
||||
setDevice(device);
|
||||
}
|
||||
|
||||
SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
|
||||
DeviceContext* deviceContext)
|
||||
{
|
||||
init();
|
||||
setDevice(device);
|
||||
setDeviceContext(deviceContext);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::init()
|
||||
{
|
||||
fDeferredDrawing = true; // On by default
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::validate() const
|
||||
{
|
||||
SkASSERT(getDevice());
|
||||
SkASSERT(INHERITED::getTotalMatrix().isIdentity());
|
||||
}
|
||||
|
||||
SkCanvas* SkDeferredCanvas::drawingCanvas() const
|
||||
{
|
||||
validate();
|
||||
return fDeferredDrawing ? getDeferredDevice()->recordingCanvas() :
|
||||
getDeferredDevice()->immediateCanvas();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::flushIfNeeded(const SkBitmap& bitmap)
|
||||
{
|
||||
validate();
|
||||
if (fDeferredDrawing) {
|
||||
getDeferredDevice()->flushIfNeeded(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
SkDeferredCanvas::DeferredDevice* SkDeferredCanvas::getDeferredDevice() const
|
||||
{
|
||||
return static_cast<SkDeferredCanvas::DeferredDevice*>(getDevice());
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::setDeferredDrawing(bool val)
|
||||
{
|
||||
validate(); // Must set device before calling this method
|
||||
SkASSERT(drawingCanvas()->getSaveCount() == 1);
|
||||
if (val != fDeferredDrawing) {
|
||||
if (fDeferredDrawing) {
|
||||
// Going live.
|
||||
getDeferredDevice()->flushPending();
|
||||
}
|
||||
fDeferredDrawing = val;
|
||||
}
|
||||
}
|
||||
|
||||
SkDeferredCanvas::~SkDeferredCanvas()
|
||||
{
|
||||
}
|
||||
|
||||
SkDevice* SkDeferredCanvas::setDevice(SkDevice* device)
|
||||
{
|
||||
INHERITED::setDevice(SkNEW_ARGS(DeferredDevice, (device)))->unref();
|
||||
return device;
|
||||
}
|
||||
|
||||
SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
|
||||
DeviceContext* deviceContext)
|
||||
{
|
||||
DeferredDevice* deferredDevice = getDeferredDevice();
|
||||
SkASSERT(deferredDevice);
|
||||
if (deferredDevice) {
|
||||
deferredDevice->setDeviceContext(deviceContext);
|
||||
}
|
||||
return deviceContext;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
|
||||
const SkPaint* paint) const
|
||||
{
|
||||
SkCanvas* canvas = drawingCanvas();
|
||||
SkISize canvasSize = getDeviceSize();
|
||||
if (rect) {
|
||||
if (!canvas->getTotalMatrix().rectStaysRect()) {
|
||||
return false; // conservative
|
||||
}
|
||||
|
||||
SkRect transformedRect;
|
||||
canvas->getTotalMatrix().mapRect(&transformedRect, *rect);
|
||||
|
||||
if (paint) {
|
||||
SkPaint::Style paintStyle = paint->getStyle();
|
||||
if (!(paintStyle == SkPaint::kFill_Style ||
|
||||
paintStyle == SkPaint::kStrokeAndFill_Style)) {
|
||||
return false;
|
||||
}
|
||||
if (paint->getMaskFilter() || paint->getLooper()
|
||||
|| paint->getPathEffect() || paint->getImageFilter()) {
|
||||
return false; // conservative
|
||||
}
|
||||
}
|
||||
|
||||
// The following test holds with AA enabled, and is conservative
|
||||
// by a 0.5 pixel margin with AA disabled
|
||||
if (transformedRect.fLeft > 0 || transformedRect.fTop > 0 ||
|
||||
transformedRect.fRight < canvasSize.fWidth ||
|
||||
transformedRect.fBottom < canvasSize.fHeight) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (canvas->getClipType()) {
|
||||
case SkCanvas::kRect_ClipType :
|
||||
{
|
||||
SkIRect bounds;
|
||||
canvas->getClipDeviceBounds(&bounds);
|
||||
if (bounds.fLeft > 0 || bounds.fTop > 0 ||
|
||||
bounds.fRight < canvasSize.fWidth ||
|
||||
bounds.fBottom < canvasSize.fHeight)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SkCanvas::kComplex_ClipType :
|
||||
return false; // conservative
|
||||
case SkCanvas::kEmpty_ClipType:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::save(SaveFlags flags)
|
||||
{
|
||||
return drawingCanvas()->save(flags);
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
SaveFlags flags)
|
||||
{
|
||||
return drawingCanvas()->saveLayer(bounds, paint, flags);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::restore()
|
||||
{
|
||||
drawingCanvas()->restore();
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::getSaveCount() const
|
||||
{
|
||||
return drawingCanvas()->getSaveCount();
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy)
|
||||
{
|
||||
return drawingCanvas()->translate(dx, dy);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy)
|
||||
{
|
||||
return drawingCanvas()->scale(sx, sy);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::rotate(SkScalar degrees)
|
||||
{
|
||||
return drawingCanvas()->rotate(degrees);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy)
|
||||
{
|
||||
return drawingCanvas()->skew(sx, sy);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::concat(const SkMatrix& matrix)
|
||||
{
|
||||
return drawingCanvas()->concat(matrix);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::setMatrix(const SkMatrix& matrix)
|
||||
{
|
||||
drawingCanvas()->setMatrix(matrix);
|
||||
}
|
||||
|
||||
const SkMatrix& SkDeferredCanvas::getTotalMatrix() const
|
||||
{
|
||||
return drawingCanvas()->getTotalMatrix();
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipRect(const SkRect& rect,
|
||||
SkRegion::Op op,
|
||||
bool doAntiAlias)
|
||||
{
|
||||
return drawingCanvas()->clipRect(rect, op, doAntiAlias);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipPath(const SkPath& path,
|
||||
SkRegion::Op op,
|
||||
bool doAntiAlias)
|
||||
{
|
||||
return drawingCanvas()->clipPath(path, op, doAntiAlias);
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
|
||||
SkRegion::Op op)
|
||||
{
|
||||
return drawingCanvas()->clipRegion(deviceRgn, op);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::clear(SkColor color)
|
||||
{
|
||||
// purge pending commands
|
||||
if (fDeferredDrawing) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->clear(color);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPaint(const SkPaint& paint)
|
||||
{
|
||||
if (fDeferredDrawing && isFullFrame(NULL, &paint) && isPaintOpaque(paint)) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->drawPaint(paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
|
||||
const SkPoint pts[], const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawPoints(mode, count, pts, paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
|
||||
{
|
||||
if (fDeferredDrawing && isFullFrame(&rect, &paint) && isPaintOpaque(paint)) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->drawRect(rect, paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawPath(path, paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
|
||||
SkScalar top, const SkPaint* paint)
|
||||
{
|
||||
SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
|
||||
bitmap.height());
|
||||
if (fDeferredDrawing &&
|
||||
isFullFrame(&bitmapRect, paint) &&
|
||||
isPaintOpaque(*paint, &bitmap)) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->drawBitmap(bitmap, left, top, paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
|
||||
const SkIRect* src,
|
||||
const SkRect& dst, const SkPaint* paint)
|
||||
{
|
||||
if (fDeferredDrawing &&
|
||||
isFullFrame(&dst, paint) &&
|
||||
isPaintOpaque(*paint, &bitmap)) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->drawBitmapRect(bitmap, src,
|
||||
dst, paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
|
||||
void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
|
||||
const SkMatrix& m,
|
||||
const SkPaint* paint)
|
||||
{
|
||||
// TODO: reset recording canvas if paint+bitmap is opaque and clip rect
|
||||
// covers canvas entirely and transformed bitmap covers canvas entirely
|
||||
drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
|
||||
const SkIRect& center, const SkRect& dst,
|
||||
const SkPaint* paint)
|
||||
{
|
||||
// TODO: reset recording canvas if paint+bitmap is opaque and clip rect
|
||||
// covers canvas entirely and dst covers canvas entirely
|
||||
drawingCanvas()->drawBitmapNine(bitmap, center,
|
||||
dst, paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
|
||||
const SkPaint* paint)
|
||||
{
|
||||
SkRect bitmapRect = SkRect::MakeXYWH(left, top, bitmap.width(),
|
||||
bitmap.height());
|
||||
if (fDeferredDrawing &&
|
||||
isFullFrame(&bitmapRect, paint) &&
|
||||
isPaintOpaque(*paint, &bitmap)) {
|
||||
getDeferredDevice()->purgePending();
|
||||
}
|
||||
|
||||
drawingCanvas()->drawSprite(bitmap, left, top,
|
||||
paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawText(text, byteLength, x,
|
||||
y, paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
|
||||
const SkPoint pos[], const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawPosText(text, byteLength,
|
||||
pos, paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
|
||||
const SkScalar xpos[], SkScalar constY,
|
||||
const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawPosTextH(text, byteLength,
|
||||
xpos, constY,
|
||||
paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
|
||||
const SkPath& path,
|
||||
const SkMatrix* matrix,
|
||||
const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawTextOnPath(text, byteLength,
|
||||
path, matrix,
|
||||
paint);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPicture(SkPicture& picture)
|
||||
{
|
||||
drawingCanvas()->drawPicture(picture);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
|
||||
const SkPoint vertices[],
|
||||
const SkPoint texs[],
|
||||
const SkColor colors[], SkXfermode* xmode,
|
||||
const uint16_t indices[], int indexCount,
|
||||
const SkPaint& paint)
|
||||
{
|
||||
drawingCanvas()->drawVertices(vmode, vertexCount,
|
||||
vertices, texs,
|
||||
colors, xmode,
|
||||
indices, indexCount,
|
||||
paint);
|
||||
}
|
||||
|
||||
SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder)
|
||||
{
|
||||
INHERITED::setBounder(bounder); // So non-virtual getBounder works
|
||||
return drawingCanvas()->setBounder(bounder);
|
||||
}
|
||||
|
||||
SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter)
|
||||
{
|
||||
INHERITED::setDrawFilter(filter); // So non-virtual getDrawFilter works
|
||||
return drawingCanvas()->setDrawFilter(filter);
|
||||
}
|
||||
|
||||
SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
|
||||
return drawingCanvas();
|
||||
}
|
||||
|
||||
// SkDeferredCanvas::DeferredDevice
|
||||
//------------------------------------
|
||||
|
||||
SkDeferredCanvas::DeferredDevice::DeferredDevice(
|
||||
SkDevice* immediateDevice, DeviceContext* deviceContext) :
|
||||
SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
|
||||
immediateDevice->height(), immediateDevice->isOpaque())
|
||||
{
|
||||
fDeviceContext = deviceContext;
|
||||
SkSafeRef(fDeviceContext);
|
||||
fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
|
||||
fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
|
||||
SkSafeRef(fImmediateCanvas);
|
||||
fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
|
||||
fImmediateDevice->height(),
|
||||
SkPicture::kUsePathBoundsForClip_RecordingFlag);
|
||||
}
|
||||
|
||||
SkDeferredCanvas::DeferredDevice::~DeferredDevice()
|
||||
{
|
||||
SkSafeUnref(fImmediateCanvas);
|
||||
SkSafeUnref(fDeviceContext);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::setDeviceContext(
|
||||
DeviceContext* deviceContext)
|
||||
{
|
||||
SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::purgePending()
|
||||
{
|
||||
// TODO: find a way to transfer the state stack and layers
|
||||
// to the new recording canvas. For now, purge only works
|
||||
// with an empty stack.
|
||||
if (fRecordingCanvas->getSaveCount() > 1)
|
||||
return;
|
||||
|
||||
// Save state that is trashed by the purge
|
||||
SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
|
||||
SkSafeRef(drawFilter); // So that it survives the purge
|
||||
SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
|
||||
SkRegion clipRegion = fRecordingCanvas->getTotalClip();
|
||||
|
||||
// beginRecording creates a new recording canvas and discards the old one,
|
||||
// hence purging deferred draw ops.
|
||||
fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
|
||||
fImmediateDevice->height(),
|
||||
SkPicture::kUsePathBoundsForClip_RecordingFlag);
|
||||
|
||||
// Restore pre-purge state
|
||||
if (!clipRegion.isEmpty()) {
|
||||
fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
|
||||
}
|
||||
if (!matrix.isIdentity()) {
|
||||
fRecordingCanvas->setMatrix(matrix);
|
||||
}
|
||||
if (drawFilter) {
|
||||
fRecordingCanvas->setDrawFilter(drawFilter)->unref();
|
||||
}
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::flushPending()
|
||||
{
|
||||
if (fDeviceContext) {
|
||||
fDeviceContext->prepareForDraw();
|
||||
}
|
||||
fPicture.draw(fImmediateCanvas);
|
||||
fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(),
|
||||
fImmediateDevice->height(),
|
||||
SkPicture::kUsePathBoundsForClip_RecordingFlag);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::flush()
|
||||
{
|
||||
flushPending();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::flushContext()
|
||||
{
|
||||
if (fDeviceContext) {
|
||||
fDeviceContext->flush();
|
||||
}
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::flushIfNeeded(const SkBitmap& bitmap)
|
||||
{
|
||||
if (bitmap.isImmutable()) {
|
||||
return; // safe to deffer without registering a dependency
|
||||
}
|
||||
|
||||
// For now, drawing a writable bitmap triggers a flush
|
||||
// TODO: implement read-only semantics and auto buffer duplication on write
|
||||
// in SkBitmap/SkPixelRef, which will make deferral possible in this case.
|
||||
flushPending();
|
||||
}
|
||||
|
||||
uint32_t SkDeferredCanvas::DeferredDevice::getDeviceCapabilities()
|
||||
{
|
||||
return fImmediateDevice->getDeviceCapabilities();
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::DeferredDevice::width() const
|
||||
{
|
||||
return fImmediateDevice->width();
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::DeferredDevice::height() const
|
||||
{
|
||||
return fImmediateDevice->height();
|
||||
}
|
||||
|
||||
SkGpuRenderTarget* SkDeferredCanvas::DeferredDevice::accessRenderTarget()
|
||||
{
|
||||
flushPending();
|
||||
return fImmediateDevice->accessRenderTarget();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::writePixels(const SkBitmap& bitmap,
|
||||
int x, int y, SkCanvas::Config8888 config8888)
|
||||
{
|
||||
if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
|
||||
(y + bitmap.height()) >= height()) {
|
||||
purgePending();
|
||||
}
|
||||
|
||||
if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
|
||||
SkCanvas::kNative_Premul_Config8888 != config8888 &&
|
||||
kPMColorAlias != config8888) {
|
||||
//Special case config: no deferral
|
||||
flushPending();
|
||||
fImmediateDevice->writePixels(bitmap, x, y, config8888);
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
fRecordingCanvas->drawSprite(bitmap, x, y, &paint);
|
||||
flushIfNeeded(bitmap);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::DeferredDevice::onAccessBitmap(SkBitmap* bitmap)
|
||||
{
|
||||
SkASSERT(bitmap);
|
||||
flushPending();
|
||||
}
|
||||
|
||||
SkDevice* SkDeferredCanvas::DeferredDevice::onCreateCompatibleDevice(
|
||||
SkBitmap::Config config, int width, int height, bool isOpaque, Usage usage)
|
||||
{
|
||||
// Save layer usage not supported, and not required by SkDeferredCanvas.
|
||||
SkASSERT(usage != kSaveLayer_Usage);
|
||||
// Create a compatible non-deferred device.
|
||||
SkDevice* compatibleDevice = fImmediateDevice->createCompatibleDevice(config, width,
|
||||
height, isOpaque);
|
||||
return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::DeferredDevice::onReadPixels(
|
||||
const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888)
|
||||
{
|
||||
flushPending();
|
||||
return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
|
||||
x, y, config8888);
|
||||
}
|
Loading…
Reference in New Issue
Block a user