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