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:
junov@chromium.org 2012-08-14 13:36:26 +00:00
Родитель e4ee35dc08
Коммит 9ed02b9da2
5 изменённых файлов: 292 добавлений и 53 удалений

Просмотреть файл

@ -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, &notificationCounter);
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);