Fixing SkDeferredCanvas::writePixels to trigger appropriate change notifications to SkSurface
BUG=crbug.com/256269 TEST=DeferredCanvas unit test, TestDeferredCanvasWritePixelsToSurface R=reed@google.com Review URL: https://codereview.chromium.org/20628005 git-svn-id: http://skia.googlecode.com/svn/trunk@10513 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
b6c79859a1
commit
44324fae1c
@ -242,6 +242,8 @@ private:
|
||||
|
||||
void beginRecording();
|
||||
void init();
|
||||
void aboutToDraw();
|
||||
void prepareForImmediatePixelWrite();
|
||||
|
||||
DeferredPipeController fPipeController;
|
||||
SkGPipeWriter fPipeWriter;
|
||||
@ -343,23 +345,26 @@ bool DeferredDevice::hasPendingCommands() {
|
||||
return fPipeController.hasPendingCommands();
|
||||
}
|
||||
|
||||
void DeferredDevice::flushPendingCommands(PlaybackMode playbackMode) {
|
||||
if (!fPipeController.hasPendingCommands()) {
|
||||
return;
|
||||
}
|
||||
if (playbackMode == kNormal_PlaybackMode) {
|
||||
void DeferredDevice::aboutToDraw()
|
||||
{
|
||||
if (NULL != fNotificationClient) {
|
||||
fNotificationClient->prepareForDraw();
|
||||
}
|
||||
if (fCanDiscardCanvasContents) {
|
||||
if (NULL != fSurface) {
|
||||
// Pre-empt notifyContentChanged(false) calls that will happen
|
||||
// during flush
|
||||
fSurface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
|
||||
}
|
||||
fCanDiscardCanvasContents = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DeferredDevice::flushPendingCommands(PlaybackMode playbackMode) {
|
||||
if (!fPipeController.hasPendingCommands()) {
|
||||
return;
|
||||
}
|
||||
if (playbackMode == kNormal_PlaybackMode) {
|
||||
aboutToDraw();
|
||||
}
|
||||
fPipeWriter.flushRecording(true);
|
||||
fPipeController.playback(kSilent_PlaybackMode == playbackMode);
|
||||
if (playbackMode == kNormal_PlaybackMode && fNotificationClient) {
|
||||
@ -441,6 +446,23 @@ GrRenderTarget* DeferredDevice::accessRenderTarget() {
|
||||
return immediateDevice()->accessRenderTarget();
|
||||
}
|
||||
|
||||
void DeferredDevice::prepareForImmediatePixelWrite() {
|
||||
// The purpose of the following code is to make sure commands are flushed, that
|
||||
// aboutToDraw() is called and that notifyContentWillChange is called, without
|
||||
// calling anything redundantly.
|
||||
if (fPipeController.hasPendingCommands()) {
|
||||
this->flushPendingCommands(kNormal_PlaybackMode);
|
||||
} else {
|
||||
bool mustNotifyDirectly = !fCanDiscardCanvasContents;
|
||||
this->aboutToDraw();
|
||||
if (mustNotifyDirectly) {
|
||||
fSurface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
|
||||
}
|
||||
}
|
||||
|
||||
fImmediateCanvas->flush();
|
||||
}
|
||||
|
||||
void DeferredDevice::writePixels(const SkBitmap& bitmap,
|
||||
int x, int y, SkCanvas::Config8888 config8888) {
|
||||
|
||||
@ -453,7 +475,7 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
|
||||
SkCanvas::kNative_Premul_Config8888 != config8888 &&
|
||||
kPMColorAlias != config8888) {
|
||||
//Special case config: no deferral
|
||||
this->flushPendingCommands(kNormal_PlaybackMode);
|
||||
prepareForImmediatePixelWrite();
|
||||
immediateDevice()->writePixels(bitmap, x, y, config8888);
|
||||
return;
|
||||
}
|
||||
@ -461,7 +483,7 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
if (shouldDrawImmediately(&bitmap, NULL, getBitmapSizeThreshold())) {
|
||||
this->flushPendingCommands(kNormal_PlaybackMode);
|
||||
prepareForImmediatePixelWrite();
|
||||
fImmediateCanvas->drawSprite(bitmap, x, y, &paint);
|
||||
} else {
|
||||
this->recordingCanvas()->drawSprite(bitmap, x, y, &paint);
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "SkDevice.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkSurface.h"
|
||||
#include "../src/image/SkSurface_Base.h"
|
||||
#include "../src/image/SkImagePriv.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContextFactory.h"
|
||||
#else
|
||||
@ -49,6 +50,221 @@ static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) {
|
||||
REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef());
|
||||
}
|
||||
|
||||
class MockSurface : public SkSurface_Base {
|
||||
public:
|
||||
MockSurface(int width, int height) : SkSurface_Base(width, height) {
|
||||
clearCounts();
|
||||
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
fBitmap.allocPixels();
|
||||
}
|
||||
|
||||
virtual SkCanvas* onNewCanvas() SK_OVERRIDE {
|
||||
return SkNEW_ARGS(SkCanvas, (fBitmap));
|
||||
}
|
||||
|
||||
virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
|
||||
return SkNewImageFromBitmap(fBitmap, true);
|
||||
}
|
||||
|
||||
virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {
|
||||
if (mode == SkSurface::kDiscard_ContentChangeMode) {
|
||||
fDiscardCount++;
|
||||
} else {
|
||||
fRetainCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void clearCounts() {
|
||||
fDiscardCount = 0;
|
||||
fRetainCount = 0;
|
||||
}
|
||||
|
||||
int fDiscardCount, fRetainCount;
|
||||
SkBitmap fBitmap;
|
||||
};
|
||||
|
||||
static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) {
|
||||
SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10)));
|
||||
SkAutoTUnref<SkDeferredCanvas> canvas(
|
||||
#if SK_DEFERRED_CANVAS_USES_FACTORIES
|
||||
SkDeferredCanvas::Create(surface.get()));
|
||||
#else
|
||||
SkNEW_ARGS(SkDeferredCanvas, (surface.get())));
|
||||
#endif
|
||||
|
||||
SkBitmap srcBitmap;
|
||||
srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
|
||||
srcBitmap.allocPixels();
|
||||
srcBitmap.eraseColor(SK_ColorGREEN);
|
||||
// Tests below depend on this bitmap being recognized as opaque
|
||||
|
||||
// Preliminary sanity check: no copy on write if no active snapshot
|
||||
surface->clearCounts();
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 1: Discard notification happens upon flushing
|
||||
// with an Image attached.
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 2: Opaque writePixels
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 0, 0);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 3: writePixels that partially covers the canvas
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 5, 0);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
|
||||
|
||||
// Case 4: unpremultiplied opaque writePixels that entirely
|
||||
// covers the canvas
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 5: unpremultiplied opaque writePixels that partially
|
||||
// covers the canvas
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 6: unpremultiplied opaque writePixels that entirely
|
||||
// covers the canvas, preceded by clear
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 7: unpremultiplied opaque writePixels that partially
|
||||
// covers the canvas, preceeded by a clear
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
// Case 8: unpremultiplied opaque writePixels that partially
|
||||
// covers the canvas, preceeded by a drawREct that partially
|
||||
// covers the canvas
|
||||
surface->clearCounts();
|
||||
SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
SkPaint paint;
|
||||
canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
|
||||
|
||||
surface->clearCounts();
|
||||
canvas->flush();
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
|
||||
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
|
||||
}
|
||||
|
||||
static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
|
||||
SkBitmap store;
|
||||
|
||||
@ -689,6 +905,7 @@ static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* f
|
||||
TestDeferredCanvasBitmapShaderNoLeak(reporter);
|
||||
TestDeferredCanvasBitmapSizeThreshold(reporter);
|
||||
TestDeferredCanvasCreateCompatibleDevice(reporter);
|
||||
TestDeferredCanvasWritePixelsToSurface(reporter);
|
||||
TestDeferredCanvasSurface(reporter, NULL);
|
||||
TestDeferredCanvasSetSurface(reporter, NULL);
|
||||
if (NULL != factory) {
|
||||
|
Loading…
Reference in New Issue
Block a user