Deferred canvas can now be flushed if an image is beyond a certain size to avoid a costly image copy.

BUG=http://code.google.com/p/chromium/issues/detail?id=137924
TEST=TestDeferredCanvasBitmapSizeThreshold unit test
Review URL: https://codereview.appspot.com/6852071

git-svn-id: http://skia.googlecode.com/svn/trunk@6527 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
sugoi@google.com 2012-11-21 15:47:04 +00:00
parent f68154a3cf
commit 7775fd5779
4 changed files with 115 additions and 34 deletions

View File

@ -199,4 +199,12 @@
backend. Defaults to 1 (build the GPU code).
*/
//#define SK_SUPPORT_GPU 1
/* Defines the maximum size allowed for a given image to be rendered using the
deferred canvas. If the image is larger than this threshold, the image
is considered too large and the copy done by the deferred canvas too
expensive, so an image of that size would instead be drawn immediately.
*/
//#define SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD 1048576
#endif

View File

@ -115,6 +115,12 @@ public:
*/
size_t freeMemoryIfPossible(size_t bytesToFree);
/**
* Specifies the maximum size (in bytes) allowed for a given image to be
* rendered using the deferred canvas.
*/
void setBitmapSizeThreshold(size_t sizeThreshold);
/**
* Executes all pending commands without drawing
*/

View File

@ -16,6 +16,10 @@
#include "SkPaint.h"
#include "SkShader.h"
#ifndef SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD
#define SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD ~0 // Disables this feature
#endif
enum {
// Deferred canvas will auto-flush when recording reaches this limit
kDefaultMaxRecordingStorageBytes = 64*1024*1024,
@ -27,8 +31,10 @@ enum PlaybackMode {
};
namespace {
bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint) {
if (bitmap && bitmap->getTexture() && !bitmap->isImmutable()) {
bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
size_t bitmapSizeThreshold) {
if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
(bitmap->getSize() > bitmapSizeThreshold))) {
return true;
}
if (paint) {
@ -50,36 +56,6 @@ bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint) {
}
}
class AutoImmediateDrawIfNeeded {
public:
AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
const SkPaint* paint) {
this->init(canvas, bitmap, paint);
}
AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
this->init(canvas, NULL, paint);
}
~AutoImmediateDrawIfNeeded() {
if (fCanvas) {
fCanvas->setDeferredDrawing(true);
}
}
private:
void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
{
if (canvas.isDeferredDrawing() && shouldDrawImmediately(bitmap, paint)) {
canvas.setDeferredDrawing(false);
fCanvas = &canvas;
} else {
fCanvas = NULL;
}
}
SkDeferredCanvas* fCanvas;
};
namespace {
bool isPaintOpaque(const SkPaint* paint,
@ -244,6 +220,8 @@ public:
bool hasPendingCommands();
size_t storageAllocatedForRecording() const;
size_t freeMemoryIfPossible(size_t bytesToFree);
size_t getBitmapSizeThreshold() const;
void setBitmapSizeThreshold(size_t sizeThreshold);
void flushPendingCommands(PlaybackMode);
void skipPendingCommands();
void setMaxRecordingStorage(size_t);
@ -339,6 +317,7 @@ private:
bool fFreshFrame;
size_t fMaxRecordingStorageBytes;
size_t fPreviousStorageAllocated;
size_t fBitmapSizeThreshold;
};
DeferredDevice::DeferredDevice(
@ -347,7 +326,8 @@ DeferredDevice::DeferredDevice(
immediateDevice->height(), immediateDevice->isOpaque())
, fRecordingCanvas(NULL)
, fFreshFrame(true)
, fPreviousStorageAllocated(0){
, fPreviousStorageAllocated(0)
, fBitmapSizeThreshold(SK_DEFERRED_CANVAS_BITMAP_SIZE_THRESHOLD){
fMaxRecordingStorageBytes = kDefaultMaxRecordingStorageBytes;
fNotificationClient = notificationClient;
@ -424,6 +404,14 @@ size_t DeferredDevice::freeMemoryIfPossible(size_t bytesToFree) {
return val;
}
size_t DeferredDevice::getBitmapSizeThreshold() const {
return fBitmapSizeThreshold;
}
void DeferredDevice::setBitmapSizeThreshold(size_t sizeThreshold) {
fBitmapSizeThreshold = sizeThreshold;
}
size_t DeferredDevice::storageAllocatedForRecording() const {
return (fPipeController.storageAllocatedForRecording()
+ fPipeWriter.storageAllocatedForRecording());
@ -492,7 +480,7 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
if (shouldDrawImmediately(&bitmap, NULL)) {
if (shouldDrawImmediately(&bitmap, NULL, getBitmapSizeThreshold())) {
this->flushPendingCommands(kNormal_PlaybackMode);
fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
} else {
@ -527,6 +515,37 @@ bool DeferredDevice::onReadPixels(
x, y, config8888);
}
class AutoImmediateDrawIfNeeded {
public:
AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkBitmap* bitmap,
const SkPaint* paint) {
this->init(canvas, bitmap, paint);
}
AutoImmediateDrawIfNeeded(SkDeferredCanvas& canvas, const SkPaint* paint) {
this->init(canvas, NULL, paint);
}
~AutoImmediateDrawIfNeeded() {
if (fCanvas) {
fCanvas->setDeferredDrawing(true);
}
}
private:
void init(SkDeferredCanvas& canvas, const SkBitmap* bitmap, const SkPaint* paint)
{
DeferredDevice* device = static_cast<DeferredDevice*>(canvas.getDevice());
if (canvas.isDeferredDrawing() && (NULL != device) &&
shouldDrawImmediately(bitmap, paint, device->getBitmapSizeThreshold())) {
canvas.setDeferredDrawing(false);
fCanvas = &canvas;
} else {
fCanvas = NULL;
}
}
SkDeferredCanvas* fCanvas;
};
SkDeferredCanvas::SkDeferredCanvas() {
this->init();
@ -554,6 +573,12 @@ size_t SkDeferredCanvas::freeMemoryIfPossible(size_t bytesToFree) {
return this->getDeferredDevice()->freeMemoryIfPossible(bytesToFree);
}
void SkDeferredCanvas::setBitmapSizeThreshold(size_t sizeThreshold) {
DeferredDevice* deferredDevice = this->getDeferredDevice();
SkASSERT(deferredDevice);
deferredDevice->setBitmapSizeThreshold(sizeThreshold);
}
void SkDeferredCanvas::recordedDrawCommand() {
if (fDeferredDrawing) {
this->getDeferredDevice()->recordedDrawCommand();

View File

@ -391,6 +391,47 @@ static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, 0 == canvas.storageAllocatedForRecording());
}
static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
SkBitmap store;
store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
store.allocPixels();
SkBitmap sourceImage;
// 100 by 100 image, takes 40,000 bytes in memory
sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
sourceImage.allocPixels();
// 1 under : should not store the image
{
SkDevice device(store);
SkDeferredCanvas canvas(&device);
canvas.setBitmapSizeThreshold(39999);
canvas.drawBitmap(sourceImage, 0, 0, NULL);
size_t newBytesAllocated = canvas.storageAllocatedForRecording();
REPORTER_ASSERT(reporter, newBytesAllocated == 0);
}
// exact value : should store the image
{
SkDevice device(store);
SkDeferredCanvas canvas(&device);
canvas.setBitmapSizeThreshold(40000);
canvas.drawBitmap(sourceImage, 0, 0, NULL);
size_t newBytesAllocated = canvas.storageAllocatedForRecording();
REPORTER_ASSERT(reporter, newBytesAllocated > 0);
}
// 1 over : should still store the image
{
SkDevice device(store);
SkDeferredCanvas canvas(&device);
canvas.setBitmapSizeThreshold(40001);
canvas.drawBitmap(sourceImage, 0, 0, NULL);
size_t newBytesAllocated = canvas.storageAllocatedForRecording();
REPORTER_ASSERT(reporter, newBytesAllocated > 0);
}
}
static void TestDeferredCanvas(skiatest::Reporter* reporter) {
TestDeferredCanvasBitmapAccess(reporter);
TestDeferredCanvasFlush(reporter);
@ -399,6 +440,7 @@ static void TestDeferredCanvas(skiatest::Reporter* reporter) {
TestDeferredCanvasBitmapCaching(reporter);
TestDeferredCanvasSkip(reporter);
TestDeferredCanvasBitmapShaderNoLeak(reporter);
TestDeferredCanvasBitmapSizeThreshold(reporter);
}
#include "TestClassDef.h"