aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar sugoi@google.com <sugoi@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-21 15:47:04 +0000
committerGravatar sugoi@google.com <sugoi@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-21 15:47:04 +0000
commit7775fd5779e632d6f5724e0e5d39ed347cf965b0 (patch)
tree42c72bb45da8d29e3818dddc94cc66088379a4d9
parentf68154a3cf43eb22d45be11f3b09e25440c366a6 (diff)
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
-rw-r--r--include/config/SkUserConfig.h8
-rw-r--r--include/utils/SkDeferredCanvas.h6
-rw-r--r--src/utils/SkDeferredCanvas.cpp93
-rw-r--r--tests/DeferredCanvasTest.cpp42
4 files changed, 115 insertions, 34 deletions
diff --git a/include/config/SkUserConfig.h b/include/config/SkUserConfig.h
index 79fdc7a2a4..ae5865ab37 100644
--- a/include/config/SkUserConfig.h
+++ b/include/config/SkUserConfig.h
@@ -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
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 97848f1129..4686d000b9 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -116,6 +116,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
*/
void silentFlush();
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 207ec053a7..ffc935d5de 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -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();
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index 860edf9a2a..6bbcf8284f 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -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"