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:
parent
f68154a3cf
commit
7775fd5779
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user