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 20namespace { 21struct 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 38DEF_BENCH(return new WStreamWriteTextBenchmark;) 39 40// Test speed of SkFloatToDecimal for typical floats that 41// might be found in a PDF document. 42struct 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 57DEF_BENCH(return new PDFScalarBench;) 58 59#ifdef SK_SUPPORT_PDF 60 61#include "SkPDFBitmap.h" 62#include "SkPDFDocument.h" 63#include "SkPDFShader.h" 64 65namespace { 66static 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 80class PDFImageBench : public Benchmark { 81public: 82 PDFImageBench() {} 83 ~PDFImageBench() override {} 84 85protected: 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 115private: 116 sk_sp<SkImage> fImage; 117}; 118 119class PDFJpegImageBench : public Benchmark { 120public: 121 PDFJpegImageBench() {} 122 ~PDFJpegImageBench() override {} 123 124protected: 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 152private: 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. */ 158class PDFCompressionBench : public Benchmark { 159public: 160 PDFCompressionBench() {} 161 ~PDFCompressionBench() override {} 162 163protected: 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 182private: 183 std::unique_ptr<SkStreamAsset> fAsset; 184}; 185 186struct 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 201struct 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 226struct 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 246DEF_BENCH(return new PDFImageBench;) 247DEF_BENCH(return new PDFJpegImageBench;) 248DEF_BENCH(return new PDFCompressionBench;) 249DEF_BENCH(return new PDFColorComponentBench;) 250DEF_BENCH(return new PDFShaderBench;) 251DEF_BENCH(return new WritePDFTextBenchmark;) 252 253#endif 254 255