зеркало из https://github.com/mozilla/moz-skia.git
Augmenting SkDeferredCanvas notification interface to signal flushes and memory allocations
Renamed SkDeferredCanvas::DeviceContext to SkDeferredCanvas::NotificationClient BUG=http://code.google.com/p/chromium/issues/detail?id=136828 TEST=Added coverage for new API to DeferredCanvas unit test. Added DeferredCanvas bench test to track deferred canvas overhead cost. Review URL: https://codereview.appspot.com/6442108 git-svn-id: http://skia.googlecode.com/svn/trunk@5078 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
e4ee35dc08
Коммит
9ed02b9da2
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkBenchmark.h"
|
||||
#include "SkDeferredCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkString.h"
|
||||
|
||||
class DeferredCanvasBench : public SkBenchmark {
|
||||
public:
|
||||
DeferredCanvasBench(void* param, const char name[]) : INHERITED(param) {
|
||||
fName.printf("deferred_canvas_%s", name);
|
||||
}
|
||||
|
||||
enum {
|
||||
N = SkBENCHLOOP(25), // number of times to create the picture
|
||||
CANVAS_WIDTH = 200,
|
||||
CANVAS_HEIGHT = 200,
|
||||
};
|
||||
protected:
|
||||
virtual const char* onGetName() {
|
||||
return fName.c_str();
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
SkDeferredCanvas deferredCanvas(canvas->getDevice()->createCompatibleDevice(
|
||||
SkBitmap::kARGB_8888_Config, CANVAS_WIDTH, CANVAS_HEIGHT, false));
|
||||
|
||||
initDeferredCanvas(deferredCanvas);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
drawInDeferredCanvas(deferredCanvas);
|
||||
}
|
||||
|
||||
finalizeDeferredCanvas(deferredCanvas);
|
||||
deferredCanvas.flush();
|
||||
}
|
||||
|
||||
virtual void initDeferredCanvas(SkDeferredCanvas& canvas) = 0;
|
||||
virtual void drawInDeferredCanvas(SkDeferredCanvas& canvas) = 0;
|
||||
virtual void finalizeDeferredCanvas(SkDeferredCanvas& canvas) = 0;
|
||||
|
||||
SkString fName;
|
||||
|
||||
private:
|
||||
typedef SkBenchmark INHERITED;
|
||||
};
|
||||
|
||||
class SimpleNotificationClient : public SkDeferredCanvas::NotificationClient {
|
||||
public:
|
||||
SimpleNotificationClient() : fDummy(false) {}
|
||||
|
||||
//bogus virtual implementations that just do something small
|
||||
virtual void prepareForDraw() SK_OVERRIDE {fDummy = true;}
|
||||
virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {fDummy = false;}
|
||||
virtual void flushedDrawCommands() SK_OVERRIDE {fDummy = !fDummy;}
|
||||
private:
|
||||
bool fDummy;
|
||||
};
|
||||
|
||||
// Test that records very simple draw operations.
|
||||
// This benchmark aims to capture performance fluctuations in the recording
|
||||
// overhead of SkDeferredCanvas
|
||||
class DeferredRecordBench : public DeferredCanvasBench {
|
||||
public:
|
||||
DeferredRecordBench(void* param)
|
||||
: INHERITED(param, "record") {
|
||||
}
|
||||
|
||||
enum {
|
||||
M = SkBENCHLOOP(700), // number of individual draws in each loop
|
||||
};
|
||||
protected:
|
||||
|
||||
virtual void initDeferredCanvas(SkDeferredCanvas& canvas) SK_OVERRIDE {
|
||||
canvas.setNotificationClient(SkNEW(SimpleNotificationClient))->unref();
|
||||
}
|
||||
|
||||
virtual void drawInDeferredCanvas(SkDeferredCanvas& canvas) SK_OVERRIDE {
|
||||
SkRect rect;
|
||||
rect.setXYWH(0, 0, 10, 10);
|
||||
SkPaint paint;
|
||||
for (int i = 0; i < M; i++) {
|
||||
canvas.save(SkCanvas::kMatrixClip_SaveFlag);
|
||||
canvas.translate(SkIntToScalar(i * 27 % CANVAS_WIDTH), SkIntToScalar(i * 13 % CANVAS_HEIGHT));
|
||||
canvas.drawRect(rect, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void finalizeDeferredCanvas(SkDeferredCanvas& canvas) SK_OVERRIDE {
|
||||
canvas.clear(0x0);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef DeferredCanvasBench INHERITED;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkBenchmark* Fact0(void* p) { return new DeferredRecordBench(p); }
|
||||
|
||||
static BenchRegistry gReg0(Fact0);
|
|
@ -13,6 +13,7 @@
|
|||
'../bench/ChromeBench.cpp',
|
||||
'../bench/DashBench.cpp',
|
||||
'../bench/DecodeBench.cpp',
|
||||
'../bench/DeferredCanvasBench.cpp',
|
||||
'../bench/FontScalerBench.cpp',
|
||||
'../bench/GradientBench.cpp',
|
||||
'../bench/GrMemoryPoolBench.cpp',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
|
@ -23,7 +23,7 @@ class DeferredDevice;
|
|||
*/
|
||||
class SK_API SkDeferredCanvas : public SkCanvas {
|
||||
public:
|
||||
class DeviceContext;
|
||||
class NotificationClient;
|
||||
|
||||
SkDeferredCanvas();
|
||||
|
||||
|
@ -35,17 +35,19 @@ public:
|
|||
|
||||
/** Construct a canvas with the specified device to draw into, and
|
||||
* a device context. Equivalent to calling default constructor, then
|
||||
* setDevice.
|
||||
* setDevice. The canvas takes reference on the device and notification
|
||||
* client.
|
||||
* @param device Specifies a device for the canvas to draw into.
|
||||
* @param deviceContext interface for the device's the graphics context
|
||||
* @param client Interface for dispatching notifications
|
||||
*/
|
||||
explicit SkDeferredCanvas(SkDevice* device, DeviceContext* deviceContext);
|
||||
explicit SkDeferredCanvas(SkDevice* device, NotificationClient* client);
|
||||
|
||||
virtual ~SkDeferredCanvas();
|
||||
|
||||
/**
|
||||
* Specify a device to be used by this canvas. Calling setDevice will
|
||||
* release the previously set device, if any.
|
||||
* release the previously set device, if any. Takes a reference on the
|
||||
* device.
|
||||
*
|
||||
* @param device The device that the canvas will raw into
|
||||
* @return The device argument, for convenience.
|
||||
|
@ -53,18 +55,20 @@ public:
|
|||
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.
|
||||
* Specify a NotificationClient to be used by this canvas. Calling
|
||||
* setNotificationClient will release the previously set
|
||||
* NotificationClient, if any. Takes a reference on the notification
|
||||
* client.
|
||||
* 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.
|
||||
* @param notificationClient interface for dispatching notifications
|
||||
* @return The notificationClient argument, for convenience.
|
||||
*/
|
||||
DeviceContext* setDeviceContext(DeviceContext* deviceContext);
|
||||
NotificationClient* setNotificationClient(NotificationClient* notificationClient);
|
||||
// Temporarily bootstrapping the deprecated method name
|
||||
NotificationClient* setDeviceContext(NotificationClient* notificationClient) {
|
||||
return setNotificationClient(notificationClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable deferred drawing. When deferral is disabled,
|
||||
|
@ -176,21 +180,43 @@ public:
|
|||
virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE;
|
||||
|
||||
public:
|
||||
class DeviceContext : public SkRefCnt {
|
||||
class NotificationClient : public SkRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(DeviceContext)
|
||||
SK_DECLARE_INST_COUNT(NotificationClient)
|
||||
|
||||
/**
|
||||
* Called before executing one or several draw commands, which means
|
||||
* once per flush when deferred rendering is enabled.
|
||||
*/
|
||||
virtual void prepareForDraw() {}
|
||||
|
||||
/**
|
||||
* Called after a recording a draw command if additional memory
|
||||
* had to be allocated for recording.
|
||||
* @param newAllocatedStorage same value as would be returned by
|
||||
* storageAllocatedForRecording(), for convenience.
|
||||
*/
|
||||
virtual void storageAllocatedForRecordingChanged(
|
||||
size_t newAllocatedStorage) {}
|
||||
|
||||
/**
|
||||
* Called after pending draw commands have been flushed
|
||||
*/
|
||||
virtual void flushedDrawCommands() {}
|
||||
|
||||
private:
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
// Temporarily bootstrapping the deprecated name for a smooth chromium DEPS roll
|
||||
typedef NotificationClient DeviceContext;
|
||||
|
||||
protected:
|
||||
virtual SkCanvas* canvasForDrawIter();
|
||||
DeferredDevice* getDeferredDevice() const;
|
||||
|
||||
private:
|
||||
void recordedDrawCommand();
|
||||
SkCanvas* drawingCanvas() const;
|
||||
SkCanvas* immediateCanvas() const;
|
||||
bool isFullFrame(const SkRect*, const SkPaint*) const;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "SkPaint.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkDeferredCanvas::DeviceContext)
|
||||
SK_DEFINE_INST_COUNT(SkDeferredCanvas::NotificationClient)
|
||||
|
||||
enum {
|
||||
// Deferred canvas will auto-flush when recording reaches this limit
|
||||
|
@ -233,10 +233,10 @@ void DeferredPipeController::reset() {
|
|||
class DeferredDevice : public SkDevice {
|
||||
public:
|
||||
DeferredDevice(SkDevice* immediateDevice,
|
||||
SkDeferredCanvas::DeviceContext* deviceContext = NULL);
|
||||
SkDeferredCanvas::NotificationClient* notificationClient = NULL);
|
||||
~DeferredDevice();
|
||||
|
||||
void setDeviceContext(SkDeferredCanvas::DeviceContext* deviceContext);
|
||||
void setNotificationClient(SkDeferredCanvas::NotificationClient* notificationClient);
|
||||
SkCanvas* recordingCanvas();
|
||||
SkCanvas* immediateCanvas() const {return fImmediateCanvas;}
|
||||
SkDevice* immediateDevice() const {return fImmediateDevice;}
|
||||
|
@ -246,6 +246,7 @@ public:
|
|||
void flushPending();
|
||||
void contentsCleared();
|
||||
void setMaxRecordingStorage(size_t);
|
||||
void recordedDrawCommand();
|
||||
|
||||
virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
|
||||
virtual int width() const SK_OVERRIDE;
|
||||
|
@ -337,20 +338,22 @@ private:
|
|||
SkDevice* fImmediateDevice;
|
||||
SkCanvas* fImmediateCanvas;
|
||||
SkCanvas* fRecordingCanvas;
|
||||
SkDeferredCanvas::DeviceContext* fDeviceContext;
|
||||
SkDeferredCanvas::NotificationClient* fNotificationClient;
|
||||
bool fFreshFrame;
|
||||
size_t fMaxRecordingStorageBytes;
|
||||
size_t fPreviousStorageAllocated;
|
||||
};
|
||||
|
||||
DeferredDevice::DeferredDevice(
|
||||
SkDevice* immediateDevice, SkDeferredCanvas::DeviceContext* deviceContext) :
|
||||
SkDevice* immediateDevice, SkDeferredCanvas::NotificationClient* notificationClient) :
|
||||
SkDevice(SkBitmap::kNo_Config, immediateDevice->width(),
|
||||
immediateDevice->height(), immediateDevice->isOpaque())
|
||||
, fFreshFrame(true) {
|
||||
, fFreshFrame(true)
|
||||
, fPreviousStorageAllocated(0){
|
||||
|
||||
fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
|
||||
fDeviceContext = deviceContext;
|
||||
SkSafeRef(fDeviceContext);
|
||||
fNotificationClient = notificationClient;
|
||||
SkSafeRef(fNotificationClient);
|
||||
fImmediateDevice = immediateDevice; // ref counted via fImmediateCanvas
|
||||
fImmediateCanvas = SkNEW_ARGS(SkCanvas, (fImmediateDevice));
|
||||
fPipeController.setPlaybackCanvas(fImmediateCanvas);
|
||||
|
@ -360,7 +363,7 @@ DeferredDevice::DeferredDevice(
|
|||
DeferredDevice::~DeferredDevice() {
|
||||
this->flushPending();
|
||||
SkSafeUnref(fImmediateCanvas);
|
||||
SkSafeUnref(fDeviceContext);
|
||||
SkSafeUnref(fNotificationClient);
|
||||
}
|
||||
|
||||
void DeferredDevice::setMaxRecordingStorage(size_t maxStorage) {
|
||||
|
@ -378,9 +381,9 @@ void DeferredDevice::beginRecording() {
|
|||
fRecordingCanvas = fPipeWriter.startRecording(&fPipeController, 0);
|
||||
}
|
||||
|
||||
void DeferredDevice::setDeviceContext(
|
||||
SkDeferredCanvas::DeviceContext* deviceContext) {
|
||||
SkRefCnt_SafeAssign(fDeviceContext, deviceContext);
|
||||
void DeferredDevice::setNotificationClient(
|
||||
SkDeferredCanvas::NotificationClient* notificationClient) {
|
||||
SkRefCnt_SafeAssign(fNotificationClient, notificationClient);
|
||||
}
|
||||
|
||||
void DeferredDevice::contentsCleared() {
|
||||
|
@ -402,6 +405,7 @@ void DeferredDevice::contentsCleared() {
|
|||
// old one, hence purging deferred draw ops.
|
||||
this->endRecording();
|
||||
this->beginRecording();
|
||||
fPreviousStorageAllocated = storageAllocatedForRecording();
|
||||
|
||||
// Restore pre-purge state
|
||||
if (!clipRegion.isEmpty()) {
|
||||
|
@ -428,12 +432,15 @@ void DeferredDevice::flushPending() {
|
|||
if (!fPipeController.hasRecorded()) {
|
||||
return;
|
||||
}
|
||||
if (fDeviceContext) {
|
||||
fDeviceContext->prepareForDraw();
|
||||
if (fNotificationClient) {
|
||||
fNotificationClient->prepareForDraw();
|
||||
}
|
||||
|
||||
fPipeWriter.flushRecording(true);
|
||||
fPipeController.playback();
|
||||
if (fNotificationClient) {
|
||||
fNotificationClient->flushedDrawCommands();
|
||||
}
|
||||
fPreviousStorageAllocated = storageAllocatedForRecording();
|
||||
}
|
||||
|
||||
void DeferredDevice::flush() {
|
||||
|
@ -442,7 +449,9 @@ void DeferredDevice::flush() {
|
|||
}
|
||||
|
||||
size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
|
||||
return fPipeWriter.freeMemoryIfPossible(bytesToFree);
|
||||
size_t val = fPipeWriter.freeMemoryIfPossible(bytesToFree);
|
||||
fPreviousStorageAllocated = storageAllocatedForRecording();
|
||||
return val;
|
||||
}
|
||||
|
||||
size_t DeferredDevice::storageAllocatedForRecording() const {
|
||||
|
@ -450,8 +459,9 @@ size_t DeferredDevice::storageAllocatedForRecording() const {
|
|||
+ fPipeWriter.storageAllocatedForRecording());
|
||||
}
|
||||
|
||||
SkCanvas* DeferredDevice::recordingCanvas() {
|
||||
void DeferredDevice::recordedDrawCommand() {
|
||||
size_t storageAllocated = this->storageAllocatedForRecording();
|
||||
|
||||
if (storageAllocated > fMaxRecordingStorageBytes) {
|
||||
// First, attempt to reduce cache without flushing
|
||||
size_t tryFree = storageAllocated - fMaxRecordingStorageBytes;
|
||||
|
@ -462,7 +472,17 @@ SkCanvas* DeferredDevice::recordingCanvas() {
|
|||
// which could cause a high flushing frequency.
|
||||
this->freeMemoryIfPossible(~0);
|
||||
}
|
||||
storageAllocated = this->storageAllocatedForRecording();
|
||||
}
|
||||
|
||||
if (fNotificationClient &&
|
||||
storageAllocated != fPreviousStorageAllocated) {
|
||||
fPreviousStorageAllocated = storageAllocated;
|
||||
fNotificationClient->storageAllocatedForRecordingChanged(storageAllocated);
|
||||
}
|
||||
}
|
||||
|
||||
SkCanvas* DeferredDevice::recordingCanvas() {
|
||||
return fRecordingCanvas;
|
||||
}
|
||||
|
||||
|
@ -507,6 +527,8 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
|
|||
fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
|
||||
} else {
|
||||
this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
|
||||
this->recordedDrawCommand();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,7 +547,7 @@ SkDevice* DeferredDevice::onCreateCompatibleDevice(
|
|||
SkAutoTUnref<SkDevice> compatibleDevice
|
||||
(fImmediateDevice->createCompatibleDevice(config, width, height,
|
||||
isOpaque));
|
||||
return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fDeviceContext));
|
||||
return SkNEW_ARGS(DeferredDevice, (compatibleDevice, fNotificationClient));
|
||||
}
|
||||
|
||||
bool DeferredDevice::onReadPixels(
|
||||
|
@ -546,10 +568,10 @@ SkDeferredCanvas::SkDeferredCanvas(SkDevice* device) {
|
|||
}
|
||||
|
||||
SkDeferredCanvas::SkDeferredCanvas(SkDevice* device,
|
||||
DeviceContext* deviceContext) {
|
||||
NotificationClient* notificationClient) {
|
||||
this->init();
|
||||
this->setDevice(device);
|
||||
this->setDeviceContext(deviceContext);
|
||||
this->setNotificationClient(notificationClient);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::init() {
|
||||
|
@ -569,6 +591,12 @@ size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
|
|||
return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::recordedDrawCommand() {
|
||||
if (fDeferredDrawing) {
|
||||
this->getDeferredDevice()->recordedDrawCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::validate() const {
|
||||
SkASSERT(this->getDevice());
|
||||
}
|
||||
|
@ -615,15 +643,15 @@ SkDevice* SkDeferredCanvas::setDevice(SkDevice* device) {
|
|||
return device;
|
||||
}
|
||||
|
||||
SkDeferredCanvas::DeviceContext* SkDeferredCanvas::setDeviceContext(
|
||||
DeviceContext* deviceContext) {
|
||||
SkDeferredCanvas::NotificationClient* SkDeferredCanvas::setNotificationClient(
|
||||
NotificationClient* notificationClient) {
|
||||
|
||||
DeferredDevice* deferredDevice = this->getDeferredDevice();
|
||||
SkASSERT(deferredDevice);
|
||||
if (deferredDevice) {
|
||||
deferredDevice->setDeviceContext(deviceContext);
|
||||
deferredDevice->setNotificationClient(notificationClient);
|
||||
}
|
||||
return deviceContext;
|
||||
return notificationClient;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
|
||||
|
@ -683,7 +711,10 @@ bool SkDeferredCanvas::isFullFrame(const SkRect* rect,
|
|||
|
||||
int SkDeferredCanvas::save(SaveFlags flags) {
|
||||
this->drawingCanvas()->save(flags);
|
||||
return this->INHERITED::save(flags);
|
||||
int val = this->INHERITED::save(flags);
|
||||
this->recordedDrawCommand();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
|
@ -691,12 +722,15 @@ int SkDeferredCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
|||
this->drawingCanvas()->saveLayer(bounds, paint, flags);
|
||||
int count = this->INHERITED::save(flags);
|
||||
this->clipRectBounds(bounds, flags, NULL);
|
||||
this->recordedDrawCommand();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::restore() {
|
||||
this->drawingCanvas()->restore();
|
||||
this->INHERITED::restore();
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::isDrawingToLayer() const {
|
||||
|
@ -705,52 +739,69 @@ bool SkDeferredCanvas::isDrawingToLayer() const {
|
|||
|
||||
bool SkDeferredCanvas::translate(SkScalar dx, SkScalar dy) {
|
||||
this->drawingCanvas()->translate(dx, dy);
|
||||
return this->INHERITED::translate(dx, dy);
|
||||
bool val = this->INHERITED::translate(dx, dy);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::scale(SkScalar sx, SkScalar sy) {
|
||||
this->drawingCanvas()->scale(sx, sy);
|
||||
return this->INHERITED::scale(sx, sy);
|
||||
bool val = this->INHERITED::scale(sx, sy);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::rotate(SkScalar degrees) {
|
||||
this->drawingCanvas()->rotate(degrees);
|
||||
return this->INHERITED::rotate(degrees);
|
||||
bool val = this->INHERITED::rotate(degrees);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::skew(SkScalar sx, SkScalar sy) {
|
||||
this->drawingCanvas()->skew(sx, sy);
|
||||
return this->INHERITED::skew(sx, sy);
|
||||
bool val = this->INHERITED::skew(sx, sy);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::concat(const SkMatrix& matrix) {
|
||||
this->drawingCanvas()->concat(matrix);
|
||||
return this->INHERITED::concat(matrix);
|
||||
bool val = this->INHERITED::concat(matrix);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::setMatrix(const SkMatrix& matrix) {
|
||||
this->drawingCanvas()->setMatrix(matrix);
|
||||
this->INHERITED::setMatrix(matrix);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipRect(const SkRect& rect,
|
||||
SkRegion::Op op,
|
||||
bool doAntiAlias) {
|
||||
this->drawingCanvas()->clipRect(rect, op, doAntiAlias);
|
||||
return this->INHERITED::clipRect(rect, op, doAntiAlias);
|
||||
bool val = this->INHERITED::clipRect(rect, op, doAntiAlias);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipPath(const SkPath& path,
|
||||
SkRegion::Op op,
|
||||
bool doAntiAlias) {
|
||||
this->drawingCanvas()->clipPath(path, op, doAntiAlias);
|
||||
return this->INHERITED::clipPath(path, op, doAntiAlias);
|
||||
bool val = this->INHERITED::clipPath(path, op, doAntiAlias);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool SkDeferredCanvas::clipRegion(const SkRegion& deviceRgn,
|
||||
SkRegion::Op op) {
|
||||
this->drawingCanvas()->clipRegion(deviceRgn, op);
|
||||
return this->INHERITED::clipRegion(deviceRgn, op);
|
||||
bool val = this->INHERITED::clipRegion(deviceRgn, op);
|
||||
this->recordedDrawCommand();
|
||||
return val;
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::clear(SkColor color) {
|
||||
|
@ -760,6 +811,7 @@ void SkDeferredCanvas::clear(SkColor color) {
|
|||
}
|
||||
|
||||
this->drawingCanvas()->clear(color);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
|
||||
|
@ -769,12 +821,14 @@ void SkDeferredCanvas::drawPaint(const SkPaint& paint) {
|
|||
}
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawPaint(paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPoints(PointMode mode, size_t count,
|
||||
const SkPoint pts[], const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawPoints(mode, count, pts, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
|
||||
|
@ -785,11 +839,13 @@ void SkDeferredCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
|
|||
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawRect(rect, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawPath(path, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
|
||||
|
@ -804,6 +860,7 @@ void SkDeferredCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
|
|||
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
|
||||
this->drawingCanvas()->drawBitmap(bitmap, left, top, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
|
||||
|
@ -818,6 +875,7 @@ void SkDeferredCanvas::drawBitmapRect(const SkBitmap& bitmap,
|
|||
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
|
||||
this->drawingCanvas()->drawBitmapRect(bitmap, src, dst, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
|
||||
|
@ -828,6 +886,7 @@ void SkDeferredCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
|
|||
// covers canvas entirely and transformed bitmap covers canvas entirely
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
|
||||
this->drawingCanvas()->drawBitmapMatrix(bitmap, m, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
|
||||
|
@ -837,6 +896,7 @@ void SkDeferredCanvas::drawBitmapNine(const SkBitmap& bitmap,
|
|||
// covers canvas entirely and dst covers canvas entirely
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
|
||||
this->drawingCanvas()->drawBitmapNine(bitmap, center, dst, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
|
||||
|
@ -854,18 +914,21 @@ void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
|
|||
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &bitmap, paint);
|
||||
this->drawingCanvas()->drawSprite(bitmap, left, top, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawText(const void* text, size_t byteLength,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawText(text, byteLength, x, y, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPosText(const void* text, size_t byteLength,
|
||||
const SkPoint pos[], const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawPosText(text, byteLength, pos, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
|
||||
|
@ -873,6 +936,7 @@ void SkDeferredCanvas::drawPosTextH(const void* text, size_t byteLength,
|
|||
const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawPosTextH(text, byteLength, xpos, constY, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
|
||||
|
@ -881,10 +945,12 @@ void SkDeferredCanvas::drawTextOnPath(const void* text, size_t byteLength,
|
|||
const SkPaint& paint) {
|
||||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawTextOnPath(text, byteLength, path, matrix, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawPicture(SkPicture& picture) {
|
||||
this->drawingCanvas()->drawPicture(picture);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
|
||||
|
@ -896,16 +962,21 @@ void SkDeferredCanvas::drawVertices(VertexMode vmode, int vertexCount,
|
|||
AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
|
||||
this->drawingCanvas()->drawVertices(vmode, vertexCount, vertices, texs, colors, xmode,
|
||||
indices, indexCount, paint);
|
||||
this->recordedDrawCommand();
|
||||
}
|
||||
|
||||
SkBounder* SkDeferredCanvas::setBounder(SkBounder* bounder) {
|
||||
this->drawingCanvas()->setBounder(bounder);
|
||||
return this->INHERITED::setBounder(bounder);
|
||||
this->INHERITED::setBounder(bounder);
|
||||
this->recordedDrawCommand();
|
||||
return bounder;
|
||||
}
|
||||
|
||||
SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
|
||||
this->drawingCanvas()->setDrawFilter(filter);
|
||||
return this->INHERITED::setDrawFilter(filter);
|
||||
this->INHERITED::setDrawFilter(filter);
|
||||
this->recordedDrawCommand();
|
||||
return filter;
|
||||
}
|
||||
|
||||
SkCanvas* SkDeferredCanvas::canvasForDrawIter() {
|
||||
|
|
|
@ -214,12 +214,34 @@ static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
|
|||
REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
|
||||
}
|
||||
|
||||
class NotificationCounter : public SkDeferredCanvas::NotificationClient {
|
||||
public:
|
||||
NotificationCounter() {
|
||||
fPrepareForDrawCount = fStorageAllocatedChangedCount = fFlushedDrawCommandsCount = 0;
|
||||
}
|
||||
|
||||
virtual void prepareForDraw() SK_OVERRIDE {
|
||||
fPrepareForDrawCount++;
|
||||
}
|
||||
virtual void storageAllocatedForRecordingChanged(size_t size) SK_OVERRIDE {
|
||||
fStorageAllocatedChangedCount++;
|
||||
}
|
||||
virtual void flushedDrawCommands() SK_OVERRIDE {
|
||||
fFlushedDrawCommandsCount++;
|
||||
}
|
||||
|
||||
int fPrepareForDrawCount;
|
||||
int fStorageAllocatedChangedCount;
|
||||
int fFlushedDrawCommandsCount;
|
||||
};
|
||||
|
||||
static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
|
||||
SkBitmap store;
|
||||
store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
|
||||
store.allocPixels();
|
||||
SkDevice device(store);
|
||||
SkDeferredCanvas canvas(&device);
|
||||
NotificationCounter notificationCounter;
|
||||
SkDeferredCanvas canvas(&device, ¬ificationCounter);
|
||||
|
||||
const int imageCount = 2;
|
||||
SkBitmap sourceImages[imageCount];
|
||||
|
@ -232,6 +254,7 @@ static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
|
|||
size_t bitmapSize = sourceImages[0].getSize();
|
||||
|
||||
canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
|
||||
REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
|
||||
// stored bitmap + drawBitmap command
|
||||
REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > bitmapSize);
|
||||
|
||||
|
@ -239,7 +262,11 @@ static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
|
|||
REPORTER_ASSERT(reporter, 0 == canvas.freeMemoryIfPossible(~0));
|
||||
|
||||
// verify that flush leaves image in cache
|
||||
REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
|
||||
canvas.flush();
|
||||
REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
|
||||
REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() >= bitmapSize);
|
||||
|
||||
// verify that after a flush, cached image can be freed
|
||||
|
@ -247,20 +274,27 @@ static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
|
|||
|
||||
// Verify that caching works for avoiding multiple copies of the same bitmap
|
||||
canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
|
||||
REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
|
||||
canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
|
||||
REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
|
||||
REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < 2 * bitmapSize);
|
||||
|
||||
// Verify partial eviction based on bytesToFree
|
||||
canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
|
||||
REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
canvas.flush();
|
||||
REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2 * bitmapSize);
|
||||
size_t bytesFreed = canvas.freeMemoryIfPossible(1);
|
||||
REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
|
||||
REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
|
||||
|
||||
// Verifiy that partial purge works, image zero is in cache but not reffed by
|
||||
// a pending draw, while image 1 is locked-in.
|
||||
canvas.freeMemoryIfPossible(~0);
|
||||
REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
|
||||
canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
|
||||
canvas.flush();
|
||||
canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
|
||||
|
|
Загрузка…
Ссылка в новой задаче