Index: tests/DeferredCanvasTest.cpp |
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp |
index a5ef714fedc07a22508dbafdd9503caabdd238f6..5a7813a3a1b5fb94f321798ba0e5a8595a0affcd 100644 |
--- a/tests/DeferredCanvasTest.cpp |
+++ b/tests/DeferredCanvasTest.cpp |
@@ -48,16 +48,31 @@ static SkPMColor read_pixel(SkSurface* surface, int x, int y) { |
surface->draw(&canvas, -SkIntToScalar(x), -SkIntToScalar(y), &paint); |
return pixel; |
} |
+class MockSurface; |
+class MockDevice : public SkBitmapDevice { |
+public: |
+ MockDevice(MockSurface* surface, const SkBitmap& bm) : SkBitmapDevice(bm), fSurface(surface) { |
+ } |
+ void discard() SK_OVERRIDE; |
+ private: |
+ MockSurface* fSurface; |
+ typedef SkBitmapDevice INHERITED; |
+}; |
class MockSurface : public SkSurface_Base { |
public: |
MockSurface(int width, int height) : SkSurface_Base(width, height, NULL) { |
clearCounts(); |
- fBitmap.allocN32Pixels(width, height); |
+ |
+ SkBitmap bitmap; |
+ bitmap.allocN32Pixels(width, height); |
+ fDevice.reset(SkNEW_ARGS(MockDevice, (this, bitmap))); |
+ fDeviceGenerationID = fDevice->accessBitmap(false).getGenerationID(); |
+ fGenerationID = this->newGenerationID(); |
} |
SkCanvas* onNewCanvas() SK_OVERRIDE { |
- return SkNEW_ARGS(SkCanvas, (fBitmap)); |
+ return SkNEW_ARGS(SkCanvas, (fDevice)); |
} |
SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE { |
@@ -65,33 +80,40 @@ public: |
} |
SkImage* onNewImageSnapshot(Budgeted) SK_OVERRIDE { |
- return SkNewImageFromBitmap(fBitmap, &this->props()); |
+ return fDevice->newImageSnapshot(); |
} |
- void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE { |
- if (mode == SkSurface::kDiscard_ContentChangeMode) { |
- fCOWDiscardCount++; |
- } else { |
- fCOWRetainCount++; |
+ uint32_t generationID() SK_OVERRIDE { |
+ uint32_t deviceGenerationID = fDevice->accessBitmap(false).getGenerationID(); |
+ if (fDeviceGenerationID != deviceGenerationID) { |
+ fDeviceGenerationID = deviceGenerationID; |
+ fGenerationID = this->newGenerationID(); |
} |
+ return fGenerationID; |
} |
- void onDiscard() SK_OVERRIDE { |
+ void incDiscardCount() { |
fDiscardCount++; |
} |
void clearCounts() { |
- fCOWDiscardCount = 0; |
- fCOWRetainCount = 0; |
fDiscardCount = 0; |
} |
- int fCOWDiscardCount; |
- int fCOWRetainCount; |
+ SkAutoTUnref<MockDevice> fDevice; |
+ uint32_t fDeviceGenerationID; |
+ uint32_t fGenerationID; |
+ |
int fDiscardCount; |
- SkBitmap fBitmap; |
}; |
+void MockDevice::discard() { |
+ if (fSurface) { |
+ fSurface->incDiscardCount(); |
+ } |
+ this->INHERITED::discard(); |
+} |
+ |
static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) { |
SkAutoTUnref<MockSurface> surface(SkNEW_ARGS(MockSurface, (10, 10))); |
SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface.get())); |
@@ -101,174 +123,174 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter) |
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 |
- // Discard notification happens on SkSurface::onDiscard, since no |
- // active snapshot. |
+ |
+ // Case 0: SkBaseDevice::discard is called even when clear is the first command. |
+ // The call is made only after flush. |
+ uint32_t surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->clear(SK_ColorWHITE); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
- // Case 1: Discard notification happens upon flushing |
+ // Case 1: SkBaseDevice::discard is called upon flushing |
// with an Image attached. |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->clear(SK_ColorWHITE); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
// Case 2: Opaque writePixels |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 3: writePixels that partially covers the canvas |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image3(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 4: unpremultiplied opaque writePixels that entirely |
// covers the canvas |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image4(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->writePixels(srcBitmap, 0, 0); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 5: unpremultiplied opaque writePixels that partially |
- // covers the canvas |
+ // covers the canvas. The surface changes immediately. |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image5(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->writePixels(srcBitmap, 5, 0); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 6: unpremultiplied opaque writePixels that entirely |
- // covers the canvas, preceded by clear |
+ // covers the canvas, preceded by clear. |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image6(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->clear(SK_ColorWHITE); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->writePixels(srcBitmap, 0, 0); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 7: unpremultiplied opaque writePixels that partially |
// covers the canvas, preceeded by a clear |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image7(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->clear(SK_ColorWHITE); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->writePixels(srcBitmap, 5, 0); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWDiscardCount); // because of the clear |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
// Case 8: unpremultiplied opaque writePixels that partially |
// covers the canvas, preceeded by a drawREct that partially |
// covers the canvas |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkAutoTUnref<SkImage> image8(canvas->newImageSnapshot()); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
SkPaint paint; |
canvas->drawRect(SkRect::MakeLTRB(0, 0, 5, 5), paint); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->writePixels(srcBitmap, 5, 0); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 1 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID != surface->generationID()); |
+ surfaceID = surface->generationID(); |
surface->clearCounts(); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWDiscardCount); |
- REPORTER_ASSERT(reporter, 0 == surface->fCOWRetainCount); |
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount); |
+ REPORTER_ASSERT(reporter, surfaceID == surface->generationID()); |
} |
static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) { |
@@ -440,19 +462,6 @@ static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) { |
} |
} |
-class MockDevice : public SkBitmapDevice { |
-public: |
- MockDevice(const SkBitmap& bm) : SkBitmapDevice(bm) { |
- fDrawBitmapCallCount = 0; |
- } |
- virtual void drawBitmap(const SkDraw&, const SkBitmap&, |
- const SkMatrix&, const SkPaint&) SK_OVERRIDE { |
- fDrawBitmapCallCount++; |
- } |
- |
- int fDrawBitmapCallCount; |
-}; |
- |
class NotificationCounter : public SkDeferredCanvas::NotificationClient { |
public: |
NotificationCounter() { |
@@ -689,22 +698,6 @@ static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) |
} |
} |
- |
-typedef const void* PixelPtr; |
-// Returns an opaque pointer which, either points to a GrTexture or RAM pixel |
-// buffer. Used to test pointer equality do determine whether a surface points |
-// to the same pixel data storage as before. |
-static PixelPtr get_surface_ptr(SkSurface* surface, bool useGpu) { |
-#if SK_SUPPORT_GPU |
- if (useGpu) { |
- return surface->getCanvas()->internal_private_accessTopLayerRenderTarget()->asTexture(); |
- } else |
-#endif |
- { |
- return surface->peekPixels(NULL, NULL); |
- } |
-} |
- |
static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) { |
SkImageInfo imageSpec = SkImageInfo::MakeN32Premul(10, 10); |
bool useGpu = SkToBool(factory); |
@@ -745,10 +738,10 @@ static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFac |
SkImage* image1 = canvas->newImageSnapshot(); |
SkAutoTUnref<SkImage> aur_i1(image1); |
- PixelPtr pixels1 = get_surface_ptr(surface, useGpu); |
- // The following clear would normally trigger a copy on write, but |
+ // The following clear would normally trigger a surface modification, but |
// it won't because rendering is deferred. |
canvas->clear(SK_ColorBLACK); |
+ uint32_t genid1 = surface->generationID(); |
// Obtaining a snapshot directly from the surface (as opposed to the |
// SkDeferredCanvas) will not trigger a flush of deferred draw operations |
// and will therefore return the same image as the previous snapshot. |
@@ -756,34 +749,26 @@ static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFac |
SkAutoTUnref<SkImage> aur_i2(image2); |
// Images identical because of deferral |
REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID()); |
+ uint32_t genid2 = surface->generationID(); |
// Now we obtain a snpshot via the deferred canvas, which triggers a flush. |
// Because there is a pending clear, this will generate a different image. |
SkImage* image3 = canvas->newImageSnapshot(); |
SkAutoTUnref<SkImage> aur_i3(image3); |
REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID()); |
- // Verify that backing store is now a different buffer because of copy on |
- // write |
- PixelPtr pixels2 = get_surface_ptr(surface, useGpu); |
- REPORTER_ASSERT(reporter, pixels1 != pixels2); |
- // Verify copy-on write with a draw operation that gets deferred by |
+ // Verify that backing store is now a different buffer because of changed |
+ // surface generation id. |
+ uint32_t genid3 = surface->generationID(); |
+ REPORTER_ASSERT(reporter, genid1 == genid2); |
+ REPORTER_ASSERT(reporter, genid1 != genid3); |
+ // Verify surface modification with a draw operation that gets deferred by |
// the in order draw buffer. |
SkPaint paint; |
canvas->drawPaint(paint); |
SkImage* image4 = canvas->newImageSnapshot(); // implicit flush |
SkAutoTUnref<SkImage> aur_i4(image4); |
- REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID()); |
- PixelPtr pixels3 = get_surface_ptr(surface, useGpu); |
- REPORTER_ASSERT(reporter, pixels2 != pixels3); |
- // Verify that a direct canvas flush with a pending draw does not trigger |
- // a copy on write when the surface is not sharing its buffer with an |
- // SkImage. |
- canvas->clear(SK_ColorWHITE); |
- canvas->flush(); |
- PixelPtr pixels4 = get_surface_ptr(surface, useGpu); |
- canvas->drawPaint(paint); |
- canvas->flush(); |
- PixelPtr pixels5 = get_surface_ptr(surface, useGpu); |
- REPORTER_ASSERT(reporter, pixels4 == pixels5); |
+ REPORTER_ASSERT(reporter, image3->uniqueID() != image4->uniqueID()); |
+ uint32_t genid4 = surface->generationID(); |
+ REPORTER_ASSERT(reporter, genid3 != genid4); |
} |
} |
@@ -829,21 +814,21 @@ static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContext |
SkASSERT(alternateSurface); |
SkAutoTUnref<SkSurface> aur1(surface); |
SkAutoTUnref<SkSurface> aur2(alternateSurface); |
- PixelPtr pixels1 = get_surface_ptr(surface, useGpu); |
- PixelPtr pixels2 = get_surface_ptr(alternateSurface, useGpu); |
+ uint32_t genid1 = surface->generationID(); |
+ uint32_t genid2 = alternateSurface->generationID(); |
SkAutoTUnref<SkDeferredCanvas> canvas(SkDeferredCanvas::Create(surface)); |
SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot()); |
canvas->setSurface(alternateSurface); |
SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot()); |
REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID()); |
- // Verify that none of the above operations triggered a surface copy on write. |
- REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1); |
- REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) == pixels2); |
- // Verify that a flushed draw command will trigger a copy on write on alternateSurface. |
+ // Verify that none of the above operations triggered a surface modification. |
+ REPORTER_ASSERT(reporter, surface->generationID() == genid1); |
+ REPORTER_ASSERT(reporter, alternateSurface->generationID() == genid2); |
+ // Verify that a flushed draw command will trigger a modification on alternateSurface. |
canvas->clear(SK_ColorWHITE); |
canvas->flush(); |
- REPORTER_ASSERT(reporter, get_surface_ptr(surface, useGpu) == pixels1); |
- REPORTER_ASSERT(reporter, get_surface_ptr(alternateSurface, useGpu) != pixels2); |
+ REPORTER_ASSERT(reporter, surface->generationID() == genid1); |
+ REPORTER_ASSERT(reporter, alternateSurface->generationID() != genid2); |
} |
} |