DeferredCanvasTest.cpp revision 3de7acc180e37c7c513f2b3425bd4616ea47fa57
1 2/* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "Test.h" 9#include "SkBitmap.h" 10#include "SkDeferredCanvas.h" 11#include "SkShader.h" 12 13static const int gWidth = 2; 14static const int gHeight = 2; 15 16static void create(SkBitmap* bm, SkBitmap::Config config, SkColor color) { 17 bm->setConfig(config, gWidth, gHeight); 18 bm->allocPixels(); 19 bm->eraseColor(color); 20} 21 22static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) { 23 SkBitmap store; 24 25 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); 26 SkDevice device(store); 27 SkDeferredCanvas canvas(&device); 28 29 canvas.clear(0x00000000); 30 31 SkAutoLockPixels alp(store); 32 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred 33 SkBitmap accessed = canvas.getDevice()->accessBitmap(false); 34 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed 35 REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef()); 36} 37 38static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) { 39 SkBitmap store; 40 41 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); 42 SkDevice device(store); 43 SkDeferredCanvas canvas(&device); 44 45 canvas.clear(0x00000000); 46 47 SkAutoLockPixels alp(store); 48 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred 49 canvas.flush(); 50 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed 51} 52 53static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) { 54 SkBitmap store; 55 SkRect fullRect; 56 fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth), 57 SkIntToScalar(gHeight)); 58 SkRect partialRect; 59 partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), 60 SkIntToScalar(1), SkIntToScalar(1)); 61 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); 62 SkDevice device(store); 63 SkDeferredCanvas canvas(&device); 64 65 // verify that frame is intially fresh 66 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 67 // no clearing op since last call to isFreshFrame -> not fresh 68 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 69 70 // Verify that clear triggers a fresh frame 71 canvas.clear(0x00000000); 72 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 73 74 // Verify that clear with saved state triggers a fresh frame 75 canvas.save(SkCanvas::kMatrixClip_SaveFlag); 76 canvas.clear(0x00000000); 77 canvas.restore(); 78 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 79 80 // Verify that clear within a layer does NOT trigger a fresh frame 81 canvas.saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag); 82 canvas.clear(0x00000000); 83 canvas.restore(); 84 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 85 86 // Verify that a clear with clipping triggers a fresh frame 87 // (clear is not affected by clipping) 88 canvas.save(SkCanvas::kMatrixClip_SaveFlag); 89 canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false); 90 canvas.clear(0x00000000); 91 canvas.restore(); 92 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 93 94 // Verify that full frame rects with different forms of opaque paint 95 // trigger frames to be marked as fresh 96 { 97 SkPaint paint; 98 paint.setStyle( SkPaint::kFill_Style ); 99 paint.setAlpha( 255 ); 100 canvas.drawRect(fullRect, paint); 101 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 102 } 103 { 104 SkPaint paint; 105 paint.setStyle( SkPaint::kFill_Style ); 106 SkBitmap bmp; 107 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); 108 bmp.setIsOpaque(true); 109 SkShader* shader = SkShader::CreateBitmapShader(bmp, 110 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 111 paint.setShader(shader)->unref(); 112 canvas.drawRect(fullRect, paint); 113 REPORTER_ASSERT(reporter, canvas.getDeferredDevice()->isFreshFrame()); 114 } 115 116 // Verify that full frame rects with different forms of non-opaque paint 117 // do not trigger frames to be marked as fresh 118 { 119 SkPaint paint; 120 paint.setStyle( SkPaint::kFill_Style ); 121 paint.setAlpha( 254 ); 122 canvas.drawRect(fullRect, paint); 123 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 124 } 125 { 126 SkPaint paint; 127 paint.setStyle( SkPaint::kFill_Style ); 128 SkBitmap bmp; 129 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF); 130 bmp.setIsOpaque(false); 131 SkShader* shader = SkShader::CreateBitmapShader(bmp, 132 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 133 paint.setShader(shader)->unref(); 134 canvas.drawRect(fullRect, paint); 135 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 136 } 137 138 // Verify that incomplete coverage does not trigger a fresh frame 139 { 140 SkPaint paint; 141 paint.setStyle(SkPaint::kFill_Style); 142 paint.setAlpha(255); 143 canvas.drawRect(partialRect, paint); 144 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 145 } 146 147 // Verify that incomplete coverage due to clipping does not trigger a fresh 148 // frame 149 { 150 canvas.save(SkCanvas::kMatrixClip_SaveFlag); 151 canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false); 152 SkPaint paint; 153 paint.setStyle(SkPaint::kFill_Style); 154 paint.setAlpha(255); 155 canvas.drawRect(fullRect, paint); 156 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 157 } 158 159 // Verify that stroked rect does not trigger a fresh frame 160 { 161 SkPaint paint; 162 paint.setStyle( SkPaint::kStroke_Style ); 163 paint.setAlpha( 255 ); 164 canvas.drawRect(fullRect, paint); 165 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 166 } 167 168 // Verify kSrcMode triggers a fresh frame even with transparent color 169 { 170 SkPaint paint; 171 paint.setStyle( SkPaint::kFill_Style ); 172 paint.setAlpha( 100 ); 173 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 174 canvas.drawRect(fullRect, paint); 175 REPORTER_ASSERT(reporter, !canvas.getDeferredDevice()->isFreshFrame()); 176 } 177} 178 179class MockDevice : public SkDevice { 180public: 181 MockDevice(const SkBitmap& bm) : SkDevice(bm) { 182 fDrawBitmapCallCount = 0; 183 } 184 virtual void drawBitmap(const SkDraw&, const SkBitmap&, 185 const SkIRect*, 186 const SkMatrix&, const SkPaint&) { 187 fDrawBitmapCallCount++; 188 } 189 190 int fDrawBitmapCallCount; 191}; 192 193// Verifies that the deferred canvas triggers a flush when its memory 194// limit is exceeded 195static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) { 196 SkBitmap store; 197 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 198 store.allocPixels(); 199 MockDevice mockDevice(store); 200 SkDeferredCanvas canvas(&mockDevice); 201 canvas.setMaxRecordingStorage(160000); 202 203 SkBitmap sourceImage; 204 // 100 by 100 image, takes 40,000 bytes in memory 205 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 206 sourceImage.allocPixels(); 207 208 for (int i = 0; i < 5; i++) { 209 sourceImage.notifyPixelsChanged(); // to force re-serialization 210 canvas.drawBitmap(sourceImage, 0, 0, NULL); 211 } 212 213 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4); 214} 215 216static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) { 217 SkBitmap store; 218 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 219 store.allocPixels(); 220 SkDevice device(store); 221 SkDeferredCanvas canvas(&device); 222 223 const int imageCount = 2; 224 SkBitmap sourceImages[imageCount]; 225 for (int i = 0; i < imageCount; i++) 226 { 227 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 228 sourceImages[i].allocPixels(); 229 } 230 231 size_t bitmapSize = sourceImages[0].getSize(); 232 233 canvas.drawBitmap(sourceImages[0], 0, 0, NULL); 234 // stored bitmap + drawBitmap command 235 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > bitmapSize); 236 237 // verify that nothing can be freed at this point 238 REPORTER_ASSERT(reporter, 0 == canvas.freeMemoryIfPossible(~0)); 239 240 // verify that flush leaves image in cache 241 canvas.flush(); 242 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() >= bitmapSize); 243 244 // verify that after a flush, cached image can be freed 245 REPORTER_ASSERT(reporter, canvas.freeMemoryIfPossible(~0) >= bitmapSize); 246 247 // Verify that caching works for avoiding multiple copies of the same bitmap 248 canvas.drawBitmap(sourceImages[0], 0, 0, NULL); 249 canvas.drawBitmap(sourceImages[0], 0, 0, NULL); 250 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < 2 * bitmapSize); 251 252 // Verify partial eviction based on bytesToFree 253 canvas.drawBitmap(sourceImages[1], 0, 0, NULL); 254 canvas.flush(); 255 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2 * bitmapSize); 256 size_t bytesFreed = canvas.freeMemoryIfPossible(1); 257 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize); 258 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize); 259 260 // Verifiy that partial purge works, image zero is in cache but not reffed by 261 // a pending draw, while image 1 is locked-in. 262 canvas.freeMemoryIfPossible(~0); 263 canvas.drawBitmap(sourceImages[0], 0, 0, NULL); 264 canvas.flush(); 265 canvas.drawBitmap(sourceImages[1], 0, 0, NULL); 266 bytesFreed = canvas.freeMemoryIfPossible(~0); 267 // only one bitmap should have been freed. 268 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize); 269 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize); 270 // Clear for next test 271 canvas.flush(); 272 canvas.freeMemoryIfPossible(~0); 273 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < bitmapSize); 274 275 // Verify the image cache is sensitive to genID bumps 276 canvas.drawBitmap(sourceImages[1], 0, 0, NULL); 277 sourceImages[1].notifyPixelsChanged(); 278 canvas.drawBitmap(sourceImages[1], 0, 0, NULL); 279 REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2*bitmapSize); 280} 281 282static void TestDeferredCanvas(skiatest::Reporter* reporter) { 283 TestDeferredCanvasBitmapAccess(reporter); 284 TestDeferredCanvasFlush(reporter); 285 TestDeferredCanvasFreshFrame(reporter); 286 TestDeferredCanvasMemoryLimit(reporter); 287 TestDeferredCanvasBitmapCaching(reporter); 288} 289 290#include "TestClassDef.h" 291DEFINE_TESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas) 292