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