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