blob: af2d3004b3ae2835643b9054ddb989f361d07487 [file] [log] [blame]
junov@chromium.org1f9767c2012-02-07 16:27:57 +00001
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"
junov@chromium.orgce65f382012-10-17 19:36:09 +000010#include "SkBitmapProcShader.h"
junov@chromium.org1f9767c2012-02-07 16:27:57 +000011#include "SkDeferredCanvas.h"
junov@chromium.org88e29142012-08-07 16:48:22 +000012#include "SkDevice.h"
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +000013#include "SkGradientShader.h"
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000014#include "SkShader.h"
junov@chromium.org67d74222013-04-12 13:33:01 +000015#include "SkSurface.h"
16#if SK_SUPPORT_GPU
17#include "GrContextFactory.h"
18#else
19class GrContextFactory;
20#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +000021
junov@chromium.org1f9767c2012-02-07 16:27:57 +000022static const int gWidth = 2;
23static const int gHeight = 2;
24
25static void create(SkBitmap* bm, SkBitmap::Config config, SkColor color) {
26 bm->setConfig(config, gWidth, gHeight);
27 bm->allocPixels();
28 bm->eraseColor(color);
29}
30
31static void TestDeferredCanvasBitmapAccess(skiatest::Reporter* reporter) {
32 SkBitmap store;
33
34 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
35 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +000036 SkAutoTUnref<SkDeferredCanvas> canvas(
37#if SK_DEFERRED_CANVAS_USES_FACTORIES
38 SkDeferredCanvas::Create(&device));
39#else
40 SkNEW_ARGS(SkDeferredCanvas, (&device)));
41#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +000042
junov@chromium.org66070a52013-05-28 17:39:08 +000043 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000044
45 SkAutoLockPixels alp(store);
46 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +000047 SkBitmap accessed = canvas->getDevice()->accessBitmap(false);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000048 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
49 REPORTER_ASSERT(reporter, accessed.pixelRef() == store.pixelRef());
50}
51
52static void TestDeferredCanvasFlush(skiatest::Reporter* reporter) {
53 SkBitmap store;
54
55 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
56 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +000057 SkAutoTUnref<SkDeferredCanvas> canvas(
58#if SK_DEFERRED_CANVAS_USES_FACTORIES
59 SkDeferredCanvas::Create(&device));
60#else
61 SkNEW_ARGS(SkDeferredCanvas, (&device)));
62#endif
junov@chromium.org1f9767c2012-02-07 16:27:57 +000063
junov@chromium.org66070a52013-05-28 17:39:08 +000064 canvas->clear(0x00000000);
junov@chromium.org1f9767c2012-02-07 16:27:57 +000065
66 SkAutoLockPixels alp(store);
67 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0xFFFFFFFF); //verify that clear was deferred
junov@chromium.org66070a52013-05-28 17:39:08 +000068 canvas->flush();
junov@chromium.org1f9767c2012-02-07 16:27:57 +000069 REPORTER_ASSERT(reporter, store.getColor(0,0) == 0x00000000); //verify that clear was executed
70}
71
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000072static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
73 SkBitmap store;
74 SkRect fullRect;
75 fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
76 SkIntToScalar(gHeight));
77 SkRect partialRect;
junov@chromium.orgb1e218e2012-02-13 22:27:58 +000078 partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
79 SkIntToScalar(1), SkIntToScalar(1));
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000080 create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
81 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +000082 SkAutoTUnref<SkDeferredCanvas> canvas(
83#if SK_DEFERRED_CANVAS_USES_FACTORIES
84 SkDeferredCanvas::Create(&device));
85#else
86 SkNEW_ARGS(SkDeferredCanvas, (&device)));
87#endif
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000088
89 // verify that frame is intially fresh
junov@chromium.org66070a52013-05-28 17:39:08 +000090 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000091 // no clearing op since last call to isFreshFrame -> not fresh
junov@chromium.org66070a52013-05-28 17:39:08 +000092 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000093
94 // Verify that clear triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +000095 canvas->clear(0x00000000);
96 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +000097
98 // Verify that clear with saved state triggers a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +000099 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
100 canvas->clear(0x00000000);
101 canvas->restore();
102 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000103
104 // Verify that clear within a layer does NOT trigger a fresh frame
junov@chromium.org66070a52013-05-28 17:39:08 +0000105 canvas->saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
106 canvas->clear(0x00000000);
107 canvas->restore();
108 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000109
110 // Verify that a clear with clipping triggers a fresh frame
111 // (clear is not affected by clipping)
junov@chromium.org66070a52013-05-28 17:39:08 +0000112 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
113 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
114 canvas->clear(0x00000000);
115 canvas->restore();
116 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000117
118 // Verify that full frame rects with different forms of opaque paint
119 // trigger frames to be marked as fresh
120 {
121 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000122 paint.setStyle(SkPaint::kFill_Style);
123 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000124 canvas->drawRect(fullRect, paint);
125 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000126 }
skia.committer@gmail.com5b6f9162012-10-12 02:01:15 +0000127 {
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000128 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000129 paint.setStyle(SkPaint::kFill_Style);
130 paint.setAlpha(255);
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000131 paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000132 canvas->drawRect(fullRect, paint);
133 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8cef67a2012-10-11 20:19:15 +0000134 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000135 {
136 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000137 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000138 SkBitmap bmp;
139 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
140 bmp.setIsOpaque(true);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000141 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000142 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
143 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000144 canvas->drawRect(fullRect, paint);
145 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000146 }
147
148 // Verify that full frame rects with different forms of non-opaque paint
149 // do not trigger frames to be marked as fresh
150 {
151 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000152 paint.setStyle(SkPaint::kFill_Style);
153 paint.setAlpha(254);
junov@chromium.org66070a52013-05-28 17:39:08 +0000154 canvas->drawRect(fullRect, paint);
155 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000156 }
157 {
158 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000159 paint.setStyle(SkPaint::kFill_Style);
160 // Defining a cone that partially overlaps the canvas
161 const SkPoint pt1 = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
162 const SkScalar r1 = SkIntToScalar(1);
163 const SkPoint pt2 = SkPoint::Make(SkIntToScalar(10), SkIntToScalar(0));
164 const SkScalar r2 = SkIntToScalar(5);
165 const SkColor colors[2] = {SK_ColorWHITE, SK_ColorWHITE};
166 const SkScalar pos[2] = {0, SK_Scalar1};
167 SkShader* shader = SkGradientShader::CreateTwoPointConical(
168 pt1, r1, pt2, r2, colors, pos, 2, SkShader::kClamp_TileMode, NULL);
169 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000170 canvas->drawRect(fullRect, paint);
171 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000172 }
173 {
174 SkPaint paint;
175 paint.setStyle(SkPaint::kFill_Style);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000176 SkBitmap bmp;
177 create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
178 bmp.setIsOpaque(false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000179 SkShader* shader = SkShader::CreateBitmapShader(bmp,
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000180 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
181 paint.setShader(shader)->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000182 canvas->drawRect(fullRect, paint);
183 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000184 }
185
186 // Verify that incomplete coverage does not trigger a fresh frame
187 {
188 SkPaint paint;
189 paint.setStyle(SkPaint::kFill_Style);
190 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000191 canvas->drawRect(partialRect, paint);
192 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000193 }
194
195 // Verify that incomplete coverage due to clipping does not trigger a fresh
196 // frame
197 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000198 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
199 canvas->clipRect(partialRect, SkRegion::kIntersect_Op, false);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000200 SkPaint paint;
201 paint.setStyle(SkPaint::kFill_Style);
202 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000203 canvas->drawRect(fullRect, paint);
204 canvas->restore();
205 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000206 }
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000207 {
junov@chromium.org66070a52013-05-28 17:39:08 +0000208 canvas->save(SkCanvas::kMatrixClip_SaveFlag);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000209 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000210 paint.setStyle(SkPaint::kFill_Style);
211 paint.setAlpha(255);
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000212 SkPath path;
213 path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
junov@chromium.org66070a52013-05-28 17:39:08 +0000214 canvas->clipPath(path, SkRegion::kIntersect_Op, false);
215 canvas->drawRect(fullRect, paint);
216 canvas->restore();
217 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f0ca062012-12-13 16:30:39 +0000218 }
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000219
220 // Verify that stroked rect does not trigger a fresh frame
221 {
222 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000223 paint.setStyle(SkPaint::kStroke_Style);
224 paint.setAlpha(255);
junov@chromium.org66070a52013-05-28 17:39:08 +0000225 canvas->drawRect(fullRect, paint);
226 REPORTER_ASSERT(reporter, !canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000227 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000228
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000229 // Verify kSrcMode triggers a fresh frame even with transparent color
230 {
231 SkPaint paint;
commit-bot@chromium.org3fbab822013-03-20 00:49:57 +0000232 paint.setStyle(SkPaint::kFill_Style);
233 paint.setAlpha(100);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000234 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
junov@chromium.org66070a52013-05-28 17:39:08 +0000235 canvas->drawRect(fullRect, paint);
236 REPORTER_ASSERT(reporter, canvas->isFreshFrame());
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000237 }
238}
239
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000240class MockDevice : public SkDevice {
241public:
242 MockDevice(const SkBitmap& bm) : SkDevice(bm) {
243 fDrawBitmapCallCount = 0;
244 }
245 virtual void drawBitmap(const SkDraw&, const SkBitmap&,
246 const SkIRect*,
247 const SkMatrix&, const SkPaint&) {
248 fDrawBitmapCallCount++;
249 }
250
251 int fDrawBitmapCallCount;
252};
253
254// Verifies that the deferred canvas triggers a flush when its memory
255// limit is exceeded
256static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
257 SkBitmap store;
258 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
259 store.allocPixels();
260 MockDevice mockDevice(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000261 SkAutoTUnref<SkDeferredCanvas> canvas(
262#if SK_DEFERRED_CANVAS_USES_FACTORIES
263 SkDeferredCanvas::Create(&mockDevice));
264#else
265 SkNEW_ARGS(SkDeferredCanvas, (&mockDevice)));
266#endif
267 canvas->setMaxRecordingStorage(160000);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000268
269 SkBitmap sourceImage;
270 // 100 by 100 image, takes 40,000 bytes in memory
271 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
272 sourceImage.allocPixels();
273
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000274 for (int i = 0; i < 5; i++) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000275 sourceImage.notifyPixelsChanged(); // to force re-serialization
junov@chromium.org66070a52013-05-28 17:39:08 +0000276 canvas->drawBitmap(sourceImage, 0, 0, NULL);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000277 }
278
scroggo@google.com15011ee2012-07-26 20:03:32 +0000279 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000280}
281
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000282class NotificationCounter : public SkDeferredCanvas::NotificationClient {
283public:
284 NotificationCounter() {
junov@google.com52a00ca2012-10-01 15:27:14 +0000285 fPrepareForDrawCount = fStorageAllocatedChangedCount =
286 fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000287 }
288
289 virtual void prepareForDraw() SK_OVERRIDE {
290 fPrepareForDrawCount++;
291 }
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000292 virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000293 fStorageAllocatedChangedCount++;
294 }
295 virtual void flushedDrawCommands() SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000296 fFlushedDrawCommandsCount++;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000297 }
junov@google.com52a00ca2012-10-01 15:27:14 +0000298 virtual void skippedPendingDrawCommands() SK_OVERRIDE {
299 fSkippedPendingDrawCommandsCount++;
300 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000301
302 int fPrepareForDrawCount;
303 int fStorageAllocatedChangedCount;
304 int fFlushedDrawCommandsCount;
junov@google.com52a00ca2012-10-01 15:27:14 +0000305 int fSkippedPendingDrawCommandsCount;
robertphillips@google.com59903972013-02-07 21:02:23 +0000306
307private:
308 typedef SkDeferredCanvas::NotificationClient INHERITED;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000309};
310
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000311static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
312 SkBitmap store;
313 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
314 store.allocPixels();
315 SkDevice device(store);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000316 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000317 SkAutoTUnref<SkDeferredCanvas> canvas(
318#if SK_DEFERRED_CANVAS_USES_FACTORIES
319 SkDeferredCanvas::Create(&device));
320#else
321 SkNEW_ARGS(SkDeferredCanvas, (&device)));
322#endif
323 canvas->setNotificationClient(&notificationCounter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000324
325 const int imageCount = 2;
326 SkBitmap sourceImages[imageCount];
327 for (int i = 0; i < imageCount; i++)
328 {
329 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
330 sourceImages[i].allocPixels();
331 }
332
333 size_t bitmapSize = sourceImages[0].getSize();
334
junov@chromium.org66070a52013-05-28 17:39:08 +0000335 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000336 REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000337 // stored bitmap + drawBitmap command
junov@chromium.org66070a52013-05-28 17:39:08 +0000338 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000339
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000340 // verify that nothing can be freed at this point
junov@chromium.org66070a52013-05-28 17:39:08 +0000341 REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000342
343 // verify that flush leaves image in cache
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000344 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
345 REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000346 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000347 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
348 REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000349 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000350
351 // verify that after a flush, cached image can be freed
junov@chromium.org66070a52013-05-28 17:39:08 +0000352 REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000353
354 // Verify that caching works for avoiding multiple copies of the same bitmap
junov@chromium.org66070a52013-05-28 17:39:08 +0000355 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000356 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000357 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000358 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
359 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000360 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000361
362 // Verify partial eviction based on bytesToFree
junov@chromium.org66070a52013-05-28 17:39:08 +0000363 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000364 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000365 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000366 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000367 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
368 size_t bytesFreed = canvas->freeMemoryIfPossible(1);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000369 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000370 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
371 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
372
rmistry@google.comd6176b02012-08-23 18:14:13 +0000373 // Verifiy that partial purge works, image zero is in cache but not reffed by
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000374 // a pending draw, while image 1 is locked-in.
junov@chromium.org66070a52013-05-28 17:39:08 +0000375 canvas->freeMemoryIfPossible(~0U);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000376 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000377 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
378 canvas->flush();
379 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
380 bytesFreed = canvas->freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000381 // only one bitmap should have been freed.
382 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
383 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
384 // Clear for next test
junov@chromium.org66070a52013-05-28 17:39:08 +0000385 canvas->flush();
386 canvas->freeMemoryIfPossible(~0U);
387 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000388
389 // Verify the image cache is sensitive to genID bumps
junov@chromium.org66070a52013-05-28 17:39:08 +0000390 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000391 sourceImages[1].notifyPixelsChanged();
junov@chromium.org66070a52013-05-28 17:39:08 +0000392 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
393 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
junov@google.com52a00ca2012-10-01 15:27:14 +0000394
395 // Verify that nothing in this test caused commands to be skipped
396 REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
397}
398
399static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
400 SkBitmap store;
401 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
402 store.allocPixels();
403 SkDevice device(store);
404 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000405 SkAutoTUnref<SkDeferredCanvas> canvas(
406#if SK_DEFERRED_CANVAS_USES_FACTORIES
407 SkDeferredCanvas::Create(&device));
408#else
409 SkNEW_ARGS(SkDeferredCanvas, (&device)));
410#endif
411 canvas->setNotificationClient(&notificationCounter);
412 canvas->clear(0x0);
junov@google.com52a00ca2012-10-01 15:27:14 +0000413 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
414 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000415 canvas->flush();
junov@google.com52a00ca2012-10-01 15:27:14 +0000416 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
417 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
418
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000419}
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000420
junov@chromium.orgce65f382012-10-17 19:36:09 +0000421static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
422 // This is a regression test for crbug.com/155875
423 // This test covers a code path that inserts bitmaps into the bitmap heap through the
424 // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
425 // the flattening and unflattening of the shader.
426 SkBitmap store;
427 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
428 store.allocPixels();
429 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000430 SkAutoTUnref<SkDeferredCanvas> canvas(
431#if SK_DEFERRED_CANVAS_USES_FACTORIES
432 SkDeferredCanvas::Create(&device));
433#else
434 SkNEW_ARGS(SkDeferredCanvas, (&device)));
435#endif
junov@chromium.orgce65f382012-10-17 19:36:09 +0000436 // test will fail if nbIterations is not in sync with
437 // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
438 const int nbIterations = 5;
439 size_t bytesAllocated = 0;
440 for(int pass = 0; pass < 2; ++pass) {
441 for(int i = 0; i < nbIterations; ++i) {
442 SkPaint paint;
443 SkBitmap paintPattern;
444 paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
445 paintPattern.allocPixels();
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000446 paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
junov@chromium.orgce65f382012-10-17 19:36:09 +0000447 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000448 canvas->drawPaint(paint);
449 canvas->flush();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000450
451 // In the first pass, memory allocation should be monotonically increasing as
452 // the bitmap heap slots fill up. In the second pass memory allocation should be
453 // stable as bitmap heap slots get recycled.
junov@chromium.org66070a52013-05-28 17:39:08 +0000454 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000455 if (pass == 0) {
456 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
457 bytesAllocated = newBytesAllocated;
458 } else {
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000459 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000460 }
461 }
462 }
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000463 // All cached resources should be evictable since last canvas call was flush()
junov@chromium.org66070a52013-05-28 17:39:08 +0000464 canvas->freeMemoryIfPossible(~0U);
465 REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
junov@chromium.orgce65f382012-10-17 19:36:09 +0000466}
467
sugoi@google.com7775fd52012-11-21 15:47:04 +0000468static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
469 SkBitmap store;
470 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
471 store.allocPixels();
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000472
sugoi@google.com7775fd52012-11-21 15:47:04 +0000473 SkBitmap sourceImage;
474 // 100 by 100 image, takes 40,000 bytes in memory
475 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
476 sourceImage.allocPixels();
477
478 // 1 under : should not store the image
479 {
480 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000481 SkAutoTUnref<SkDeferredCanvas> canvas(
482#if SK_DEFERRED_CANVAS_USES_FACTORIES
483 SkDeferredCanvas::Create(&device));
484#else
485 SkNEW_ARGS(SkDeferredCanvas, (&device)));
486#endif
487 canvas->setBitmapSizeThreshold(39999);
488 canvas->drawBitmap(sourceImage, 0, 0, NULL);
489 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000490 REPORTER_ASSERT(reporter, newBytesAllocated == 0);
491 }
492
493 // exact value : should store the image
494 {
495 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000496 SkAutoTUnref<SkDeferredCanvas> canvas(
497#if SK_DEFERRED_CANVAS_USES_FACTORIES
498 SkDeferredCanvas::Create(&device));
499#else
500 SkNEW_ARGS(SkDeferredCanvas, (&device)));
501#endif
502 canvas->setBitmapSizeThreshold(40000);
503 canvas->drawBitmap(sourceImage, 0, 0, NULL);
504 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000505 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
506 }
507
508 // 1 over : should still store the image
509 {
510 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000511 SkAutoTUnref<SkDeferredCanvas> canvas(
512#if SK_DEFERRED_CANVAS_USES_FACTORIES
513 SkDeferredCanvas::Create(&device));
514#else
515 SkNEW_ARGS(SkDeferredCanvas, (&device)));
516#endif
517 canvas->setBitmapSizeThreshold(40001);
518 canvas->drawBitmap(sourceImage, 0, 0, NULL);
519 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000520 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
521 }
522}
523
junov@chromium.org67d74222013-04-12 13:33:01 +0000524
525typedef void* PixelPtr;
526// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
527// buffer. Used to test pointer equality do determine whether a surface points
528// to the same pixel data storage as before.
junov@chromium.org3c5ec8d2013-04-12 13:34:47 +0000529static PixelPtr getSurfacePixelPtr(SkSurface* surface, bool useGpu) {
junov@chromium.org67d74222013-04-12 13:33:01 +0000530 return useGpu ? surface->getCanvas()->getDevice()->accessBitmap(false).getTexture() :
531 surface->getCanvas()->getDevice()->accessBitmap(false).getPixels();
532}
533
534static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
535 SkImage::Info imageSpec = {
536 10, // width
537 10, // height
538 SkImage::kPMColor_ColorType,
539 SkImage::kPremul_AlphaType
540 };
541 SkSurface* surface;
542 bool useGpu = NULL != factory;
543#if SK_SUPPORT_GPU
544 if (useGpu) {
545 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
546 surface = SkSurface::NewRenderTarget(context, imageSpec);
547 } else {
548 surface = SkSurface::NewRaster(imageSpec);
549 }
550#else
551 SkASSERT(!useGpu);
552 surface = SkSurface::NewRaster(imageSpec);
553#endif
554 SkASSERT(NULL != surface);
555 SkAutoTUnref<SkSurface> aur(surface);
junov@chromium.org66070a52013-05-28 17:39:08 +0000556 SkAutoTUnref<SkDeferredCanvas> canvas(
557#if SK_DEFERRED_CANVAS_USES_FACTORIES
558 SkDeferredCanvas::Create(surface));
559#else
560 SkNEW_ARGS(SkDeferredCanvas, (surface)));
561#endif
junov@chromium.org67d74222013-04-12 13:33:01 +0000562
junov@chromium.org66070a52013-05-28 17:39:08 +0000563 SkImage* image1 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000564 SkAutoTUnref<SkImage> aur_i1(image1);
565 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
566 // The following clear would normally trigger a copy on write, but
567 // it won't because rendering is deferred.
junov@chromium.org66070a52013-05-28 17:39:08 +0000568 canvas->clear(SK_ColorBLACK);
junov@chromium.org67d74222013-04-12 13:33:01 +0000569 // Obtaining a snapshot directly from the surface (as opposed to the
570 // SkDeferredCanvas) will not trigger a flush of deferred draw operations
571 // and will therefore return the same image as the previous snapshot.
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000572 SkImage* image2 = surface->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000573 SkAutoTUnref<SkImage> aur_i2(image2);
574 // Images identical because of deferral
575 REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
576 // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
577 // Because there is a pending clear, this will generate a different image.
junov@chromium.org66070a52013-05-28 17:39:08 +0000578 SkImage* image3 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000579 SkAutoTUnref<SkImage> aur_i3(image3);
580 REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
581 // Verify that backing store is now a different buffer because of copy on
582 // write
583 PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu);
584 REPORTER_ASSERT(reporter, pixels1 != pixels2);
junov@chromium.org9becf002013-04-15 18:15:23 +0000585 // Verify copy-on write with a draw operation that gets deferred by
586 // the in order draw buffer.
587 SkPaint paint;
junov@chromium.org66070a52013-05-28 17:39:08 +0000588 canvas->drawPaint(paint);
589 SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
junov@chromium.org9becf002013-04-15 18:15:23 +0000590 SkAutoTUnref<SkImage> aur_i4(image4);
591 REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
junov@chromium.org67d74222013-04-12 13:33:01 +0000592 PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org9becf002013-04-15 18:15:23 +0000593 REPORTER_ASSERT(reporter, pixels2 != pixels3);
junov@chromium.org67d74222013-04-12 13:33:01 +0000594 // Verify that a direct canvas flush with a pending draw does not trigger
595 // a copy on write when the surface is not sharing its buffer with an
596 // SkImage.
junov@chromium.org66070a52013-05-28 17:39:08 +0000597 canvas->clear(SK_ColorWHITE);
598 canvas->flush();
junov@chromium.org67d74222013-04-12 13:33:01 +0000599 PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000600 canvas->drawPaint(paint);
601 canvas->flush();
junov@chromium.org9becf002013-04-15 18:15:23 +0000602 PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu);
603 REPORTER_ASSERT(reporter, pixels4 == pixels5);
junov@chromium.org67d74222013-04-12 13:33:01 +0000604}
605
junov@chromium.org7070f762013-05-24 17:13:00 +0000606static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
607 SkImage::Info imageSpec = {
608 10, // width
609 10, // height
610 SkImage::kPMColor_ColorType,
611 SkImage::kPremul_AlphaType
612 };
613 SkSurface* surface;
614 SkSurface* alternateSurface;
615 bool useGpu = NULL != factory;
616#if SK_SUPPORT_GPU
617 if (useGpu) {
618 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
619 surface = SkSurface::NewRenderTarget(context, imageSpec);
620 alternateSurface = SkSurface::NewRenderTarget(context, imageSpec);
621 } else {
622 surface = SkSurface::NewRaster(imageSpec);
623 alternateSurface = SkSurface::NewRaster(imageSpec);
624 }
625#else
626 SkASSERT(!useGpu);
627 surface = SkSurface::NewRaster(imageSpec);
628 alternateSurface = SkSurface::NewRaster(imageSpec);
629#endif
630 SkASSERT(NULL != surface);
631 SkASSERT(NULL != alternateSurface);
632 SkAutoTUnref<SkSurface> aur1(surface);
633 SkAutoTUnref<SkSurface> aur2(alternateSurface);
634 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
635 PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000636 SkAutoTUnref<SkDeferredCanvas> canvas(
637#if SK_DEFERRED_CANVAS_USES_FACTORIES
638 SkDeferredCanvas::Create(surface));
639#else
640 SkNEW_ARGS(SkDeferredCanvas, (surface)));
641#endif
642 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
643 canvas->setSurface(alternateSurface);
644 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
junov@chromium.org7070f762013-05-24 17:13:00 +0000645 REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
646 // Verify that none of the above operations triggered a surface copy on write.
647 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
648 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2);
649 // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
junov@chromium.org66070a52013-05-28 17:39:08 +0000650 canvas->clear(SK_ColorWHITE);
651 canvas->flush();
junov@chromium.org7070f762013-05-24 17:13:00 +0000652 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
653 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2);
654}
655
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000656static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
657 SkBitmap store;
658 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
659 store.allocPixels();
660 SkDevice device(store);
661 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000662 SkAutoTUnref<SkDeferredCanvas> canvas(
663#if SK_DEFERRED_CANVAS_USES_FACTORIES
664 SkDeferredCanvas::Create(&device));
665#else
666 SkNEW_ARGS(SkDeferredCanvas, (&device)));
667#endif
668 canvas->setNotificationClient(&notificationCounter);
669 SkAutoTUnref<SkDevice> secondaryDevice(canvas->createCompatibleDevice(
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000670 SkBitmap::kARGB_8888_Config, 10, 10, device.isOpaque()));
671 SkCanvas secondaryCanvas(secondaryDevice.get());
672 SkRect rect = SkRect::MakeWH(5, 5);
673 SkPaint paint;
674 // After spawning a compatible canvas:
675 // 1) Verify that secondary canvas is usable and does not report to the notification client.
676 secondaryCanvas.drawRect(rect, paint);
677 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
678 // 2) Verify that original canvas is usable and still reports to the notification client.
junov@chromium.org66070a52013-05-28 17:39:08 +0000679 canvas->drawRect(rect, paint);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000680 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
681}
682
junov@chromium.org67d74222013-04-12 13:33:01 +0000683static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* factory) {
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000684 TestDeferredCanvasBitmapAccess(reporter);
685 TestDeferredCanvasFlush(reporter);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000686 TestDeferredCanvasFreshFrame(reporter);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000687 TestDeferredCanvasMemoryLimit(reporter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000688 TestDeferredCanvasBitmapCaching(reporter);
junov@google.com52a00ca2012-10-01 15:27:14 +0000689 TestDeferredCanvasSkip(reporter);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000690 TestDeferredCanvasBitmapShaderNoLeak(reporter);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000691 TestDeferredCanvasBitmapSizeThreshold(reporter);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000692 TestDeferredCanvasCreateCompatibleDevice(reporter);
junov@chromium.org67d74222013-04-12 13:33:01 +0000693 TestDeferredCanvasSurface(reporter, NULL);
junov@chromium.org7070f762013-05-24 17:13:00 +0000694 TestDeferredCanvasSetSurface(reporter, NULL);
junov@chromium.org67d74222013-04-12 13:33:01 +0000695 if (NULL != factory) {
696 TestDeferredCanvasSurface(reporter, factory);
junov@chromium.org7070f762013-05-24 17:13:00 +0000697 TestDeferredCanvasSetSurface(reporter, factory);
junov@chromium.org67d74222013-04-12 13:33:01 +0000698 }
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000699}
700
701#include "TestClassDef.h"
junov@chromium.org67d74222013-04-12 13:33:01 +0000702DEFINE_GPUTESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas)