SkFlags now follows proper dashing convention.
[platform/upstream/libSkiaSharp.git] / tools / render_pictures_main.cpp
1 /*
2  * Copyright 2012 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  */
7
8 #include "CopyTilesRenderer.h"
9 #include "SkBitmap.h"
10 #include "SkDevice.h"
11 #include "SkCommandLineFlags.h"
12 #include "SkGraphics.h"
13 #include "SkImageDecoder.h"
14 #include "SkImageEncoder.h"
15 #include "SkMath.h"
16 #include "SkOSFile.h"
17 #include "SkPicture.h"
18 #include "SkStream.h"
19 #include "SkString.h"
20 #include "PictureRenderer.h"
21 #include "PictureRenderingFlags.h"
22 #include "picture_utils.h"
23
24 // Flags used by this file, alphabetically:
25 DEFINE_int32(clone, 0, "Clone the picture n times before rendering.");
26 DECLARE_bool(deferImageDecoding);
27 DEFINE_int32(maxComponentDiff, 256, "Maximum diff on a component, 0 - 256. Components that differ "
28              "by more than this amount are considered errors, though all diffs are reported. "
29              "Requires --validate.");
30 DECLARE_string(readPath);
31 DEFINE_string2(writePath, w, "", "Directory to write the rendered images.");
32 DEFINE_bool(writeWholeImage, false, "In tile mode, write the entire rendered image to a "
33             "file, instead of an image for each tile.");
34 DEFINE_bool(validate, false, "Verify that the rendered image contains the same pixels as "
35             "the picture rendered in simple mode. When used in conjunction with --bbh, results "
36             "are validated against the picture rendered in the same mode, but without the bbh.");
37
38 static void make_output_filepath(SkString* path, const SkString& dir,
39                                  const SkString& name) {
40     sk_tools::make_filepath(path, dir, name);
41     // Remove ".skp"
42     path->remove(path->size() - 4, 4);
43 }
44
45 // Defined in PictureRenderingFlags.cpp
46 extern bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap);
47
48 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
49                            sk_tools::PictureRenderer& renderer,
50                            SkBitmap** out) {
51     SkString inputFilename;
52     sk_tools::get_basename(&inputFilename, inputPath);
53
54     SkFILEStream inputStream;
55     inputStream.setPath(inputPath.c_str());
56     if (!inputStream.isValid()) {
57         SkDebugf("Could not open file %s\n", inputPath.c_str());
58         return false;
59     }
60
61     bool success = false;
62     SkPicture* picture;
63     if (FLAGS_deferImageDecoding) {
64         picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &lazy_decode_bitmap));
65     } else {
66         picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &SkImageDecoder::DecodeMemory));
67     }
68     if (!success) {
69         SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
70         return false;
71     }
72
73     for (int i = 0; i < FLAGS_clone; ++i) {
74         SkPicture* clone = picture->clone();
75         SkDELETE(picture);
76         picture = clone;
77     }
78
79     SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(),
80              inputPath.c_str());
81
82     renderer.init(picture);
83     renderer.setup();
84
85     SkString* outputPath = NULL;
86     if (NULL != outputDir && outputDir->size() > 0) {
87         outputPath = SkNEW(SkString);
88         make_output_filepath(outputPath, *outputDir, inputFilename);
89     }
90
91     success = renderer.render(outputPath, out);
92     if (outputPath) {
93         if (!success) {
94             SkDebugf("Could not write to file %s\n", outputPath->c_str());
95         }
96         SkDELETE(outputPath);
97     }
98
99     renderer.end();
100
101     SkDELETE(picture);
102     return success;
103 }
104
105 static inline int getByte(uint32_t value, int index) {
106     SkASSERT(0 <= index && index < 4);
107     return (value >> (index * 8)) & 0xFF;
108 }
109
110 static int MaxByteDiff(uint32_t v1, uint32_t v2) {
111     return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
112                    SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
113 }
114
115 namespace {
116 class AutoRestoreBbhType {
117 public:
118     AutoRestoreBbhType() {
119         fRenderer = NULL;
120         fSavedBbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
121     }
122
123     void set(sk_tools::PictureRenderer* renderer,
124              sk_tools::PictureRenderer::BBoxHierarchyType bbhType) {
125         fRenderer = renderer;
126         fSavedBbhType = renderer->getBBoxHierarchyType();
127         renderer->setBBoxHierarchyType(bbhType);
128     }
129
130     ~AutoRestoreBbhType() {
131         if (NULL != fRenderer) {
132             fRenderer->setBBoxHierarchyType(fSavedBbhType);
133         }
134     }
135
136 private:
137     sk_tools::PictureRenderer* fRenderer;
138     sk_tools::PictureRenderer::BBoxHierarchyType fSavedBbhType;
139 };
140 }
141
142 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
143                            sk_tools::PictureRenderer& renderer) {
144     int diffs[256] = {0};
145     SkBitmap* bitmap = NULL;
146     bool success = render_picture(inputPath,
147         FLAGS_writeWholeImage ? NULL : outputDir,
148         renderer,
149         FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL);
150
151     if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) {
152         SkDebugf("Failed to draw the picture.\n");
153         SkDELETE(bitmap);
154         return false;
155     }
156
157     if (FLAGS_validate) {
158         SkBitmap* referenceBitmap = NULL;
159         sk_tools::PictureRenderer* referenceRenderer;
160         // If the renderer uses a BBoxHierarchy, then the reference renderer
161         // will be the same renderer, without the bbh.
162         AutoRestoreBbhType arbbh;
163         if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType !=
164             renderer.getBBoxHierarchyType()) {
165             referenceRenderer = &renderer;
166             referenceRenderer->ref();  // to match auto unref below
167             arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
168         } else {
169             referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer);
170         }
171         SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer);
172
173         success = render_picture(inputPath, NULL, *referenceRenderer,
174                                  &referenceBitmap);
175
176         if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) {
177             SkDebugf("Failed to draw the reference picture.\n");
178             SkDELETE(bitmap);
179             SkDELETE(referenceBitmap);
180             return false;
181         }
182
183         if (success && (bitmap->width() != referenceBitmap->width())) {
184             SkDebugf("Expected image width: %i, actual image width %i.\n",
185                      referenceBitmap->width(), bitmap->width());
186             SkDELETE(bitmap);
187             SkDELETE(referenceBitmap);
188             return false;
189         }
190         if (success && (bitmap->height() != referenceBitmap->height())) {
191             SkDebugf("Expected image height: %i, actual image height %i",
192                      referenceBitmap->height(), bitmap->height());
193             SkDELETE(bitmap);
194             SkDELETE(referenceBitmap);
195             return false;
196         }
197
198         for (int y = 0; success && y < bitmap->height(); y++) {
199             for (int x = 0; success && x < bitmap->width(); x++) {
200                 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
201                                        *bitmap->getAddr32(x, y));
202                 SkASSERT(diff >= 0 && diff <= 255);
203                 diffs[diff]++;
204
205                 if (diff > FLAGS_maxComponentDiff) {
206                     SkDebugf("Expected pixel at (%i %i) exceedds maximum "
207                                  "component diff of %i: 0x%x, actual 0x%x\n",
208                              x, y, FLAGS_maxComponentDiff,
209                              *referenceBitmap->getAddr32(x, y),
210                              *bitmap->getAddr32(x, y));
211                     SkDELETE(bitmap);
212                     SkDELETE(referenceBitmap);
213                     return false;
214                 }
215             }
216         }
217         SkDELETE(referenceBitmap);
218
219         for (int i = 1; i <= 255; ++i) {
220             if(diffs[i] > 0) {
221                 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
222             }
223         }
224     }
225
226     if (FLAGS_writeWholeImage) {
227         sk_tools::force_all_opaque(*bitmap);
228         if (NULL != outputDir && FLAGS_writeWholeImage) {
229             SkString inputFilename;
230             sk_tools::get_basename(&inputFilename, inputPath);
231             SkString outputPath;
232             make_output_filepath(&outputPath, *outputDir, inputFilename);
233             outputPath.append(".png");
234             if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
235                                             SkImageEncoder::kPNG_Type, 100)) {
236                 SkDebugf("Failed to draw the picture.\n");
237                 success = false;
238             }
239         }
240     }
241     SkDELETE(bitmap);
242
243     return success;
244 }
245
246
247 static int process_input(const char* input, const SkString* outputDir,
248                          sk_tools::PictureRenderer& renderer) {
249     SkOSFile::Iter iter(input, "skp");
250     SkString inputFilename;
251     int failures = 0;
252     SkDebugf("process_input, %s\n", input);
253     if (iter.next(&inputFilename)) {
254         do {
255             SkString inputPath;
256             SkString inputAsSkString(input);
257             sk_tools::make_filepath(&inputPath, inputAsSkString, inputFilename);
258             if (!render_picture(inputPath, outputDir, renderer)) {
259                 ++failures;
260             }
261         } while(iter.next(&inputFilename));
262     } else if (SkStrEndsWith(input, ".skp")) {
263         SkString inputPath(input);
264         if (!render_picture(inputPath, outputDir, renderer)) {
265             ++failures;
266         }
267     } else {
268         SkString warning;
269         warning.printf("Warning: skipping %s\n", input);
270         SkDebugf(warning.c_str());
271     }
272     return failures;
273 }
274
275 int tool_main(int argc, char** argv);
276 int tool_main(int argc, char** argv) {
277     SkCommandLineFlags::SetUsage("Render .skp files.");
278     SkCommandLineFlags::Parse(argc, argv);
279
280     if (FLAGS_readPath.isEmpty()) {
281         SkDebugf(".skp files or directories are required.\n");
282         exit(-1);
283     }
284
285     if (FLAGS_maxComponentDiff < 0 || FLAGS_maxComponentDiff > 256) {
286         SkDebugf("--maxComponentDiff must be between 0 and 256\n");
287         exit(-1);
288     }
289
290     if (FLAGS_maxComponentDiff != 256 && !FLAGS_validate) {
291         SkDebugf("--maxComponentDiff requires --validate\n");
292         exit(-1);
293     }
294
295     if (FLAGS_clone < 0) {
296         SkDebugf("--clone must be >= 0. Was %i\n", FLAGS_clone);
297         exit(-1);
298     }
299
300     SkString errorString;
301     SkAutoTUnref<sk_tools::PictureRenderer> renderer(parseRenderer(errorString,
302                                                                    kRender_PictureTool));
303     if (errorString.size() > 0) {
304         SkDebugf("%s\n", errorString.c_str());
305     }
306
307     if (renderer.get() == NULL) {
308         exit(-1);
309     }
310
311     SkAutoGraphics ag;
312
313     SkString outputDir;
314     if (FLAGS_writePath.count() == 1) {
315         outputDir.set(FLAGS_writePath[0]);
316     }
317
318     int failures = 0;
319     for (int i = 0; i < FLAGS_readPath.count(); i ++) {
320         failures += process_input(FLAGS_readPath[i], &outputDir, *renderer.get());
321     }
322     if (failures != 0) {
323         SkDebugf("Failed to render %i pictures.\n", failures);
324         return 1;
325     }
326 #if SK_SUPPORT_GPU
327 #if GR_CACHE_STATS
328     if (renderer->isUsingGpuDevice()) {
329         GrContext* ctx = renderer->getGrContext();
330
331         ctx->printCacheStats();
332     }
333 #endif
334 #endif
335     return 0;
336 }
337
338 #if !defined SK_BUILD_FOR_IOS
339 int main(int argc, char * const argv[]) {
340     return tool_main(argc, (char**) argv);
341 }
342 #endif