blob: b2cc8d8fb4b4c7cdfe4bdcea5a76f6c52f018d0a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
bsalomon@google.com971d0c82011-08-19 17:22:05 +00007
epoger@google.com57f7abc2012-11-13 03:41:55 +00008/*
9 * Code for the "gm" (Golden Master) rendering comparison tool.
10 *
11 * If you make changes to this, re-run the self-tests at gm/tests/run.sh
12 * to make sure they still pass... you may need to change the expected
13 * results of the self-test.
14 */
15
bungeman@google.comb29c8832011-10-10 13:19:10 +000016#include "gm.h"
epoger@google.com7bc13a62012-02-14 14:53:59 +000017#include "system_preferences.h"
reed@android.comb9b9a182009-07-08 02:54:47 +000018#include "SkColorPriv.h"
reed@google.com8a85d0c2011-06-24 19:12:12 +000019#include "SkData.h"
junov@google.com4370aed2012-01-18 16:21:08 +000020#include "SkDeferredCanvas.h"
bsalomon@google.com971d0c82011-08-19 17:22:05 +000021#include "SkDevice.h"
epoger@google.comde961632012-10-26 18:56:36 +000022#include "SkDrawFilter.h"
scroggo@google.com5af9b202012-06-04 17:17:36 +000023#include "SkGPipe.h"
reed@android.com8015dd82009-06-21 00:49:18 +000024#include "SkGraphics.h"
25#include "SkImageDecoder.h"
26#include "SkImageEncoder.h"
epoger@google.come8ebeb12012-10-29 16:42:11 +000027#include "SkOSFile.h"
tomhudson@google.com9875dd12011-04-25 15:49:53 +000028#include "SkPicture.h"
robertphillips@google.com977b9c82012-06-05 19:35:09 +000029#include "SkRefCnt.h"
scroggo@google.com72c96722012-06-06 21:07:10 +000030#include "SkStream.h"
bsalomon@google.com2a48c3a2012-08-03 14:54:45 +000031#include "SkTArray.h"
junov@chromium.org3cb834b2012-12-13 16:39:53 +000032#include "SkTileGridPicture.h"
scroggo@google.com72c96722012-06-06 21:07:10 +000033#include "SamplePipeControllers.h"
reed@google.com07700442010-12-20 19:46:07 +000034
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000035#if SK_SUPPORT_GPU
36#include "GrContextFactory.h"
37#include "GrRenderTarget.h"
38#include "SkGpuDevice.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000039typedef GrContextFactory::GLContextType GLContextType;
40#else
41class GrContext;
42class GrRenderTarget;
43typedef int GLContextType;
44#endif
45
mike@reedtribe.org10afbef2011-12-30 16:02:53 +000046static bool gForceBWtext;
47
reed@google.com8923c6c2011-11-08 14:59:38 +000048extern bool gSkSuppressFontCachePurgeSpew;
49
reed@google.com07700442010-12-20 19:46:07 +000050#ifdef SK_SUPPORT_PDF
tomhudson@google.com9875dd12011-04-25 15:49:53 +000051 #include "SkPDFDevice.h"
52 #include "SkPDFDocument.h"
reed@google.com07700442010-12-20 19:46:07 +000053#endif
reed@android.com00dae862009-06-10 15:38:48 +000054
epoger@google.come3cc2eb2012-01-18 20:11:13 +000055// Until we resolve http://code.google.com/p/skia/issues/detail?id=455 ,
56// stop writing out XPS-format image baselines in gm.
57#undef SK_SUPPORT_XPS
bungeman@google.comb29c8832011-10-10 13:19:10 +000058#ifdef SK_SUPPORT_XPS
59 #include "SkXPSDevice.h"
60#endif
61
reed@google.com46cce912011-06-29 12:54:46 +000062#ifdef SK_BUILD_FOR_MAC
63 #include "SkCGUtils.h"
bsalomon@google.com0a09eef2011-06-29 19:42:58 +000064 #define CAN_IMAGE_PDF 1
reed@google.com46cce912011-06-29 12:54:46 +000065#else
bsalomon@google.com0a09eef2011-06-29 19:42:58 +000066 #define CAN_IMAGE_PDF 0
reed@google.com46cce912011-06-29 12:54:46 +000067#endif
68
epoger@google.comc7cf2b32011-12-28 19:31:01 +000069typedef int ErrorBitfield;
70const static ErrorBitfield ERROR_NONE = 0x00;
71const static ErrorBitfield ERROR_NO_GPU_CONTEXT = 0x01;
72const static ErrorBitfield ERROR_PIXEL_MISMATCH = 0x02;
73const static ErrorBitfield ERROR_DIMENSION_MISMATCH = 0x04;
74const static ErrorBitfield ERROR_READING_REFERENCE_IMAGE = 0x08;
75const static ErrorBitfield ERROR_WRITING_REFERENCE_IMAGE = 0x10;
76
reed@android.com00dae862009-06-10 15:38:48 +000077using namespace skiagm;
78
reed@google.comce7ffac2012-11-09 14:51:18 +000079/*
80 * Return the max of the difference (in absolute value) for any component.
81 * Returns 0 if they are equal.
82 */
83static int compute_PMColor_maxDiff(SkPMColor c0, SkPMColor c1) {
84 int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
85 int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
86 int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
87 int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
88 return SkMax32(da, SkMax32(dr, SkMax32(dg, db)));
89}
90
epoger@google.com57f7abc2012-11-13 03:41:55 +000091struct FailRec {
92 SkString fName;
93 int fMaxPixelError;
94
95 FailRec() : fMaxPixelError(0) {}
96 FailRec(const SkString& name) : fName(name), fMaxPixelError(0) {}
97};
98
reed@android.com00dae862009-06-10 15:38:48 +000099class Iter {
100public:
101 Iter() {
bsalomon@google.com39149582011-06-13 21:55:32 +0000102 this->reset();
103 }
104
105 void reset() {
reed@android.comdd0ac282009-06-20 02:38:16 +0000106 fReg = GMRegistry::Head();
reed@android.com00dae862009-06-10 15:38:48 +0000107 }
reed@google.comd4dfd102011-01-18 21:05:42 +0000108
reed@android.comdd0ac282009-06-20 02:38:16 +0000109 GM* next() {
reed@android.com00dae862009-06-10 15:38:48 +0000110 if (fReg) {
reed@android.comdd0ac282009-06-20 02:38:16 +0000111 GMRegistry::Factory fact = fReg->factory();
reed@android.com00dae862009-06-10 15:38:48 +0000112 fReg = fReg->next();
reed@android.comdd0ac282009-06-20 02:38:16 +0000113 return fact(0);
reed@android.com00dae862009-06-10 15:38:48 +0000114 }
115 return NULL;
116 }
reed@google.comd4dfd102011-01-18 21:05:42 +0000117
reed@android.com00dae862009-06-10 15:38:48 +0000118 static int Count() {
reed@android.comdd0ac282009-06-20 02:38:16 +0000119 const GMRegistry* reg = GMRegistry::Head();
reed@android.com00dae862009-06-10 15:38:48 +0000120 int count = 0;
121 while (reg) {
122 count += 1;
123 reg = reg->next();
124 }
125 return count;
126 }
reed@google.comd4dfd102011-01-18 21:05:42 +0000127
reed@android.com00dae862009-06-10 15:38:48 +0000128private:
129 const GMRegistry* fReg;
130};
131
vandebo@chromium.org686abdf2011-02-03 23:00:40 +0000132enum Backend {
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000133 kRaster_Backend,
134 kGPU_Backend,
135 kPDF_Backend,
136 kXPS_Backend,
137};
138
139enum BbhType {
140 kNone_BbhType,
141 kRTree_BbhType,
142 kTileGrid_BbhType,
vandebo@chromium.org686abdf2011-02-03 23:00:40 +0000143};
144
bsalomon@google.com7361f542012-04-19 19:15:35 +0000145enum ConfigFlags {
146 kNone_ConfigFlag = 0x0,
147 /* Write GM images if a write path is provided. */
148 kWrite_ConfigFlag = 0x1,
epoger@google.comf28dd8a2012-10-25 16:27:34 +0000149 /* Read reference GM images if a read path is provided. */
bsalomon@google.com7361f542012-04-19 19:15:35 +0000150 kRead_ConfigFlag = 0x2,
151 kRW_ConfigFlag = (kWrite_ConfigFlag | kRead_ConfigFlag),
152};
153
tomhudson@google.com9875dd12011-04-25 15:49:53 +0000154struct ConfigData {
bsalomon@google.com7361f542012-04-19 19:15:35 +0000155 SkBitmap::Config fConfig;
156 Backend fBackend;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000157 GLContextType fGLContextType; // GPU backend only
bsalomon@google.com7361f542012-04-19 19:15:35 +0000158 int fSampleCnt; // GPU backend only
159 ConfigFlags fFlags;
160 const char* fName;
tomhudson@google.com9875dd12011-04-25 15:49:53 +0000161};
162
mike@reedtribe.org10afbef2011-12-30 16:02:53 +0000163class BWTextDrawFilter : public SkDrawFilter {
164public:
reed@google.com971aca72012-11-26 20:26:54 +0000165 virtual bool filter(SkPaint*, Type) SK_OVERRIDE;
mike@reedtribe.org10afbef2011-12-30 16:02:53 +0000166};
reed@google.com971aca72012-11-26 20:26:54 +0000167bool BWTextDrawFilter::filter(SkPaint* p, Type t) {
mike@reedtribe.org10afbef2011-12-30 16:02:53 +0000168 if (kText_Type == t) {
169 p->setAntiAlias(false);
170 }
reed@google.com971aca72012-11-26 20:26:54 +0000171 return true;
mike@reedtribe.org10afbef2011-12-30 16:02:53 +0000172}
173
scroggo@google.com565254b2012-06-28 15:41:32 +0000174struct PipeFlagComboData {
175 const char* name;
176 uint32_t flags;
177};
178
179static PipeFlagComboData gPipeWritingFlagCombos[] = {
180 { "", 0 },
181 { " cross-process", SkGPipeWriter::kCrossProcess_Flag },
scroggob3c0f482012-07-02 19:07:57 +0000182 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag
scroggo@google.com15011ee2012-07-26 20:03:32 +0000183 | SkGPipeWriter::kSharedAddressSpace_Flag }
scroggo@google.com565254b2012-06-28 15:41:32 +0000184};
185
epoger@google.comde961632012-10-26 18:56:36 +0000186class GMMain {
187public:
epoger@google.come8ebeb12012-10-29 16:42:11 +0000188 GMMain() {
189 // Set default values of member variables, which tool_main()
190 // may override.
191 fNotifyMissingReadReference = true;
192 fUseFileHierarchy = false;
193 }
194
195 SkString make_name(const char shortName[], const char configName[]) {
196 SkString name;
epoger@google.com57f7abc2012-11-13 03:41:55 +0000197 if (0 == strlen(configName)) {
198 name.append(shortName);
199 } else if (fUseFileHierarchy) {
epoger@google.come8ebeb12012-10-29 16:42:11 +0000200 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName);
201 } else {
202 name.appendf("%s_%s", shortName, configName);
203 }
epoger@google.comde961632012-10-26 18:56:36 +0000204 return name;
205 }
206
207 static SkString make_filename(const char path[],
208 const char pathSuffix[],
209 const SkString& name,
210 const char suffix[]) {
211 SkString filename(path);
epoger@google.come8ebeb12012-10-29 16:42:11 +0000212 if (filename.endsWith(SkPATH_SEPARATOR)) {
epoger@google.comde961632012-10-26 18:56:36 +0000213 filename.remove(filename.size() - 1, 1);
214 }
epoger@google.come8ebeb12012-10-29 16:42:11 +0000215 filename.appendf("%s%c%s.%s", pathSuffix, SkPATH_SEPARATOR,
216 name.c_str(), suffix);
epoger@google.comde961632012-10-26 18:56:36 +0000217 return filename;
218 }
219
220 /* since PNG insists on unpremultiplying our alpha, we take no
221 precision chances and force all pixels to be 100% opaque,
222 otherwise on compare we may not get a perfect match.
223 */
224 static void force_all_opaque(const SkBitmap& bitmap) {
225 SkAutoLockPixels lock(bitmap);
226 for (int y = 0; y < bitmap.height(); y++) {
227 for (int x = 0; x < bitmap.width(); x++) {
228 *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
229 }
scroggo@google.com565254b2012-06-28 15:41:32 +0000230 }
231 }
epoger@google.comde961632012-10-26 18:56:36 +0000232
233 static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) {
234 SkBitmap copy;
235 bitmap.copyTo(&copy, SkBitmap::kARGB_8888_Config);
236 force_all_opaque(copy);
237 return SkImageEncoder::EncodeFile(path.c_str(), copy,
238 SkImageEncoder::kPNG_Type, 100);
239 }
240
241 static inline SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1) {
242 int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
243 int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
244 int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
245 return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db));
246 }
247
248 static void compute_diff(const SkBitmap& target, const SkBitmap& base,
249 SkBitmap* diff) {
250 SkAutoLockPixels alp(*diff);
251
252 const int w = target.width();
253 const int h = target.height();
254 for (int y = 0; y < h; y++) {
255 for (int x = 0; x < w; x++) {
256 SkPMColor c0 = *base.getAddr32(x, y);
257 SkPMColor c1 = *target.getAddr32(x, y);
258 SkPMColor d = 0;
259 if (c0 != c1) {
260 d = compute_diff_pmcolor(c0, c1);
261 }
262 *diff->getAddr32(x, y) = d;
263 }
264 }
265 }
266
epoger@google.com57f7abc2012-11-13 03:41:55 +0000267 // Records an error in fFailedTests, if we want to record errors
268 // of this type.
269 void RecordError(ErrorBitfield errorType, const SkString& name,
270 const char renderModeDescriptor [], int maxPixelError=0) {
271 switch (errorType) {
272 case ERROR_NONE:
273 break;
274 case ERROR_READING_REFERENCE_IMAGE:
275 break;
276 default:
277 FailRec& rec = fFailedTests.push_back(make_name(
278 name.c_str(), renderModeDescriptor));
279 rec.fMaxPixelError = maxPixelError;
280 break;
281 }
282 }
283
284 // List contents of fFailedTests via SkDebug.
285 void ListErrors() {
286 for (int i = 0; i < fFailedTests.count(); ++i) {
287 int pixErr = fFailedTests[i].fMaxPixelError;
288 SkString pixStr;
289 if (pixErr > 0) {
290 pixStr.printf(" pixel_error %d", pixErr);
291 }
292 SkDebugf("\t\t%s%s\n", fFailedTests[i].fName.c_str(),
293 pixStr.c_str());
294 }
295 }
296
epoger@google.comde961632012-10-26 18:56:36 +0000297 // Compares "target" and "base" bitmaps, returning the result
298 // (ERROR_NONE if the two bitmaps are identical).
299 //
300 // If a "diff" bitmap is passed in, pixel diffs (if any) will be written
301 // into it.
epoger@google.com57f7abc2012-11-13 03:41:55 +0000302 ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base,
303 const SkString& name,
304 const char* renderModeDescriptor,
305 SkBitmap* diff) {
epoger@google.comde961632012-10-26 18:56:36 +0000306 SkBitmap copy;
307 const SkBitmap* bm = &target;
308 if (target.config() != SkBitmap::kARGB_8888_Config) {
309 target.copyTo(&copy, SkBitmap::kARGB_8888_Config);
310 bm = &copy;
311 }
312 SkBitmap baseCopy;
313 const SkBitmap* bp = &base;
314 if (base.config() != SkBitmap::kARGB_8888_Config) {
315 base.copyTo(&baseCopy, SkBitmap::kARGB_8888_Config);
316 bp = &baseCopy;
317 }
318
319 force_all_opaque(*bm);
320 force_all_opaque(*bp);
321
322 const int w = bm->width();
323 const int h = bm->height();
324 if (w != bp->width() || h != bp->height()) {
325 SkDebugf(
326 "---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n",
327 renderModeDescriptor, name.c_str(),
328 bp->width(), bp->height(), w, h);
epoger@google.com57f7abc2012-11-13 03:41:55 +0000329 RecordError(ERROR_DIMENSION_MISMATCH, name, renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000330 return ERROR_DIMENSION_MISMATCH;
331 }
332
333 SkAutoLockPixels bmLock(*bm);
334 SkAutoLockPixels baseLock(*bp);
335
reed@google.comce7ffac2012-11-09 14:51:18 +0000336 int maxErr = 0;
epoger@google.comde961632012-10-26 18:56:36 +0000337 for (int y = 0; y < h; y++) {
338 for (int x = 0; x < w; x++) {
339 SkPMColor c0 = *bp->getAddr32(x, y);
340 SkPMColor c1 = *bm->getAddr32(x, y);
341 if (c0 != c1) {
reed@google.comce7ffac2012-11-09 14:51:18 +0000342 maxErr = SkMax32(maxErr, compute_PMColor_maxDiff(c0, c1));
epoger@google.comde961632012-10-26 18:56:36 +0000343 }
344 }
345 }
346
reed@google.comce7ffac2012-11-09 14:51:18 +0000347 if (maxErr > 0) {
348 SkDebugf(
349 "----- %s max pixel mismatch for %s is %d\n",
350 renderModeDescriptor, name.c_str(), maxErr);
reed@google.comce7ffac2012-11-09 14:51:18 +0000351 if (diff) {
352 diff->setConfig(SkBitmap::kARGB_8888_Config, w, h);
353 diff->allocPixels();
354 compute_diff(*bm, *bp, diff);
355 }
epoger@google.com57f7abc2012-11-13 03:41:55 +0000356 RecordError(ERROR_PIXEL_MISMATCH, name, renderModeDescriptor,
357 maxErr);
reed@google.comce7ffac2012-11-09 14:51:18 +0000358 return ERROR_PIXEL_MISMATCH;
359 }
epoger@google.comde961632012-10-26 18:56:36 +0000360 return ERROR_NONE;
361 }
362
363 static bool write_document(const SkString& path,
364 const SkDynamicMemoryWStream& document) {
365 SkFILEWStream stream(path.c_str());
366 SkAutoDataUnref data(document.copyToData());
367 return stream.writeData(data.get());
368 }
369
370 /// Returns true if processing should continue, false to skip the
371 /// remainder of this config for this GM.
372 //@todo thudson 22 April 2011 - could refactor this to take in
373 // a factory to generate the context, always call readPixels()
374 // (logically a noop for rasters, if wasted time), and thus collapse the
375 // GPU special case and also let this be used for SkPicture testing.
376 static void setup_bitmap(const ConfigData& gRec, SkISize& size,
377 SkBitmap* bitmap) {
378 bitmap->setConfig(gRec.fConfig, size.width(), size.height());
379 bitmap->allocPixels();
junov@google.comdbfac8a2012-12-06 21:47:40 +0000380 bitmap->eraseColor(SK_ColorTRANSPARENT);
epoger@google.comde961632012-10-26 18:56:36 +0000381 }
382
383 static void installFilter(SkCanvas* canvas) {
384 if (gForceBWtext) {
385 canvas->setDrawFilter(new BWTextDrawFilter)->unref();
386 }
387 }
388
reed@google.comaef73612012-11-16 13:41:45 +0000389 static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF, bool isDeferred) {
epoger@google.comde961632012-10-26 18:56:36 +0000390 SkAutoCanvasRestore acr(canvas, true);
391
392 if (!isPDF) {
393 canvas->concat(gm->getInitialTransform());
394 }
395 installFilter(canvas);
reed@google.comaef73612012-11-16 13:41:45 +0000396 gm->setCanvasIsDeferred(isDeferred);
epoger@google.comde961632012-10-26 18:56:36 +0000397 gm->draw(canvas);
398 canvas->setDrawFilter(NULL);
399 }
400
401 static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec,
402 GrContext* context,
403 GrRenderTarget* rt,
404 SkBitmap* bitmap,
405 bool deferred) {
406 SkISize size (gm->getISize());
407 setup_bitmap(gRec, size, bitmap);
408
409 SkAutoTUnref<SkCanvas> canvas;
410
411 if (gRec.fBackend == kRaster_Backend) {
412 SkAutoTUnref<SkDevice> device(new SkDevice(*bitmap));
413 if (deferred) {
414 canvas.reset(new SkDeferredCanvas(device));
415 } else {
416 canvas.reset(new SkCanvas(device));
417 }
reed@google.comaef73612012-11-16 13:41:45 +0000418 invokeGM(gm, canvas, false, deferred);
epoger@google.comde961632012-10-26 18:56:36 +0000419 canvas->flush();
420 }
421#if SK_SUPPORT_GPU
422 else { // GPU
423 if (NULL == context) {
424 return ERROR_NO_GPU_CONTEXT;
425 }
426 SkAutoTUnref<SkDevice> device(new SkGpuDevice(context, rt));
427 if (deferred) {
428 canvas.reset(new SkDeferredCanvas(device));
429 } else {
430 canvas.reset(new SkCanvas(device));
431 }
reed@google.comaef73612012-11-16 13:41:45 +0000432 invokeGM(gm, canvas, false, deferred);
epoger@google.comde961632012-10-26 18:56:36 +0000433 // the device is as large as the current rendertarget, so
434 // we explicitly only readback the amount we expect (in
435 // size) overwrite our previous allocation
436 bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
437 size.fHeight);
438 canvas->readPixels(bitmap, 0, 0);
439 }
440#endif
441 return ERROR_NONE;
442 }
443
444 static void generate_image_from_picture(GM* gm, const ConfigData& gRec,
445 SkPicture* pict, SkBitmap* bitmap) {
446 SkISize size = gm->getISize();
447 setup_bitmap(gRec, size, bitmap);
448 SkCanvas canvas(*bitmap);
449 installFilter(&canvas);
450 canvas.drawPicture(*pict);
451 }
452
453 static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
454#ifdef SK_SUPPORT_PDF
455 SkMatrix initialTransform = gm->getInitialTransform();
456 SkISize pageSize = gm->getISize();
457 SkPDFDevice* dev = NULL;
458 if (initialTransform.isIdentity()) {
459 dev = new SkPDFDevice(pageSize, pageSize, initialTransform);
460 } else {
461 SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()),
462 SkIntToScalar(pageSize.height()));
463 initialTransform.mapRect(&content);
464 content.intersect(0, 0, SkIntToScalar(pageSize.width()),
465 SkIntToScalar(pageSize.height()));
466 SkISize contentSize =
467 SkISize::Make(SkScalarRoundToInt(content.width()),
468 SkScalarRoundToInt(content.height()));
469 dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
470 }
471 SkAutoUnref aur(dev);
472
473 SkCanvas c(dev);
reed@google.comaef73612012-11-16 13:41:45 +0000474 invokeGM(gm, &c, true, false);
epoger@google.comde961632012-10-26 18:56:36 +0000475
476 SkPDFDocument doc;
477 doc.appendPage(dev);
478 doc.emitPDF(&pdf);
479#endif
480 }
481
482 static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) {
483#ifdef SK_SUPPORT_XPS
484 SkISize size = gm->getISize();
485
486 SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()),
487 SkIntToScalar(size.height()));
488 static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254);
489 static const SkScalar upm = 72 * inchesPerMeter;
490 SkVector unitsPerMeter = SkPoint::Make(upm, upm);
491 static const SkScalar ppm = 200 * inchesPerMeter;
492 SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm);
493
494 SkXPSDevice* dev = new SkXPSDevice();
495 SkAutoUnref aur(dev);
496
497 SkCanvas c(dev);
498 dev->beginPortfolio(&xps);
499 dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize);
reed@google.comaef73612012-11-16 13:41:45 +0000500 invokeGM(gm, &c, false, false);
epoger@google.comde961632012-10-26 18:56:36 +0000501 dev->endSheet();
502 dev->endPortfolio();
503
504#endif
505 }
506
epoger@google.com57f7abc2012-11-13 03:41:55 +0000507 ErrorBitfield write_reference_image(
epoger@google.comde961632012-10-26 18:56:36 +0000508 const ConfigData& gRec, const char writePath [],
509 const char renderModeDescriptor [], const SkString& name,
510 SkBitmap& bitmap, SkDynamicMemoryWStream* document) {
511 SkString path;
512 bool success = false;
513 if (gRec.fBackend == kRaster_Backend ||
514 gRec.fBackend == kGPU_Backend ||
515 (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) {
516
517 path = make_filename(writePath, renderModeDescriptor, name, "png");
518 success = write_bitmap(path, bitmap);
519 }
520 if (kPDF_Backend == gRec.fBackend) {
521 path = make_filename(writePath, renderModeDescriptor, name, "pdf");
522 success = write_document(path, *document);
523 }
524 if (kXPS_Backend == gRec.fBackend) {
525 path = make_filename(writePath, renderModeDescriptor, name, "xps");
526 success = write_document(path, *document);
527 }
528 if (success) {
529 return ERROR_NONE;
530 } else {
531 fprintf(stderr, "FAILED to write %s\n", path.c_str());
epoger@google.com57f7abc2012-11-13 03:41:55 +0000532 RecordError(ERROR_WRITING_REFERENCE_IMAGE, name,
533 renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000534 return ERROR_WRITING_REFERENCE_IMAGE;
535 }
536 }
537
538 // Compares bitmap "bitmap" to "referenceBitmap"; if they are
539 // different, writes out "bitmap" (in PNG format) within the
540 // diffPath subdir.
541 //
542 // Returns the ErrorBitfield from compare(), describing any differences
543 // between "bitmap" and "referenceBitmap" (or ERROR_NONE if there are none).
epoger@google.com57f7abc2012-11-13 03:41:55 +0000544 ErrorBitfield compare_to_reference_image_in_memory(
epoger@google.comde961632012-10-26 18:56:36 +0000545 const SkString& name, SkBitmap &bitmap, const SkBitmap& referenceBitmap,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000546 const char diffPath [], const char renderModeDescriptor []) {
epoger@google.comde961632012-10-26 18:56:36 +0000547 ErrorBitfield errors;
548 SkBitmap diffBitmap;
549 errors = compare(bitmap, referenceBitmap, name, renderModeDescriptor,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000550 diffPath ? &diffBitmap : NULL);
epoger@google.comde961632012-10-26 18:56:36 +0000551 if ((ERROR_NONE != errors) && diffPath) {
552 // write out the generated image
553 SkString genName = make_filename(diffPath, "", name, "png");
554 if (!write_bitmap(genName, bitmap)) {
epoger@google.com57f7abc2012-11-13 03:41:55 +0000555 RecordError(ERROR_WRITING_REFERENCE_IMAGE, name,
556 renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000557 errors |= ERROR_WRITING_REFERENCE_IMAGE;
558 }
559 }
560 return errors;
561 }
562
563 // Compares bitmap "bitmap" to a reference bitmap read from disk;
564 // if they are different, writes out "bitmap" (in PNG format)
565 // within the diffPath subdir.
566 //
567 // Returns a description of the difference between "bitmap" and
568 // the reference bitmap, or ERROR_READING_REFERENCE_IMAGE if
569 // unable to read the reference bitmap from disk.
epoger@google.come8ebeb12012-10-29 16:42:11 +0000570 ErrorBitfield compare_to_reference_image_on_disk(
epoger@google.comde961632012-10-26 18:56:36 +0000571 const char readPath [], const SkString& name, SkBitmap &bitmap,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000572 const char diffPath [], const char renderModeDescriptor []) {
epoger@google.comde961632012-10-26 18:56:36 +0000573 SkString path = make_filename(readPath, "", name, "png");
574 SkBitmap referenceBitmap;
575 if (SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
576 SkBitmap::kARGB_8888_Config,
577 SkImageDecoder::kDecodePixels_Mode,
578 NULL)) {
579 return compare_to_reference_image_in_memory(name, bitmap,
580 referenceBitmap,
581 diffPath,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000582 renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000583 } else {
epoger@google.come8ebeb12012-10-29 16:42:11 +0000584 if (fNotifyMissingReadReference) {
epoger@google.comde961632012-10-26 18:56:36 +0000585 fprintf(stderr, "FAILED to read %s\n", path.c_str());
586 }
epoger@google.com57f7abc2012-11-13 03:41:55 +0000587 RecordError(ERROR_READING_REFERENCE_IMAGE, name,
588 renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000589 return ERROR_READING_REFERENCE_IMAGE;
590 }
591 }
592
593 // NOTE: As far as I can tell, this function is NEVER called with a
594 // non-blank renderModeDescriptor, EXCEPT when readPath and writePath are
595 // both NULL (and thus no images are read from or written to disk).
596 // So I don't trust that the renderModeDescriptor is being used for
597 // anything other than debug output these days.
epoger@google.come8ebeb12012-10-29 16:42:11 +0000598 ErrorBitfield handle_test_results(GM* gm,
599 const ConfigData& gRec,
600 const char writePath [],
601 const char readPath [],
602 const char diffPath [],
603 const char renderModeDescriptor [],
604 SkBitmap& bitmap,
605 SkDynamicMemoryWStream* pdf,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000606 const SkBitmap* referenceBitmap) {
epoger@google.comde961632012-10-26 18:56:36 +0000607 SkString name = make_name(gm->shortName(), gRec.fName);
608 ErrorBitfield retval = ERROR_NONE;
609
610 if (readPath && (gRec.fFlags & kRead_ConfigFlag)) {
611 retval |= compare_to_reference_image_on_disk(readPath, name, bitmap,
612 diffPath,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000613 renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000614 }
615 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
616 retval |= write_reference_image(gRec, writePath,
617 renderModeDescriptor,
618 name, bitmap, pdf);
619 }
620 if (referenceBitmap) {
621 retval |= compare_to_reference_image_in_memory(
epoger@google.com57f7abc2012-11-13 03:41:55 +0000622 name, bitmap, *referenceBitmap, diffPath, renderModeDescriptor);
epoger@google.comde961632012-10-26 18:56:36 +0000623 }
624 return retval;
625 }
626
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000627 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType) {
epoger@google.comde961632012-10-26 18:56:36 +0000628 // Pictures are refcounted so must be on heap
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000629 SkPicture* pict;
epoger@google.comde961632012-10-26 18:56:36 +0000630 SkISize size = gm->getISize();
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000631 if (kTileGrid_BbhType == bbhType) {
632 pict = new SkTileGridPicture(16, 16, size.width(), size.height());
633 } else {
634 pict = new SkPicture;
635 }
636 uint32_t recordFlags = (kNone_BbhType == bbhType) ?
637 0 : SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
638 SkCanvas* cv = pict->beginRecording(size.width(), size.height(), recordFlags);
reed@google.comaef73612012-11-16 13:41:45 +0000639 invokeGM(gm, cv, false, false);
epoger@google.comde961632012-10-26 18:56:36 +0000640 pict->endRecording();
641
642 return pict;
643 }
644
645 static SkPicture* stream_to_new_picture(const SkPicture& src) {
646
647 // To do in-memory commiunications with a stream, we need to:
648 // * create a dynamic memory stream
649 // * copy it into a buffer
650 // * create a read stream from it
651 // ?!?!
652
653 SkDynamicMemoryWStream storage;
654 src.serialize(&storage);
655
656 int streamSize = storage.getOffset();
657 SkAutoMalloc dstStorage(streamSize);
658 void* dst = dstStorage.get();
659 //char* dst = new char [streamSize];
660 //@todo thudson 22 April 2011 when can we safely delete [] dst?
661 storage.copyTo(dst);
662 SkMemoryStream pictReadback(dst, streamSize);
663 SkPicture* retval = new SkPicture (&pictReadback);
664 return retval;
665 }
666
667 // Test: draw into a bitmap or pdf.
668 // Depending on flags, possibly compare to an expected image
669 // and possibly output a diff image if it fails to match.
epoger@google.come8ebeb12012-10-29 16:42:11 +0000670 ErrorBitfield test_drawing(GM* gm,
671 const ConfigData& gRec,
672 const char writePath [],
673 const char readPath [],
674 const char diffPath [],
675 GrContext* context,
676 GrRenderTarget* rt,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000677 SkBitmap* bitmap) {
epoger@google.comde961632012-10-26 18:56:36 +0000678 SkDynamicMemoryWStream document;
679
680 if (gRec.fBackend == kRaster_Backend ||
681 gRec.fBackend == kGPU_Backend) {
682 // Early exit if we can't generate the image.
683 ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap,
684 false);
685 if (ERROR_NONE != errors) {
686 return errors;
687 }
688 } else if (gRec.fBackend == kPDF_Backend) {
689 generate_pdf(gm, document);
690#if CAN_IMAGE_PDF
691 SkAutoDataUnref data(document.copyToData());
692 SkMemoryStream stream(data->data(), data->size());
693 SkPDFDocumentToBitmap(&stream, bitmap);
694#endif
695 } else if (gRec.fBackend == kXPS_Backend) {
696 generate_xps(gm, document);
697 }
698 return handle_test_results(gm, gRec, writePath, readPath, diffPath,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000699 "", *bitmap, &document, NULL);
epoger@google.comde961632012-10-26 18:56:36 +0000700 }
701
epoger@google.come8ebeb12012-10-29 16:42:11 +0000702 ErrorBitfield test_deferred_drawing(GM* gm,
703 const ConfigData& gRec,
704 const SkBitmap& referenceBitmap,
705 const char diffPath [],
706 GrContext* context,
707 GrRenderTarget* rt) {
epoger@google.comde961632012-10-26 18:56:36 +0000708 SkDynamicMemoryWStream document;
709
710 if (gRec.fBackend == kRaster_Backend ||
711 gRec.fBackend == kGPU_Backend) {
712 SkBitmap bitmap;
713 // Early exit if we can't generate the image, but this is
714 // expected in some cases, so don't report a test failure.
715 if (!generate_image(gm, gRec, context, rt, &bitmap, true)) {
716 return ERROR_NONE;
717 }
718 return handle_test_results(gm, gRec, NULL, NULL, diffPath,
719 "-deferred", bitmap, NULL,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000720 &referenceBitmap);
epoger@google.comde961632012-10-26 18:56:36 +0000721 }
722 return ERROR_NONE;
723 }
724
epoger@google.come8ebeb12012-10-29 16:42:11 +0000725 ErrorBitfield test_pipe_playback(GM* gm,
726 const ConfigData& gRec,
727 const SkBitmap& referenceBitmap,
728 const char readPath [],
729 const char diffPath []) {
epoger@google.comde961632012-10-26 18:56:36 +0000730 ErrorBitfield errors = ERROR_NONE;
731 for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
732 SkBitmap bitmap;
733 SkISize size = gm->getISize();
734 setup_bitmap(gRec, size, &bitmap);
735 SkCanvas canvas(bitmap);
736 PipeController pipeController(&canvas);
737 SkGPipeWriter writer;
738 SkCanvas* pipeCanvas = writer.startRecording(
739 &pipeController, gPipeWritingFlagCombos[i].flags);
reed@google.comaef73612012-11-16 13:41:45 +0000740 invokeGM(gm, pipeCanvas, false, false);
epoger@google.comde961632012-10-26 18:56:36 +0000741 writer.endRecording();
742 SkString string("-pipe");
743 string.append(gPipeWritingFlagCombos[i].name);
744 errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath,
745 string.c_str(), bitmap, NULL,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000746 &referenceBitmap);
epoger@google.comde961632012-10-26 18:56:36 +0000747 if (errors != ERROR_NONE) {
748 break;
749 }
750 }
751 return errors;
752 }
753
epoger@google.come8ebeb12012-10-29 16:42:11 +0000754 ErrorBitfield test_tiled_pipe_playback(
epoger@google.comde961632012-10-26 18:56:36 +0000755 GM* gm, const ConfigData& gRec, const SkBitmap& referenceBitmap,
756 const char readPath [], const char diffPath []) {
757 ErrorBitfield errors = ERROR_NONE;
758 for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
759 SkBitmap bitmap;
760 SkISize size = gm->getISize();
761 setup_bitmap(gRec, size, &bitmap);
762 SkCanvas canvas(bitmap);
763 TiledPipeController pipeController(bitmap);
764 SkGPipeWriter writer;
765 SkCanvas* pipeCanvas = writer.startRecording(
766 &pipeController, gPipeWritingFlagCombos[i].flags);
reed@google.comaef73612012-11-16 13:41:45 +0000767 invokeGM(gm, pipeCanvas, false, false);
epoger@google.comde961632012-10-26 18:56:36 +0000768 writer.endRecording();
769 SkString string("-tiled pipe");
770 string.append(gPipeWritingFlagCombos[i].name);
771 errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath,
772 string.c_str(), bitmap, NULL,
epoger@google.com57f7abc2012-11-13 03:41:55 +0000773 &referenceBitmap);
epoger@google.comde961632012-10-26 18:56:36 +0000774 if (errors != ERROR_NONE) {
775 break;
776 }
777 }
778 return errors;
779 }
epoger@google.come8ebeb12012-10-29 16:42:11 +0000780
781 //
782 // member variables.
783 // They are public for now, to allow easier setting by tool_main().
784 //
785
786 // if true, emit a message when we can't find a reference image to compare
787 bool fNotifyMissingReadReference;
788
789 bool fUseFileHierarchy;
790
epoger@google.com57f7abc2012-11-13 03:41:55 +0000791 // information about all failed tests we have encountered so far
792 SkTArray<FailRec> fFailedTests;
793
epoger@google.comde961632012-10-26 18:56:36 +0000794}; // end of GMMain class definition
scroggo@google.com72c96722012-06-06 21:07:10 +0000795
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000796#if SK_SUPPORT_GPU
797static const GLContextType kDontCare_GLContextType = GrContextFactory::kNative_GLContextType;
798#else
799static const GLContextType kDontCare_GLContextType = 0;
800#endif
bsalomon@google.com7361f542012-04-19 19:15:35 +0000801
802// If the platform does not support writing PNGs of PDFs then there will be no
epoger@google.comf28dd8a2012-10-25 16:27:34 +0000803// reference images to read. However, we can always write the .pdf files
bsalomon@google.com7361f542012-04-19 19:15:35 +0000804static const ConfigFlags kPDFConfigFlags = CAN_IMAGE_PDF ? kRW_ConfigFlag :
805 kWrite_ConfigFlag;
806
tomhudson@google.com9875dd12011-04-25 15:49:53 +0000807static const ConfigData gRec[] = {
bsalomon@google.com7361f542012-04-19 19:15:35 +0000808 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "8888" },
reed@google.com69dc4ff2012-11-29 21:21:54 +0000809#if 0 // stop testing this (for now at least) since we want to remove support for it (soon please!!!)
bsalomon@google.com7361f542012-04-19 19:15:35 +0000810 { SkBitmap::kARGB_4444_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "4444" },
reed@google.com69dc4ff2012-11-29 21:21:54 +0000811#endif
bsalomon@google.com7361f542012-04-19 19:15:35 +0000812 { SkBitmap::kRGB_565_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "565" },
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000813#if defined(SK_SCALAR_IS_FLOAT) && SK_SUPPORT_GPU
bsalomon@google.com7361f542012-04-19 19:15:35 +0000814 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kNative_GLContextType, 0, kRW_ConfigFlag, "gpu" },
robertphillips@google.coma73e8602012-08-02 17:56:02 +0000815#ifndef SK_BUILD_FOR_ANDROID
816 // currently we don't want to run MSAA tests on Android
bsalomon@google.com7361f542012-04-19 19:15:35 +0000817 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kNative_GLContextType, 16, kRW_ConfigFlag, "msaa16" },
robertphillips@google.coma73e8602012-08-02 17:56:02 +0000818#endif
bsalomon@google.com7361f542012-04-19 19:15:35 +0000819 /* The debug context does not generate images */
820 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kDebug_GLContextType, 0, kNone_ConfigFlag, "debug" },
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000821#if SK_ANGLE
bsalomon@google.com7361f542012-04-19 19:15:35 +0000822 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 0, kRW_ConfigFlag, "angle" },
823 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 16, kRW_ConfigFlag, "anglemsaa16" },
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000824#endif // SK_ANGLE
825#ifdef SK_MESA
bsalomon@google.com7361f542012-04-19 19:15:35 +0000826 { SkBitmap::kARGB_8888_Config, kGPU_Backend, GrContextFactory::kMESA_GLContextType, 0, kRW_ConfigFlag, "mesa" },
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000827#endif // SK_MESA
robertphillips@google.coma73e8602012-08-02 17:56:02 +0000828#endif // defined(SK_SCALAR_IS_FLOAT) && SK_SUPPORT_GPU
bungeman@google.comb29c8832011-10-10 13:19:10 +0000829#ifdef SK_SUPPORT_XPS
bsalomon@google.com7361f542012-04-19 19:15:35 +0000830 /* At present we have no way of comparing XPS files (either natively or by converting to PNG). */
831 { SkBitmap::kARGB_8888_Config, kXPS_Backend, kDontCare_GLContextType, 0, kWrite_ConfigFlag, "xps" },
robertphillips@google.coma73e8602012-08-02 17:56:02 +0000832#endif // SK_SUPPORT_XPS
bsalomon@google.com7361f542012-04-19 19:15:35 +0000833#ifdef SK_SUPPORT_PDF
834 { SkBitmap::kARGB_8888_Config, kPDF_Backend, kDontCare_GLContextType, 0, kPDFConfigFlags, "pdf" },
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000835#endif // SK_SUPPORT_PDF
reed@android.com00dae862009-06-10 15:38:48 +0000836};
837
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000838static void usage(const char * argv0) {
839 SkDebugf("%s\n", argv0);
reed@google.come5f48b92012-06-22 15:27:39 +0000840 SkDebugf(" [--config ");
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000841 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
842 if (i > 0) {
843 SkDebugf("|");
844 }
845 SkDebugf(gRec[i].fName);
846 }
epoger@google.com82cb65b2012-10-29 18:59:17 +0000847 SkDebugf("]:\n run these configurations\n");
848 SkDebugf(
849// Alphabetized ignoring "no" prefix ("readPath", "noreplay", "resourcePath").
850// It would probably be better if we allowed both yes-and-no settings for each
851// one, e.g.:
852// [--replay|--noreplay]: whether to exercise SkPicture replay; default is yes
853" [--nodeferred]: skip the deferred rendering test pass\n"
854" [--diffPath|-d <path>]: write difference images into this directory\n"
855" [--disable-missing-warning]: don't print a message to stderr if\n"
856" unable to read a reference image for any tests (NOT default behavior)\n"
857" [--enable-missing-warning]: print message to stderr (but don't fail) if\n"
858" unable to read a reference image for any tests (default behavior)\n"
859" [--forceBWtext]: disable text anti-aliasing\n"
860" [--help|-h]: show this help message\n"
861" [--hierarchy|--nohierarchy]: whether to use multilevel directory structure\n"
862" when reading/writing files; default is no\n"
863" [--match <substring>]: only run tests whose name includes this substring\n"
864" [--modulo <remainder> <divisor>]: only run tests for which \n"
865" testIndex %% divisor == remainder\n"
866" [--nopdf]: skip the pdf rendering test pass\n"
867" [--nopipe]: Skip SkGPipe replay\n"
868" [--readPath|-r <path>]: read reference images from this dir, and report\n"
869" any differences between those and the newly generated ones\n"
870" [--noreplay]: do not exercise SkPicture replay\n"
871" [--resourcePath|-i <path>]: directory that stores image resources\n"
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000872" [--rtree]: use an rtree structure for SkPicture testing\n"
epoger@google.com82cb65b2012-10-29 18:59:17 +0000873" [--noserialize]: do not exercise SkPicture serialization & deserialization\n"
874" [--notexturecache]: disable the gpu texture cache\n"
875" [--tiledPipe]: Exercise tiled SkGPipe replay\n"
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000876" [--tileGrid]: use a tileGrid structure for SkPicture testing\n"
epoger@google.com82cb65b2012-10-29 18:59:17 +0000877" [--writePath|-w <path>]: write rendered images into this directory\n"
878" [--writePicturePath|-wp <path>]: write .skp files into this directory\n"
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000879 );
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000880}
881
882static int findConfig(const char config[]) {
883 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
884 if (!strcmp(config, gRec[i].fName)) {
885 return i;
886 }
887 }
888 return -1;
889}
890
reed@google.comb2a51622011-10-31 16:30:04 +0000891static bool skip_name(const SkTDArray<const char*> array, const char name[]) {
892 if (0 == array.count()) {
893 // no names, so don't skip anything
894 return false;
895 }
896 for (int i = 0; i < array.count(); ++i) {
897 if (strstr(name, array[i])) {
898 // found the name, so don't skip
899 return false;
900 }
901 }
902 return true;
903}
904
bsalomon@google.comd9f826c2011-07-18 15:25:04 +0000905namespace skiagm {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000906#if SK_SUPPORT_GPU
bsalomon@google.com7361f542012-04-19 19:15:35 +0000907SkAutoTUnref<GrContext> gGrContext;
908/**
bsalomon@google.comc7a24d22012-11-01 18:03:48 +0000909 * Sets the global GrContext, accessible by individual GMs
bsalomon@google.com7361f542012-04-19 19:15:35 +0000910 */
caryclark@google.com13130862012-06-06 12:10:45 +0000911static void SetGr(GrContext* grContext) {
bsalomon@google.com7361f542012-04-19 19:15:35 +0000912 SkSafeRef(grContext);
913 gGrContext.reset(grContext);
bsalomon@google.comd9f826c2011-07-18 15:25:04 +0000914}
bsalomon@google.com7361f542012-04-19 19:15:35 +0000915
916/**
917 * Gets the global GrContext, can be called by GM tests.
918 */
caryclark@google.com13130862012-06-06 12:10:45 +0000919GrContext* GetGr();
bsalomon@google.com7361f542012-04-19 19:15:35 +0000920GrContext* GetGr() {
921 return gGrContext.get();
922}
923
924/**
925 * Sets the global GrContext and then resets it to its previous value at
926 * destruction.
927 */
928class AutoResetGr : SkNoncopyable {
929public:
930 AutoResetGr() : fOld(NULL) {}
931 void set(GrContext* context) {
932 SkASSERT(NULL == fOld);
933 fOld = GetGr();
934 SkSafeRef(fOld);
935 SetGr(context);
936 }
937 ~AutoResetGr() { SetGr(fOld); SkSafeUnref(fOld); }
938private:
939 GrContext* fOld;
940};
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000941#else
942GrContext* GetGr() { return NULL; }
943#endif
bsalomon@google.comd9f826c2011-07-18 15:25:04 +0000944}
945
caryclark@google.com5987f582012-10-02 18:33:14 +0000946int tool_main(int argc, char** argv);
947int tool_main(int argc, char** argv) {
robertphillips@google.comb74af872012-06-27 19:41:42 +0000948
949#ifdef SK_ENABLE_INST_COUNT
950 gPrintInstCount = true;
951#endif
952
robertphillips@google.com977b9c82012-06-05 19:35:09 +0000953 SkGraphics::Init();
reed@google.com8923c6c2011-11-08 14:59:38 +0000954 // we don't need to see this during a run
955 gSkSuppressFontCachePurgeSpew = true;
reed@google.comd4dfd102011-01-18 21:05:42 +0000956
epoger@google.com7bc13a62012-02-14 14:53:59 +0000957 setSystemPreferences();
epoger@google.comde961632012-10-26 18:56:36 +0000958 GMMain gmmain;
epoger@google.com7bc13a62012-02-14 14:53:59 +0000959
reed@android.com8015dd82009-06-21 00:49:18 +0000960 const char* writePath = NULL; // if non-null, where we write the originals
mike@reedtribe.org5d0c62f2012-06-02 14:50:13 +0000961 const char* writePicturePath = NULL; // if non-null, where we write serialized pictures
reed@android.com8015dd82009-06-21 00:49:18 +0000962 const char* readPath = NULL; // if non-null, were we read from to compare
tomhudson@google.com9875dd12011-04-25 15:49:53 +0000963 const char* diffPath = NULL; // if non-null, where we write our diffs (from compare)
robertphillips@google.com8570b5c2012-03-20 17:40:58 +0000964 const char* resourcePath = NULL;// if non-null, where we read from for image resources
reed@android.com8015dd82009-06-21 00:49:18 +0000965
reed@google.comb2a51622011-10-31 16:30:04 +0000966 SkTDArray<const char*> fMatches;
twiz@google.come24a0792012-01-31 18:35:30 +0000967
reed@google.comab973972011-09-19 19:01:38 +0000968 bool doPDF = true;
reed@google.comb8b09832011-05-26 15:57:56 +0000969 bool doReplay = true;
scroggo@google.com565254b2012-06-28 15:41:32 +0000970 bool doPipe = true;
scroggo@google.com72c96722012-06-06 21:07:10 +0000971 bool doTiledPipe = false;
scroggo@google.com39362522012-09-14 17:37:46 +0000972 bool doSerialize = true;
junov@google.com4370aed2012-01-18 16:21:08 +0000973 bool doDeferred = true;
twiz@google.come24a0792012-01-31 18:35:30 +0000974 bool disableTextureCache = false;
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000975 SkTDArray<size_t> configs;
976 bool userConfig = false;
junov@chromium.org3cb834b2012-12-13 16:39:53 +0000977 BbhType bbhType = kNone_BbhType;
twiz@google.come24a0792012-01-31 18:35:30 +0000978
epoger@google.com82cb65b2012-10-29 18:59:17 +0000979 int moduloRemainder = -1;
980 int moduloDivisor = -1;
reed@google.comae7b8f32012-10-18 21:30:57 +0000981
tomhudson@google.com9875dd12011-04-25 15:49:53 +0000982 const char* const commandName = argv[0];
reed@android.com8015dd82009-06-21 00:49:18 +0000983 char* const* stop = argv + argc;
984 for (++argv; argv < stop; ++argv) {
epoger@google.com82cb65b2012-10-29 18:59:17 +0000985 if (strcmp(*argv, "--config") == 0) {
scroggo@google.com5867c0f2012-06-07 17:39:48 +0000986 argv++;
987 if (argv < stop) {
988 int index = findConfig(*argv);
989 if (index >= 0) {
990 *configs.append() = index;
991 userConfig = true;
992 } else {
993 SkString str;
994 str.printf("unrecognized config %s\n", *argv);
995 SkDebugf(str.c_str());
996 usage(commandName);
997 return -1;
998 }
999 } else {
reed@google.come5f48b92012-06-22 15:27:39 +00001000 SkDebugf("missing arg for --config\n");
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001001 usage(commandName);
1002 return -1;
1003 }
epoger@google.com82cb65b2012-10-29 18:59:17 +00001004 } else if (strcmp(*argv, "--nodeferred") == 0) {
1005 doDeferred = false;
1006 } else if ((0 == strcmp(*argv, "--diffPath")) ||
1007 (0 == strcmp(*argv, "-d"))) {
1008 argv++;
1009 if (argv < stop && **argv) {
1010 diffPath = *argv;
1011 }
1012 } else if (strcmp(*argv, "--disable-missing-warning") == 0) {
1013 gmmain.fNotifyMissingReadReference = false;
junov@chromium.org3cb834b2012-12-13 16:39:53 +00001014 } else if (strcmp(*argv, "--rtree") == 0) {
1015 bbhType = kRTree_BbhType;
1016 } else if (strcmp(*argv, "--tileGrid") == 0) {
1017 bbhType = kTileGrid_BbhType;
epoger@google.com82cb65b2012-10-29 18:59:17 +00001018 } else if (strcmp(*argv, "--enable-missing-warning") == 0) {
1019 gmmain.fNotifyMissingReadReference = true;
1020 } else if (strcmp(*argv, "--forceBWtext") == 0) {
1021 gForceBWtext = true;
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001022 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
1023 usage(commandName);
1024 return -1;
epoger@google.com82cb65b2012-10-29 18:59:17 +00001025 } else if (strcmp(*argv, "--hierarchy") == 0) {
1026 gmmain.fUseFileHierarchy = true;
1027 } else if (strcmp(*argv, "--nohierarchy") == 0) {
1028 gmmain.fUseFileHierarchy = false;
1029 } else if (strcmp(*argv, "--match") == 0) {
1030 ++argv;
1031 if (argv < stop && **argv) {
1032 // just record the ptr, no need for a deep copy
1033 *fMatches.append() = *argv;
1034 }
1035 } else if (strcmp(*argv, "--modulo") == 0) {
1036 ++argv;
1037 if (argv >= stop) {
1038 continue;
1039 }
1040 moduloRemainder = atoi(*argv);
1041
1042 ++argv;
1043 if (argv >= stop) {
1044 continue;
1045 }
1046 moduloDivisor = atoi(*argv);
bsalomon@google.comc7a24d22012-11-01 18:03:48 +00001047 if (moduloRemainder < 0 || moduloDivisor <= 0 || moduloRemainder >= moduloDivisor) {
1048 SkDebugf("invalid modulo values.");
1049 return -1;
1050 }
epoger@google.com82cb65b2012-10-29 18:59:17 +00001051 } else if (strcmp(*argv, "--nopdf") == 0) {
1052 doPDF = false;
1053 } else if (strcmp(*argv, "--nopipe") == 0) {
1054 doPipe = false;
1055 } else if ((0 == strcmp(*argv, "--readPath")) ||
1056 (0 == strcmp(*argv, "-r"))) {
1057 argv++;
1058 if (argv < stop && **argv) {
1059 readPath = *argv;
1060 }
1061 } else if (strcmp(*argv, "--noreplay") == 0) {
1062 doReplay = false;
1063 } else if ((0 == strcmp(*argv, "--resourcePath")) ||
1064 (0 == strcmp(*argv, "-i"))) {
1065 argv++;
1066 if (argv < stop && **argv) {
1067 resourcePath = *argv;
1068 }
1069 } else if (strcmp(*argv, "--serialize") == 0) {
1070 doSerialize = true;
1071 } else if (strcmp(*argv, "--noserialize") == 0) {
1072 doSerialize = false;
1073 } else if (strcmp(*argv, "--notexturecache") == 0) {
1074 disableTextureCache = true;
1075 } else if (strcmp(*argv, "--tiledPipe") == 0) {
1076 doTiledPipe = true;
1077 } else if ((0 == strcmp(*argv, "--writePath")) ||
1078 (0 == strcmp(*argv, "-w"))) {
1079 argv++;
1080 if (argv < stop && **argv) {
1081 writePath = *argv;
1082 }
1083 } else if ((0 == strcmp(*argv, "--writePicturePath")) ||
1084 (0 == strcmp(*argv, "-wp"))) {
1085 argv++;
1086 if (argv < stop && **argv) {
1087 writePicturePath = *argv;
1088 }
tomhudson@google.com9875dd12011-04-25 15:49:53 +00001089 } else {
robertphillips@google.com8570b5c2012-03-20 17:40:58 +00001090 usage(commandName);
1091 return -1;
tomhudson@google.com9875dd12011-04-25 15:49:53 +00001092 }
1093 }
1094 if (argv != stop) {
robertphillips@google.com8570b5c2012-03-20 17:40:58 +00001095 usage(commandName);
1096 return -1;
tomhudson@google.com9875dd12011-04-25 15:49:53 +00001097 }
reed@google.com873cb1e2010-12-23 15:00:45 +00001098
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001099 if (!userConfig) {
1100 // if no config is specified by user, we add them all.
1101 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
1102 *configs.append() = i;
1103 }
1104 }
1105
robertphillips@google.com8570b5c2012-03-20 17:40:58 +00001106 GM::SetResourcePath(resourcePath);
1107
reed@android.com00f883e2010-12-14 17:46:14 +00001108 if (readPath) {
1109 fprintf(stderr, "reading from %s\n", readPath);
chudy@google.comf32f6e82012-07-12 15:42:37 +00001110 }
epoger@google.com9284ccd2012-04-18 13:36:54 +00001111 if (writePath) {
reed@android.com00f883e2010-12-14 17:46:14 +00001112 fprintf(stderr, "writing to %s\n", writePath);
1113 }
mike@reedtribe.org5d0c62f2012-06-02 14:50:13 +00001114 if (writePicturePath) {
1115 fprintf(stderr, "writing pictures to %s\n", writePicturePath);
1116 }
robertphillips@google.com8570b5c2012-03-20 17:40:58 +00001117 if (resourcePath) {
1118 fprintf(stderr, "reading resources from %s\n", resourcePath);
1119 }
1120
epoger@google.com82cb65b2012-10-29 18:59:17 +00001121 if (moduloDivisor <= 0) {
1122 moduloRemainder = -1;
reed@google.comae7b8f32012-10-18 21:30:57 +00001123 }
epoger@google.com82cb65b2012-10-29 18:59:17 +00001124 if (moduloRemainder < 0 || moduloRemainder >= moduloDivisor) {
1125 moduloRemainder = -1;
reed@google.comae7b8f32012-10-18 21:30:57 +00001126 }
1127
epoger@google.comc7cf2b32011-12-28 19:31:01 +00001128 // Accumulate success of all tests.
1129 int testsRun = 0;
1130 int testsPassed = 0;
1131 int testsFailed = 0;
1132 int testsMissingReferenceImages = 0;
1133
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001134#if SK_SUPPORT_GPU
1135 GrContextFactory* grFactory = new GrContextFactory;
twiz@google.come24a0792012-01-31 18:35:30 +00001136 if (disableTextureCache) {
1137 skiagm::GetGr()->setTextureCacheLimits(0, 0);
1138 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001139#endif
twiz@google.come24a0792012-01-31 18:35:30 +00001140
reed@google.comae7b8f32012-10-18 21:30:57 +00001141 int gmIndex = -1;
1142 SkString moduloStr;
1143
epoger@google.come8ebeb12012-10-29 16:42:11 +00001144 // If we will be writing out files, prepare subdirectories.
1145 if (writePath) {
1146 if (!sk_mkdir(writePath)) {
1147 return -1;
1148 }
1149 if (gmmain.fUseFileHierarchy) {
1150 for (int i = 0; i < configs.count(); i++) {
1151 ConfigData config = gRec[configs[i]];
1152 SkString subdir;
1153 subdir.appendf("%s%c%s", writePath, SkPATH_SEPARATOR,
1154 config.fName);
1155 if (!sk_mkdir(subdir.c_str())) {
1156 return -1;
1157 }
1158 }
1159 }
1160 }
1161
bsalomon@google.com7361f542012-04-19 19:15:35 +00001162 Iter iter;
1163 GM* gm;
reed@android.com00dae862009-06-10 15:38:48 +00001164 while ((gm = iter.next()) != NULL) {
skia.committer@gmail.com6a748ad2012-10-19 02:01:19 +00001165
reed@google.comae7b8f32012-10-18 21:30:57 +00001166 ++gmIndex;
epoger@google.com82cb65b2012-10-29 18:59:17 +00001167 if (moduloRemainder >= 0) {
1168 if ((gmIndex % moduloDivisor) != moduloRemainder) {
reed@google.comae7b8f32012-10-18 21:30:57 +00001169 continue;
1170 }
epoger@google.com82cb65b2012-10-29 18:59:17 +00001171 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor);
reed@google.comae7b8f32012-10-18 21:30:57 +00001172 }
1173
reed@google.comece2b022011-07-25 14:28:57 +00001174 const char* shortName = gm->shortName();
reed@google.comb2a51622011-10-31 16:30:04 +00001175 if (skip_name(fMatches, shortName)) {
reed@google.comece2b022011-07-25 14:28:57 +00001176 SkDELETE(gm);
1177 continue;
1178 }
1179
tomhudson@google.com9875dd12011-04-25 15:49:53 +00001180 SkISize size = gm->getISize();
reed@google.comae7b8f32012-10-18 21:30:57 +00001181 SkDebugf("%sdrawing... %s [%d %d]\n", moduloStr.c_str(), shortName,
reed@android.com8015dd82009-06-21 00:49:18 +00001182 size.width(), size.height());
djsollen@google.comebce16d2012-10-26 14:07:13 +00001183
1184 ErrorBitfield testErrors = ERROR_NONE;
1185 uint32_t gmFlags = gm->getFlags();
reed@android.com8015dd82009-06-21 00:49:18 +00001186
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001187 for (int i = 0; i < configs.count(); i++) {
1188 ConfigData config = gRec[configs[i]];
epoger@google.come8ebeb12012-10-29 16:42:11 +00001189
epoger@google.comc7cf2b32011-12-28 19:31:01 +00001190 // Skip any tests that we don't even need to try.
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001191 if ((kPDF_Backend == config.fBackend) &&
bungeman@google.com64e011a2011-09-19 19:31:04 +00001192 (!doPDF || (gmFlags & GM::kSkipPDF_Flag)))
epoger@google.comde961632012-10-26 18:56:36 +00001193 {
1194 continue;
1195 }
reed@google.com1b6c73d2012-10-10 15:17:24 +00001196 if ((gmFlags & GM::kSkip565_Flag) &&
1197 (kRaster_Backend == config.fBackend) &&
1198 (SkBitmap::kRGB_565_Config == config.fConfig)) {
1199 continue;
1200 }
reed@google.comab973972011-09-19 19:01:38 +00001201
epoger@google.comc7cf2b32011-12-28 19:31:01 +00001202 // Now we know that we want to run this test and record its
1203 // success or failure.
djsollen@google.comebce16d2012-10-26 14:07:13 +00001204 ErrorBitfield renderErrors = ERROR_NONE;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001205 GrRenderTarget* renderTarget = NULL;
1206#if SK_SUPPORT_GPU
1207 SkAutoTUnref<GrRenderTarget> rt;
1208 AutoResetGr autogr;
djsollen@google.comebce16d2012-10-26 14:07:13 +00001209 if ((ERROR_NONE == renderErrors) &&
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001210 kGPU_Backend == config.fBackend) {
1211 GrContext* gr = grFactory->get(config.fGLContextType);
1212 bool grSuccess = false;
1213 if (gr) {
1214 // create a render target to back the device
1215 GrTextureDesc desc;
1216 desc.fConfig = kSkia8888_PM_GrPixelConfig;
1217 desc.fFlags = kRenderTarget_GrTextureFlagBit;
1218 desc.fWidth = gm->getISize().width();
1219 desc.fHeight = gm->getISize().height();
1220 desc.fSampleCnt = config.fSampleCnt;
1221 GrTexture* tex = gr->createUncachedTexture(desc, NULL, 0);
1222 if (tex) {
1223 rt.reset(tex->asRenderTarget());
1224 rt.get()->ref();
1225 tex->unref();
1226 autogr.set(gr);
1227 renderTarget = rt.get();
1228 grSuccess = NULL != renderTarget;
1229 }
1230 }
1231 if (!grSuccess) {
djsollen@google.comebce16d2012-10-26 14:07:13 +00001232 renderErrors |= ERROR_NO_GPU_CONTEXT;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001233 }
tomhudson@google.com73fb0422011-04-25 19:20:54 +00001234 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001235#endif
vandebo@chromium.org686abdf2011-02-03 23:00:40 +00001236
djsollen@google.comebce16d2012-10-26 14:07:13 +00001237 SkBitmap comparisonBitmap;
1238
1239 if (ERROR_NONE == renderErrors) {
epoger@google.comde961632012-10-26 18:56:36 +00001240 renderErrors |= gmmain.test_drawing(gm, config, writePath,
1241 readPath, diffPath, GetGr(),
1242 renderTarget,
epoger@google.com57f7abc2012-11-13 03:41:55 +00001243 &comparisonBitmap);
epoger@google.comc7cf2b32011-12-28 19:31:01 +00001244 }
1245
djsollen@google.comebce16d2012-10-26 14:07:13 +00001246 if (doDeferred && !renderErrors &&
scroggo@google.com5867c0f2012-06-07 17:39:48 +00001247 (kGPU_Backend == config.fBackend ||
1248 kRaster_Backend == config.fBackend)) {
epoger@google.comde961632012-10-26 18:56:36 +00001249 renderErrors |= gmmain.test_deferred_drawing(gm, config,
1250 comparisonBitmap,
1251 diffPath, GetGr(),
1252 renderTarget);
junov@google.com4370aed2012-01-18 16:21:08 +00001253 }
1254
djsollen@google.comebce16d2012-10-26 14:07:13 +00001255 testErrors |= renderErrors;
tomhudson@google.com9875dd12011-04-25 15:49:53 +00001256 }
djsollen@google.comebce16d2012-10-26 14:07:13 +00001257
1258 SkBitmap comparisonBitmap;
1259 const ConfigData compareConfig =
1260 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "comparison" };
epoger@google.comde961632012-10-26 18:56:36 +00001261 testErrors |= gmmain.generate_image(gm, compareConfig, NULL, NULL, &comparisonBitmap, false);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001262
1263 // run the picture centric GM steps
1264 if (!(gmFlags & GM::kSkipPicture_Flag)) {
1265
1266 ErrorBitfield pictErrors = ERROR_NONE;
1267
1268 //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm));
junov@chromium.org3cb834b2012-12-13 16:39:53 +00001269 SkPicture* pict = gmmain.generate_new_picture(gm, bbhType);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001270 SkAutoUnref aur(pict);
1271
1272 if ((ERROR_NONE == testErrors) && doReplay) {
1273 SkBitmap bitmap;
epoger@google.comde961632012-10-26 18:56:36 +00001274 gmmain.generate_image_from_picture(gm, compareConfig, pict,
1275 &bitmap);
1276 pictErrors |= gmmain.handle_test_results(gm, compareConfig,
1277 NULL, NULL, diffPath,
1278 "-replay", bitmap,
1279 NULL,
epoger@google.com57f7abc2012-11-13 03:41:55 +00001280 &comparisonBitmap);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001281 }
1282
epoger@google.comde961632012-10-26 18:56:36 +00001283 if ((ERROR_NONE == testErrors) &&
1284 (ERROR_NONE == pictErrors) &&
1285 doSerialize) {
1286 SkPicture* repict = gmmain.stream_to_new_picture(*pict);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001287 SkAutoUnref aurr(repict);
1288
1289 SkBitmap bitmap;
epoger@google.comde961632012-10-26 18:56:36 +00001290 gmmain.generate_image_from_picture(gm, compareConfig, repict,
1291 &bitmap);
1292 pictErrors |= gmmain.handle_test_results(gm, compareConfig,
1293 NULL, NULL, diffPath,
1294 "-serialize", bitmap,
1295 NULL,
epoger@google.com57f7abc2012-11-13 03:41:55 +00001296 &comparisonBitmap);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001297 }
1298
1299 if (writePicturePath) {
1300 const char* pictureSuffix = "skp";
epoger@google.comde961632012-10-26 18:56:36 +00001301 SkString path = gmmain.make_filename(writePicturePath, "",
1302 SkString(gm->shortName()),
1303 pictureSuffix);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001304 SkFILEWStream stream(path.c_str());
1305 pict->serialize(&stream);
1306 }
1307
1308 testErrors |= pictErrors;
1309 }
1310
1311 // run the pipe centric GM steps
1312 if (!(gmFlags & GM::kSkipPipe_Flag)) {
1313
1314 ErrorBitfield pipeErrors = ERROR_NONE;
1315
1316 if ((ERROR_NONE == testErrors) && doPipe) {
epoger@google.comde961632012-10-26 18:56:36 +00001317 pipeErrors |= gmmain.test_pipe_playback(gm, compareConfig,
1318 comparisonBitmap,
1319 readPath, diffPath);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001320 }
1321
1322 if ((ERROR_NONE == testErrors) &&
1323 (ERROR_NONE == pipeErrors) &&
1324 doTiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) {
epoger@google.comde961632012-10-26 18:56:36 +00001325 pipeErrors |= gmmain.test_tiled_pipe_playback(gm, compareConfig,
1326 comparisonBitmap,
1327 readPath,
1328 diffPath);
djsollen@google.comebce16d2012-10-26 14:07:13 +00001329 }
1330
1331 testErrors |= pipeErrors;
1332 }
1333
1334 // Update overall results.
1335 // We only tabulate the particular error types that we currently
1336 // care about (e.g., missing reference images). Later on, if we
1337 // want to also tabulate pixel mismatches vs dimension mistmatches
1338 // (or whatever else), we can do so.
1339 testsRun++;
1340 if (ERROR_NONE == testErrors) {
1341 testsPassed++;
1342 } else if (ERROR_READING_REFERENCE_IMAGE & testErrors) {
1343 testsMissingReferenceImages++;
1344 } else {
1345 testsFailed++;
1346 }
1347
reed@android.com00dae862009-06-10 15:38:48 +00001348 SkDELETE(gm);
1349 }
robertphillips@google.coma2f80082012-08-02 16:22:47 +00001350 SkDebugf("Ran %d tests: %d passed, %d failed, %d missing reference images\n",
1351 testsRun, testsPassed, testsFailed, testsMissingReferenceImages);
epoger@google.com57f7abc2012-11-13 03:41:55 +00001352 gmmain.ListErrors();
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +00001353
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001354#if SK_SUPPORT_GPU
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +00001355
robertphillips@google.com59552022012-08-31 13:07:37 +00001356#if GR_CACHE_STATS
robertphillips@google.com5f9f2f52012-08-22 10:57:05 +00001357 for (int i = 0; i < configs.count(); i++) {
1358 ConfigData config = gRec[configs[i]];
1359
1360 if (kGPU_Backend == config.fBackend) {
1361 GrContext* gr = grFactory->get(config.fGLContextType);
1362
1363 SkDebugf("config: %s %x\n", config.fName, gr);
1364 gr->printCacheStats();
1365 }
1366 }
1367#endif
1368
robertphillips@google.com977b9c82012-06-05 19:35:09 +00001369 delete grFactory;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +00001370#endif
robertphillips@google.com977b9c82012-06-05 19:35:09 +00001371 SkGraphics::Term();
1372
epoger@google.comc7cf2b32011-12-28 19:31:01 +00001373 return (0 == testsFailed) ? 0 : -1;
reed@android.com00dae862009-06-10 15:38:48 +00001374}
caryclark@google.com5987f582012-10-02 18:33:14 +00001375
borenet@google.com7158e6a2012-11-01 17:43:44 +00001376#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
caryclark@google.com5987f582012-10-02 18:33:14 +00001377int main(int argc, char * const argv[]) {
1378 return tool_main(argc, (char**) argv);
1379}
1380#endif