1 /* 2 * Copyright 2016 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 "Benchmark.h" 9 10 #include "Resources.h" 11 #include "SkAutoPixmapStorage.h" 12 #include "SkData.h" 13 #include "SkGradientShader.h" 14 #include "SkImage.h" 15 #include "SkPixmap.h" 16 #include "SkRandom.h" 17 #include "SkStream.h" 18 19 namespace { 20 struct WStreamWriteTextBenchmark : public Benchmark { 21 std::unique_ptr<SkWStream> fWStream; 22 WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {} 23 const char* onGetName() override { return "WStreamWriteText"; } 24 bool isSuitableFor(Backend backend) override { 25 return backend == kNonRendering_Backend; 26 } 27 void onDraw(int loops, SkCanvas*) override { 28 while (loops-- > 0) { 29 for (int i = 1000; i-- > 0;) { 30 fWStream->writeText("HELLO SKIA!\n"); 31 } 32 } 33 } 34 }; 35 } // namespace 36 37 DEF_BENCH(return new WStreamWriteTextBenchmark;) 38 39 #ifdef SK_SUPPORT_PDF 40 41 #include "SkPDFBitmap.h" 42 #include "SkPDFDocument.h" 43 #include "SkPDFShader.h" 44 #include "SkPDFUtils.h" 45 46 namespace { 47 static void test_pdf_object_serialization(const sk_sp<SkPDFObject> object) { 48 // SkDebugWStream wStream; 49 SkNullWStream wStream; 50 SkPDFObjNumMap objNumMap; 51 objNumMap.addObjectRecursively(object.get()); 52 for (int i = 0; i < objNumMap.objects().count(); ++i) { 53 SkPDFObject* object = objNumMap.objects()[i].get(); 54 wStream.writeDecAsText(i + 1); 55 wStream.writeText(" 0 obj\n"); 56 object->emitObject(&wStream, objNumMap); 57 wStream.writeText("\nendobj\n"); 58 } 59 } 60 61 class PDFImageBench : public Benchmark { 62 public: 63 PDFImageBench() {} 64 ~PDFImageBench() override {} 65 66 protected: 67 const char* onGetName() override { return "PDFImage"; } 68 bool isSuitableFor(Backend backend) override { 69 return backend == kNonRendering_Backend; 70 } 71 void onDelayedSetup() override { 72 sk_sp<SkImage> img(GetResourceAsImage("color_wheel.png")); 73 if (img) { 74 // force decoding, throw away reference to encoded data. 75 SkAutoPixmapStorage pixmap; 76 pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions())); 77 if (img->readPixels(pixmap, 0, 0)) { 78 fImage = SkImage::MakeRasterCopy(pixmap); 79 } 80 } 81 } 82 void onDraw(int loops, SkCanvas*) override { 83 if (!fImage) { 84 return; 85 } 86 while (loops-- > 0) { 87 auto object = SkPDFCreateBitmapObject(fImage, nullptr); 88 SkASSERT(object); 89 if (!object) { 90 return; 91 } 92 test_pdf_object_serialization(object); 93 } 94 } 95 96 private: 97 sk_sp<SkImage> fImage; 98 }; 99 100 class PDFJpegImageBench : public Benchmark { 101 public: 102 PDFJpegImageBench() {} 103 ~PDFJpegImageBench() override {} 104 105 protected: 106 const char* onGetName() override { return "PDFJpegImage"; } 107 bool isSuitableFor(Backend backend) override { 108 return backend == kNonRendering_Backend; 109 } 110 void onDelayedSetup() override { 111 sk_sp<SkImage> img(GetResourceAsImage("mandrill_512_q075.jpg")); 112 if (!img) { return; } 113 sk_sp<SkData> encoded = img->refEncodedData(); 114 SkASSERT(encoded); 115 if (!encoded) { return; } 116 fImage = img; 117 } 118 void onDraw(int loops, SkCanvas*) override { 119 if (!fImage) { 120 SkDEBUGFAIL(""); 121 return; 122 } 123 while (loops-- > 0) { 124 auto object = SkPDFCreateBitmapObject(fImage, nullptr); 125 SkASSERT(object); 126 if (!object) { 127 return; 128 } 129 test_pdf_object_serialization(object); 130 } 131 } 132 133 private: 134 sk_sp<SkImage> fImage; 135 }; 136 137 /** Test calling DEFLATE on a 78k PDF command stream. Used for measuring 138 alternate zlib settings, usage, and library versions. */ 139 class PDFCompressionBench : public Benchmark { 140 public: 141 PDFCompressionBench() {} 142 ~PDFCompressionBench() override {} 143 144 protected: 145 const char* onGetName() override { return "PDFCompression"; } 146 bool isSuitableFor(Backend backend) override { 147 return backend == kNonRendering_Backend; 148 } 149 void onDelayedSetup() override { 150 fAsset.reset(GetResourceAsStream("pdf_command_stream.txt")); 151 } 152 void onDraw(int loops, SkCanvas*) override { 153 SkASSERT(fAsset); 154 if (!fAsset) { return; } 155 while (loops-- > 0) { 156 sk_sp<SkPDFObject> object = 157 sk_make_sp<SkPDFSharedStream>( 158 std::unique_ptr<SkStreamAsset>(fAsset->duplicate())); 159 test_pdf_object_serialization(object); 160 } 161 } 162 163 private: 164 std::unique_ptr<SkStreamAsset> fAsset; 165 }; 166 167 // Test speed of SkPDFUtils::FloatToDecimal for typical floats that 168 // might be found in a PDF document. 169 struct PDFScalarBench : public Benchmark { 170 bool isSuitableFor(Backend b) override { 171 return b == kNonRendering_Backend; 172 } 173 const char* onGetName() override { return "PDFScalar"; } 174 void onDraw(int loops, SkCanvas*) override { 175 SkRandom random; 176 char dst[SkPDFUtils::kMaximumFloatDecimalLength]; 177 while (loops-- > 0) { 178 auto f = random.nextRangeF(-500.0f, 1500.0f); 179 (void)SkPDFUtils::FloatToDecimal(f, dst); 180 } 181 } 182 }; 183 184 struct PDFColorComponentBench : public Benchmark { 185 bool isSuitableFor(Backend b) override { 186 return b == kNonRendering_Backend; 187 } 188 const char* onGetName() override { return "PDFColorComponent"; } 189 void onDraw(int loops, SkCanvas*) override { 190 char dst[5]; 191 while (loops-- > 0) { 192 for (int i = 0; i < 256; ++i) { 193 (void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst); 194 } 195 } 196 } 197 }; 198 199 struct PDFShaderBench : public Benchmark { 200 sk_sp<SkShader> fShader; 201 const char* onGetName() final { return "PDFShader"; } 202 bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; } 203 void onDelayedSetup() final { 204 const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}}; 205 const SkColor colors[] = { 206 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, 207 SK_ColorWHITE, SK_ColorBLACK, 208 }; 209 fShader = SkGradientShader::MakeLinear( 210 pts, colors, nullptr, SK_ARRAY_COUNT(colors), 211 SkShader::kClamp_TileMode); 212 } 213 void onDraw(int loops, SkCanvas*) final { 214 SkASSERT(fShader); 215 while (loops-- > 0) { 216 SkNullWStream nullStream; 217 SkPDFDocument doc(&nullStream, nullptr, 72, 218 SkDocument::PDFMetadata(), nullptr, false); 219 sk_sp<SkPDFObject> shader = 220 SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), {0, 0, 400,400}); 221 } 222 } 223 }; 224 225 struct WritePDFTextBenchmark : public Benchmark { 226 std::unique_ptr<SkWStream> fWStream; 227 WritePDFTextBenchmark() : fWStream(new SkNullWStream) {} 228 const char* onGetName() override { return "WritePDFText"; } 229 bool isSuitableFor(Backend backend) override { 230 return backend == kNonRendering_Backend; 231 } 232 void onDraw(int loops, SkCanvas*) override { 233 static const char kHello[] = "HELLO SKIA!\n"; 234 static const char kBinary[] = "\001\002\003\004\005\006"; 235 while (loops-- > 0) { 236 for (int i = 1000; i-- > 0;) { 237 SkPDFUtils::WriteString(fWStream.get(), kHello, strlen(kHello)); 238 SkPDFUtils::WriteString(fWStream.get(), kBinary, strlen(kBinary)); 239 } 240 } 241 } 242 }; 243 244 } // namespace 245 DEF_BENCH(return new PDFImageBench;) 246 DEF_BENCH(return new PDFJpegImageBench;) 247 DEF_BENCH(return new PDFCompressionBench;) 248 DEF_BENCH(return new PDFScalarBench;) 249 DEF_BENCH(return new PDFColorComponentBench;) 250 DEF_BENCH(return new PDFShaderBench;) 251 DEF_BENCH(return new WritePDFTextBenchmark;) 252 253 #endif 254 255