blob: 1289c036f631be524cbc075232684d3caac4b6ea [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&,
commit-bot@chromium.org3e2ea252013-07-23 11:28:45 +0000246 const SkMatrix&, const SkPaint&) SK_OVERRIDE {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000247 fDrawBitmapCallCount++;
248 }
249
250 int fDrawBitmapCallCount;
251};
252
253// Verifies that the deferred canvas triggers a flush when its memory
254// limit is exceeded
255static void TestDeferredCanvasMemoryLimit(skiatest::Reporter* reporter) {
256 SkBitmap store;
257 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
258 store.allocPixels();
259 MockDevice mockDevice(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000260 SkAutoTUnref<SkDeferredCanvas> canvas(
261#if SK_DEFERRED_CANVAS_USES_FACTORIES
262 SkDeferredCanvas::Create(&mockDevice));
263#else
264 SkNEW_ARGS(SkDeferredCanvas, (&mockDevice)));
265#endif
266 canvas->setMaxRecordingStorage(160000);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000267
268 SkBitmap sourceImage;
269 // 100 by 100 image, takes 40,000 bytes in memory
270 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
271 sourceImage.allocPixels();
272
junov@chromium.orgb10a6bd2012-07-25 17:27:13 +0000273 for (int i = 0; i < 5; i++) {
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000274 sourceImage.notifyPixelsChanged(); // to force re-serialization
junov@chromium.org66070a52013-05-28 17:39:08 +0000275 canvas->drawBitmap(sourceImage, 0, 0, NULL);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000276 }
277
scroggo@google.com15011ee2012-07-26 20:03:32 +0000278 REPORTER_ASSERT(reporter, mockDevice.fDrawBitmapCallCount == 4);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000279}
280
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000281class NotificationCounter : public SkDeferredCanvas::NotificationClient {
282public:
283 NotificationCounter() {
junov@google.com52a00ca2012-10-01 15:27:14 +0000284 fPrepareForDrawCount = fStorageAllocatedChangedCount =
285 fFlushedDrawCommandsCount = fSkippedPendingDrawCommandsCount = 0;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000286 }
287
288 virtual void prepareForDraw() SK_OVERRIDE {
289 fPrepareForDrawCount++;
290 }
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000291 virtual void storageAllocatedForRecordingChanged(size_t) SK_OVERRIDE {
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000292 fStorageAllocatedChangedCount++;
293 }
294 virtual void flushedDrawCommands() SK_OVERRIDE {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000295 fFlushedDrawCommandsCount++;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000296 }
junov@google.com52a00ca2012-10-01 15:27:14 +0000297 virtual void skippedPendingDrawCommands() SK_OVERRIDE {
298 fSkippedPendingDrawCommandsCount++;
299 }
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000300
301 int fPrepareForDrawCount;
302 int fStorageAllocatedChangedCount;
303 int fFlushedDrawCommandsCount;
junov@google.com52a00ca2012-10-01 15:27:14 +0000304 int fSkippedPendingDrawCommandsCount;
robertphillips@google.com59903972013-02-07 21:02:23 +0000305
306private:
307 typedef SkDeferredCanvas::NotificationClient INHERITED;
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000308};
309
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000310static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
311 SkBitmap store;
312 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
313 store.allocPixels();
314 SkDevice device(store);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000315 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000316 SkAutoTUnref<SkDeferredCanvas> canvas(
317#if SK_DEFERRED_CANVAS_USES_FACTORIES
318 SkDeferredCanvas::Create(&device));
319#else
320 SkNEW_ARGS(SkDeferredCanvas, (&device)));
321#endif
322 canvas->setNotificationClient(&notificationCounter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000323
324 const int imageCount = 2;
325 SkBitmap sourceImages[imageCount];
326 for (int i = 0; i < imageCount; i++)
327 {
328 sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
329 sourceImages[i].allocPixels();
330 }
331
332 size_t bitmapSize = sourceImages[0].getSize();
333
junov@chromium.org66070a52013-05-28 17:39:08 +0000334 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000335 REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000336 // stored bitmap + drawBitmap command
junov@chromium.org66070a52013-05-28 17:39:08 +0000337 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > bitmapSize);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000338
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000339 // verify that nothing can be freed at this point
junov@chromium.org66070a52013-05-28 17:39:08 +0000340 REPORTER_ASSERT(reporter, 0 == canvas->freeMemoryIfPossible(~0U));
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000341
342 // verify that flush leaves image in cache
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000343 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
344 REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000345 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000346 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
347 REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000348 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000349
350 // verify that after a flush, cached image can be freed
junov@chromium.org66070a52013-05-28 17:39:08 +0000351 REPORTER_ASSERT(reporter, canvas->freeMemoryIfPossible(~0U) >= bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000352
353 // Verify that caching works for avoiding multiple copies of the same bitmap
junov@chromium.org66070a52013-05-28 17:39:08 +0000354 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000355 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000356 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000357 REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
358 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000359 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < 2 * bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000360
361 // Verify partial eviction based on bytesToFree
junov@chromium.org66070a52013-05-28 17:39:08 +0000362 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000363 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000364 canvas->flush();
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000365 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000366 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2 * bitmapSize);
367 size_t bytesFreed = canvas->freeMemoryIfPossible(1);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000368 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000369 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
370 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
371
rmistry@google.comd6176b02012-08-23 18:14:13 +0000372 // Verifiy that partial purge works, image zero is in cache but not reffed by
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000373 // a pending draw, while image 1 is locked-in.
junov@chromium.org66070a52013-05-28 17:39:08 +0000374 canvas->freeMemoryIfPossible(~0U);
junov@chromium.org9ed02b92012-08-14 13:36:26 +0000375 REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000376 canvas->drawBitmap(sourceImages[0], 0, 0, NULL);
377 canvas->flush();
378 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
379 bytesFreed = canvas->freeMemoryIfPossible(~0U);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000380 // only one bitmap should have been freed.
381 REPORTER_ASSERT(reporter, bytesFreed >= bitmapSize);
382 REPORTER_ASSERT(reporter, bytesFreed < 2*bitmapSize);
383 // Clear for next test
junov@chromium.org66070a52013-05-28 17:39:08 +0000384 canvas->flush();
385 canvas->freeMemoryIfPossible(~0U);
386 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() < bitmapSize);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000387
388 // Verify the image cache is sensitive to genID bumps
junov@chromium.org66070a52013-05-28 17:39:08 +0000389 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000390 sourceImages[1].notifyPixelsChanged();
junov@chromium.org66070a52013-05-28 17:39:08 +0000391 canvas->drawBitmap(sourceImages[1], 0, 0, NULL);
392 REPORTER_ASSERT(reporter, canvas->storageAllocatedForRecording() > 2*bitmapSize);
junov@google.com52a00ca2012-10-01 15:27:14 +0000393
394 // Verify that nothing in this test caused commands to be skipped
395 REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
396}
397
398static void TestDeferredCanvasSkip(skiatest::Reporter* reporter) {
399 SkBitmap store;
400 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
401 store.allocPixels();
402 SkDevice device(store);
403 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000404 SkAutoTUnref<SkDeferredCanvas> canvas(
405#if SK_DEFERRED_CANVAS_USES_FACTORIES
406 SkDeferredCanvas::Create(&device));
407#else
408 SkNEW_ARGS(SkDeferredCanvas, (&device)));
409#endif
410 canvas->setNotificationClient(&notificationCounter);
411 canvas->clear(0x0);
junov@google.com52a00ca2012-10-01 15:27:14 +0000412 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
413 REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
junov@chromium.org66070a52013-05-28 17:39:08 +0000414 canvas->flush();
junov@google.com52a00ca2012-10-01 15:27:14 +0000415 REPORTER_ASSERT(reporter, 1 == notificationCounter.fSkippedPendingDrawCommandsCount);
416 REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
417
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000418}
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000419
junov@chromium.orgce65f382012-10-17 19:36:09 +0000420static void TestDeferredCanvasBitmapShaderNoLeak(skiatest::Reporter* reporter) {
421 // This is a regression test for crbug.com/155875
422 // This test covers a code path that inserts bitmaps into the bitmap heap through the
423 // flattening of SkBitmapProcShaders. The refcount in the bitmap heap is maintained through
424 // the flattening and unflattening of the shader.
425 SkBitmap store;
426 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
427 store.allocPixels();
428 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000429 SkAutoTUnref<SkDeferredCanvas> canvas(
430#if SK_DEFERRED_CANVAS_USES_FACTORIES
431 SkDeferredCanvas::Create(&device));
432#else
433 SkNEW_ARGS(SkDeferredCanvas, (&device)));
434#endif
junov@chromium.orgce65f382012-10-17 19:36:09 +0000435 // test will fail if nbIterations is not in sync with
436 // BITMAPS_TO_KEEP in SkGPipeWrite.cpp
437 const int nbIterations = 5;
438 size_t bytesAllocated = 0;
439 for(int pass = 0; pass < 2; ++pass) {
440 for(int i = 0; i < nbIterations; ++i) {
441 SkPaint paint;
442 SkBitmap paintPattern;
443 paintPattern.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
444 paintPattern.allocPixels();
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000445 paint.setShader(SkNEW_ARGS(SkBitmapProcShader,
junov@chromium.orgce65f382012-10-17 19:36:09 +0000446 (paintPattern, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)))->unref();
junov@chromium.org66070a52013-05-28 17:39:08 +0000447 canvas->drawPaint(paint);
448 canvas->flush();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000449
450 // In the first pass, memory allocation should be monotonically increasing as
451 // the bitmap heap slots fill up. In the second pass memory allocation should be
452 // stable as bitmap heap slots get recycled.
junov@chromium.org66070a52013-05-28 17:39:08 +0000453 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
junov@chromium.orgce65f382012-10-17 19:36:09 +0000454 if (pass == 0) {
455 REPORTER_ASSERT(reporter, newBytesAllocated > bytesAllocated);
456 bytesAllocated = newBytesAllocated;
457 } else {
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000458 REPORTER_ASSERT(reporter, newBytesAllocated == bytesAllocated);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000459 }
460 }
461 }
skia.committer@gmail.com989a95e2012-10-18 02:01:23 +0000462 // All cached resources should be evictable since last canvas call was flush()
junov@chromium.org66070a52013-05-28 17:39:08 +0000463 canvas->freeMemoryIfPossible(~0U);
464 REPORTER_ASSERT(reporter, 0 == canvas->storageAllocatedForRecording());
junov@chromium.orgce65f382012-10-17 19:36:09 +0000465}
466
sugoi@google.com7775fd52012-11-21 15:47:04 +0000467static void TestDeferredCanvasBitmapSizeThreshold(skiatest::Reporter* reporter) {
468 SkBitmap store;
469 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
470 store.allocPixels();
skia.committer@gmail.com1c9c0d32012-11-22 02:02:41 +0000471
sugoi@google.com7775fd52012-11-21 15:47:04 +0000472 SkBitmap sourceImage;
473 // 100 by 100 image, takes 40,000 bytes in memory
474 sourceImage.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
475 sourceImage.allocPixels();
476
477 // 1 under : should not store the image
478 {
479 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000480 SkAutoTUnref<SkDeferredCanvas> canvas(
481#if SK_DEFERRED_CANVAS_USES_FACTORIES
482 SkDeferredCanvas::Create(&device));
483#else
484 SkNEW_ARGS(SkDeferredCanvas, (&device)));
485#endif
486 canvas->setBitmapSizeThreshold(39999);
487 canvas->drawBitmap(sourceImage, 0, 0, NULL);
488 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000489 REPORTER_ASSERT(reporter, newBytesAllocated == 0);
490 }
491
492 // exact value : should store the image
493 {
494 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000495 SkAutoTUnref<SkDeferredCanvas> canvas(
496#if SK_DEFERRED_CANVAS_USES_FACTORIES
497 SkDeferredCanvas::Create(&device));
498#else
499 SkNEW_ARGS(SkDeferredCanvas, (&device)));
500#endif
501 canvas->setBitmapSizeThreshold(40000);
502 canvas->drawBitmap(sourceImage, 0, 0, NULL);
503 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000504 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
505 }
506
507 // 1 over : should still store the image
508 {
509 SkDevice device(store);
junov@chromium.org66070a52013-05-28 17:39:08 +0000510 SkAutoTUnref<SkDeferredCanvas> canvas(
511#if SK_DEFERRED_CANVAS_USES_FACTORIES
512 SkDeferredCanvas::Create(&device));
513#else
514 SkNEW_ARGS(SkDeferredCanvas, (&device)));
515#endif
516 canvas->setBitmapSizeThreshold(40001);
517 canvas->drawBitmap(sourceImage, 0, 0, NULL);
518 size_t newBytesAllocated = canvas->storageAllocatedForRecording();
sugoi@google.com7775fd52012-11-21 15:47:04 +0000519 REPORTER_ASSERT(reporter, newBytesAllocated > 0);
520 }
521}
522
junov@chromium.org67d74222013-04-12 13:33:01 +0000523
524typedef void* PixelPtr;
525// Returns an opaque pointer which, either points to a GrTexture or RAM pixel
526// buffer. Used to test pointer equality do determine whether a surface points
527// to the same pixel data storage as before.
junov@chromium.org3c5ec8d2013-04-12 13:34:47 +0000528static PixelPtr getSurfacePixelPtr(SkSurface* surface, bool useGpu) {
junov@chromium.org67d74222013-04-12 13:33:01 +0000529 return useGpu ? surface->getCanvas()->getDevice()->accessBitmap(false).getTexture() :
530 surface->getCanvas()->getDevice()->accessBitmap(false).getPixels();
531}
532
533static void TestDeferredCanvasSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
534 SkImage::Info imageSpec = {
535 10, // width
536 10, // height
537 SkImage::kPMColor_ColorType,
538 SkImage::kPremul_AlphaType
539 };
540 SkSurface* surface;
541 bool useGpu = NULL != factory;
542#if SK_SUPPORT_GPU
543 if (useGpu) {
544 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
545 surface = SkSurface::NewRenderTarget(context, imageSpec);
546 } else {
547 surface = SkSurface::NewRaster(imageSpec);
548 }
549#else
550 SkASSERT(!useGpu);
551 surface = SkSurface::NewRaster(imageSpec);
552#endif
553 SkASSERT(NULL != surface);
554 SkAutoTUnref<SkSurface> aur(surface);
junov@chromium.org66070a52013-05-28 17:39:08 +0000555 SkAutoTUnref<SkDeferredCanvas> canvas(
556#if SK_DEFERRED_CANVAS_USES_FACTORIES
557 SkDeferredCanvas::Create(surface));
558#else
559 SkNEW_ARGS(SkDeferredCanvas, (surface)));
560#endif
junov@chromium.org67d74222013-04-12 13:33:01 +0000561
junov@chromium.org66070a52013-05-28 17:39:08 +0000562 SkImage* image1 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000563 SkAutoTUnref<SkImage> aur_i1(image1);
564 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
565 // The following clear would normally trigger a copy on write, but
566 // it won't because rendering is deferred.
junov@chromium.org66070a52013-05-28 17:39:08 +0000567 canvas->clear(SK_ColorBLACK);
junov@chromium.org67d74222013-04-12 13:33:01 +0000568 // Obtaining a snapshot directly from the surface (as opposed to the
569 // SkDeferredCanvas) will not trigger a flush of deferred draw operations
570 // and will therefore return the same image as the previous snapshot.
junov@chromium.org5ee449a2013-04-12 20:20:50 +0000571 SkImage* image2 = surface->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000572 SkAutoTUnref<SkImage> aur_i2(image2);
573 // Images identical because of deferral
574 REPORTER_ASSERT(reporter, image1->uniqueID() == image2->uniqueID());
575 // Now we obtain a snpshot via the deferred canvas, which triggers a flush.
576 // Because there is a pending clear, this will generate a different image.
junov@chromium.org66070a52013-05-28 17:39:08 +0000577 SkImage* image3 = canvas->newImageSnapshot();
junov@chromium.org67d74222013-04-12 13:33:01 +0000578 SkAutoTUnref<SkImage> aur_i3(image3);
579 REPORTER_ASSERT(reporter, image1->uniqueID() != image3->uniqueID());
580 // Verify that backing store is now a different buffer because of copy on
581 // write
582 PixelPtr pixels2 = getSurfacePixelPtr(surface, useGpu);
583 REPORTER_ASSERT(reporter, pixels1 != pixels2);
junov@chromium.org9becf002013-04-15 18:15:23 +0000584 // Verify copy-on write with a draw operation that gets deferred by
585 // the in order draw buffer.
586 SkPaint paint;
junov@chromium.org66070a52013-05-28 17:39:08 +0000587 canvas->drawPaint(paint);
588 SkImage* image4 = canvas->newImageSnapshot(); // implicit flush
junov@chromium.org9becf002013-04-15 18:15:23 +0000589 SkAutoTUnref<SkImage> aur_i4(image4);
590 REPORTER_ASSERT(reporter, image4->uniqueID() != image3->uniqueID());
junov@chromium.org67d74222013-04-12 13:33:01 +0000591 PixelPtr pixels3 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org9becf002013-04-15 18:15:23 +0000592 REPORTER_ASSERT(reporter, pixels2 != pixels3);
junov@chromium.org67d74222013-04-12 13:33:01 +0000593 // Verify that a direct canvas flush with a pending draw does not trigger
594 // a copy on write when the surface is not sharing its buffer with an
595 // SkImage.
junov@chromium.org66070a52013-05-28 17:39:08 +0000596 canvas->clear(SK_ColorWHITE);
597 canvas->flush();
junov@chromium.org67d74222013-04-12 13:33:01 +0000598 PixelPtr pixels4 = getSurfacePixelPtr(surface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000599 canvas->drawPaint(paint);
600 canvas->flush();
junov@chromium.org9becf002013-04-15 18:15:23 +0000601 PixelPtr pixels5 = getSurfacePixelPtr(surface, useGpu);
602 REPORTER_ASSERT(reporter, pixels4 == pixels5);
junov@chromium.org67d74222013-04-12 13:33:01 +0000603}
604
junov@chromium.org7070f762013-05-24 17:13:00 +0000605static void TestDeferredCanvasSetSurface(skiatest::Reporter* reporter, GrContextFactory* factory) {
606 SkImage::Info imageSpec = {
607 10, // width
608 10, // height
609 SkImage::kPMColor_ColorType,
610 SkImage::kPremul_AlphaType
611 };
612 SkSurface* surface;
613 SkSurface* alternateSurface;
614 bool useGpu = NULL != factory;
615#if SK_SUPPORT_GPU
616 if (useGpu) {
617 GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
618 surface = SkSurface::NewRenderTarget(context, imageSpec);
619 alternateSurface = SkSurface::NewRenderTarget(context, imageSpec);
620 } else {
621 surface = SkSurface::NewRaster(imageSpec);
622 alternateSurface = SkSurface::NewRaster(imageSpec);
623 }
624#else
625 SkASSERT(!useGpu);
626 surface = SkSurface::NewRaster(imageSpec);
627 alternateSurface = SkSurface::NewRaster(imageSpec);
628#endif
629 SkASSERT(NULL != surface);
630 SkASSERT(NULL != alternateSurface);
631 SkAutoTUnref<SkSurface> aur1(surface);
632 SkAutoTUnref<SkSurface> aur2(alternateSurface);
633 PixelPtr pixels1 = getSurfacePixelPtr(surface, useGpu);
634 PixelPtr pixels2 = getSurfacePixelPtr(alternateSurface, useGpu);
junov@chromium.org66070a52013-05-28 17:39:08 +0000635 SkAutoTUnref<SkDeferredCanvas> canvas(
636#if SK_DEFERRED_CANVAS_USES_FACTORIES
637 SkDeferredCanvas::Create(surface));
638#else
639 SkNEW_ARGS(SkDeferredCanvas, (surface)));
640#endif
641 SkAutoTUnref<SkImage> image1(canvas->newImageSnapshot());
642 canvas->setSurface(alternateSurface);
643 SkAutoTUnref<SkImage> image2(canvas->newImageSnapshot());
junov@chromium.org7070f762013-05-24 17:13:00 +0000644 REPORTER_ASSERT(reporter, image1->uniqueID() != image2->uniqueID());
645 // Verify that none of the above operations triggered a surface copy on write.
646 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
647 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) == pixels2);
648 // Verify that a flushed draw command will trigger a copy on write on alternateSurface.
junov@chromium.org66070a52013-05-28 17:39:08 +0000649 canvas->clear(SK_ColorWHITE);
650 canvas->flush();
junov@chromium.org7070f762013-05-24 17:13:00 +0000651 REPORTER_ASSERT(reporter, getSurfacePixelPtr(surface, useGpu) == pixels1);
652 REPORTER_ASSERT(reporter, getSurfacePixelPtr(alternateSurface, useGpu) != pixels2);
653}
654
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000655static void TestDeferredCanvasCreateCompatibleDevice(skiatest::Reporter* reporter) {
656 SkBitmap store;
657 store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
658 store.allocPixels();
659 SkDevice device(store);
660 NotificationCounter notificationCounter;
junov@chromium.org66070a52013-05-28 17:39:08 +0000661 SkAutoTUnref<SkDeferredCanvas> canvas(
662#if SK_DEFERRED_CANVAS_USES_FACTORIES
663 SkDeferredCanvas::Create(&device));
664#else
665 SkNEW_ARGS(SkDeferredCanvas, (&device)));
666#endif
667 canvas->setNotificationClient(&notificationCounter);
668 SkAutoTUnref<SkDevice> secondaryDevice(canvas->createCompatibleDevice(
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000669 SkBitmap::kARGB_8888_Config, 10, 10, device.isOpaque()));
670 SkCanvas secondaryCanvas(secondaryDevice.get());
671 SkRect rect = SkRect::MakeWH(5, 5);
672 SkPaint paint;
673 // After spawning a compatible canvas:
674 // 1) Verify that secondary canvas is usable and does not report to the notification client.
675 secondaryCanvas.drawRect(rect, paint);
676 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 0);
677 // 2) Verify that original canvas is usable and still reports to the notification client.
junov@chromium.org66070a52013-05-28 17:39:08 +0000678 canvas->drawRect(rect, paint);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000679 REPORTER_ASSERT(reporter, notificationCounter.fStorageAllocatedChangedCount == 1);
680}
681
junov@chromium.org67d74222013-04-12 13:33:01 +0000682static void TestDeferredCanvas(skiatest::Reporter* reporter, GrContextFactory* factory) {
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000683 TestDeferredCanvasBitmapAccess(reporter);
684 TestDeferredCanvasFlush(reporter);
junov@chromium.org8f9ecbd2012-02-13 21:53:45 +0000685 TestDeferredCanvasFreshFrame(reporter);
junov@chromium.orgbfeddae2012-07-23 13:35:14 +0000686 TestDeferredCanvasMemoryLimit(reporter);
junov@chromium.org2e14ba82012-08-07 14:26:57 +0000687 TestDeferredCanvasBitmapCaching(reporter);
junov@google.com52a00ca2012-10-01 15:27:14 +0000688 TestDeferredCanvasSkip(reporter);
junov@chromium.orgce65f382012-10-17 19:36:09 +0000689 TestDeferredCanvasBitmapShaderNoLeak(reporter);
sugoi@google.com7775fd52012-11-21 15:47:04 +0000690 TestDeferredCanvasBitmapSizeThreshold(reporter);
junov@chromium.orgb1c725a2013-05-21 20:16:17 +0000691 TestDeferredCanvasCreateCompatibleDevice(reporter);
junov@chromium.org67d74222013-04-12 13:33:01 +0000692 TestDeferredCanvasSurface(reporter, NULL);
junov@chromium.org7070f762013-05-24 17:13:00 +0000693 TestDeferredCanvasSetSurface(reporter, NULL);
junov@chromium.org67d74222013-04-12 13:33:01 +0000694 if (NULL != factory) {
695 TestDeferredCanvasSurface(reporter, factory);
junov@chromium.org7070f762013-05-24 17:13:00 +0000696 TestDeferredCanvasSetSurface(reporter, factory);
junov@chromium.org67d74222013-04-12 13:33:01 +0000697 }
junov@chromium.org1f9767c2012-02-07 16:27:57 +0000698}
699
700#include "TestClassDef.h"
junov@chromium.org67d74222013-04-12 13:33:01 +0000701DEFINE_GPUTESTCLASS("DeferredCanvas", TestDeferredCanvasClass, TestDeferredCanvas)