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 "SkExecutor.h"
14 #include "SkFloatToDecimal.h"
15 #include "SkGradientShader.h"
16 #include "SkImage.h"
17 #include "SkPDFUnion.h"
18 #include "SkPixmap.h"
19 #include "SkRandom.h"
20 #include "SkStream.h"
21 #include "SkTo.h"
22
23 namespace {
24 struct WStreamWriteTextBenchmark : public Benchmark {
25 std::unique_ptr<SkWStream> fWStream;
WStreamWriteTextBenchmark__anone3b05aab0111::WStreamWriteTextBenchmark26 WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anone3b05aab0111::WStreamWriteTextBenchmark27 const char* onGetName() override { return "WStreamWriteText"; }
isSuitableFor__anone3b05aab0111::WStreamWriteTextBenchmark28 bool isSuitableFor(Backend backend) override {
29 return backend == kNonRendering_Backend;
30 }
onDraw__anone3b05aab0111::WStreamWriteTextBenchmark31 void onDraw(int loops, SkCanvas*) override {
32 while (loops-- > 0) {
33 for (int i = 1000; i-- > 0;) {
34 fWStream->writeText("HELLO SKIA!\n");
35 }
36 }
37 }
38 };
39 } // namespace
40
41 DEF_BENCH(return new WStreamWriteTextBenchmark;)
42
43 // Test speed of SkFloatToDecimal for typical floats that
44 // might be found in a PDF document.
45 struct PDFScalarBench : public Benchmark {
PDFScalarBenchPDFScalarBench46 PDFScalarBench(const char* n, float (*f)(SkRandom*)) : fName(n), fNextFloat(f) {}
47 const char* fName;
48 float (*fNextFloat)(SkRandom*);
isSuitableForPDFScalarBench49 bool isSuitableFor(Backend b) override {
50 return b == kNonRendering_Backend;
51 }
onGetNamePDFScalarBench52 const char* onGetName() override { return fName; }
onDrawPDFScalarBench53 void onDraw(int loops, SkCanvas*) override {
54 SkRandom random;
55 char dst[kMaximumSkFloatToDecimalLength];
56 while (loops-- > 0) {
57 auto f = fNextFloat(&random);
58 (void)SkFloatToDecimal(f, dst);
59 }
60 }
61 };
62
next_common(SkRandom * random)63 float next_common(SkRandom* random) {
64 return random->nextRangeF(-500.0f, 1500.0f);
65 }
next_any(SkRandom * random)66 float next_any(SkRandom* random) {
67 union { uint32_t u; float f; };
68 u = random->nextU();
69 static_assert(sizeof(float) == sizeof(uint32_t), "");
70 return f;
71 }
72
73 DEF_BENCH(return new PDFScalarBench("PDFScalar_common", next_common);)
74 DEF_BENCH(return new PDFScalarBench("PDFScalar_random", next_any);)
75
76 #ifdef SK_SUPPORT_PDF
77
78 #include "SkPDFBitmap.h"
79 #include "SkPDFDocumentPriv.h"
80 #include "SkPDFShader.h"
81 #include "SkPDFUtils.h"
82
83 namespace {
84 class PDFImageBench : public Benchmark {
85 public:
PDFImageBench()86 PDFImageBench() {}
~PDFImageBench()87 ~PDFImageBench() override {}
88
89 protected:
onGetName()90 const char* onGetName() override { return "PDFImage"; }
isSuitableFor(Backend backend)91 bool isSuitableFor(Backend backend) override {
92 return backend == kNonRendering_Backend;
93 }
onDelayedSetup()94 void onDelayedSetup() override {
95 sk_sp<SkImage> img(GetResourceAsImage("images/color_wheel.png"));
96 if (img) {
97 // force decoding, throw away reference to encoded data.
98 SkAutoPixmapStorage pixmap;
99 pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions()));
100 if (img->readPixels(pixmap, 0, 0)) {
101 fImage = SkImage::MakeRasterCopy(pixmap);
102 }
103 }
104 }
onDraw(int loops,SkCanvas *)105 void onDraw(int loops, SkCanvas*) override {
106 if (!fImage) {
107 return;
108 }
109 while (loops-- > 0) {
110 SkNullWStream nullStream;
111 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
112 doc.beginPage(256, 256);
113 (void)SkPDFSerializeImage(fImage.get(), &doc);
114 }
115 }
116
117 private:
118 sk_sp<SkImage> fImage;
119 };
120
121 class PDFJpegImageBench : public Benchmark {
122 public:
PDFJpegImageBench()123 PDFJpegImageBench() {}
~PDFJpegImageBench()124 ~PDFJpegImageBench() override {}
125
126 protected:
onGetName()127 const char* onGetName() override { return "PDFJpegImage"; }
isSuitableFor(Backend backend)128 bool isSuitableFor(Backend backend) override {
129 return backend == kNonRendering_Backend;
130 }
onDelayedSetup()131 void onDelayedSetup() override {
132 sk_sp<SkImage> img(GetResourceAsImage("images/mandrill_512_q075.jpg"));
133 if (!img) { return; }
134 sk_sp<SkData> encoded = img->refEncodedData();
135 SkASSERT(encoded);
136 if (!encoded) { return; }
137 fImage = img;
138 }
onDraw(int loops,SkCanvas *)139 void onDraw(int loops, SkCanvas*) override {
140 if (!fImage) {
141 SkDEBUGFAIL("");
142 return;
143 }
144 while (loops-- > 0) {
145 SkNullWStream nullStream;
146 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
147 doc.beginPage(256, 256);
148 (void)SkPDFSerializeImage(fImage.get(), &doc);
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:
PDFCompressionBench()160 PDFCompressionBench() {}
~PDFCompressionBench()161 ~PDFCompressionBench() override {}
162
163 protected:
onGetName()164 const char* onGetName() override { return "PDFCompression"; }
isSuitableFor(Backend backend)165 bool isSuitableFor(Backend backend) override {
166 return backend == kNonRendering_Backend;
167 }
onDelayedSetup()168 void onDelayedSetup() override {
169 fAsset = GetResourceAsStream("pdf_command_stream.txt");
170 }
onDraw(int loops,SkCanvas *)171 void onDraw(int loops, SkCanvas*) override {
172 SkASSERT(fAsset);
173 if (!fAsset) { return; }
174 while (loops-- > 0) {
175 SkNullWStream wStream;
176 SkPDFDocument doc(&wStream, SkPDF::Metadata());
177 doc.beginPage(256, 256);
178 (void)SkPDFStreamOut(nullptr, fAsset->duplicate(), &doc, true);
179 }
180 }
181
182 private:
183 std::unique_ptr<SkStreamAsset> fAsset;
184 };
185
186 struct PDFColorComponentBench : public Benchmark {
isSuitableFor__anone3b05aab0311::PDFColorComponentBench187 bool isSuitableFor(Backend b) override {
188 return b == kNonRendering_Backend;
189 }
onGetName__anone3b05aab0311::PDFColorComponentBench190 const char* onGetName() override { return "PDFColorComponent"; }
onDraw__anone3b05aab0311::PDFColorComponentBench191 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;
onGetName__anone3b05aab0311::PDFShaderBench203 const char* onGetName() final { return "PDFShader"; }
isSuitableFor__anone3b05aab0311::PDFShaderBench204 bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
onDelayedSetup__anone3b05aab0311::PDFShaderBench205 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 }
onDraw__anone3b05aab0311::PDFShaderBench215 void onDraw(int loops, SkCanvas*) final {
216 SkASSERT(fShader);
217 while (loops-- > 0) {
218 SkNullWStream nullStream;
219 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
220 doc.beginPage(256, 256);
221 (void) SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(),
222 {0, 0, 400, 400}, SK_ColorBLACK);
223 }
224 }
225 };
226
227 struct WritePDFTextBenchmark : public Benchmark {
228 std::unique_ptr<SkWStream> fWStream;
WritePDFTextBenchmark__anone3b05aab0311::WritePDFTextBenchmark229 WritePDFTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anone3b05aab0311::WritePDFTextBenchmark230 const char* onGetName() override { return "WritePDFText"; }
isSuitableFor__anone3b05aab0311::WritePDFTextBenchmark231 bool isSuitableFor(Backend backend) override {
232 return backend == kNonRendering_Backend;
233 }
onDraw__anone3b05aab0311::WritePDFTextBenchmark234 void onDraw(int loops, SkCanvas*) override {
235 static const char kHello[] = "HELLO SKIA!\n";
236 static const char kBinary[] = "\001\002\003\004\005\006";
237 while (loops-- > 0) {
238 for (int i = 1000; i-- > 0;) {
239 SkPDFWriteString(fWStream.get(), kHello, strlen(kHello));
240 SkPDFWriteString(fWStream.get(), kBinary, strlen(kBinary));
241 }
242 }
243 }
244 };
245
246 } // namespace
247 DEF_BENCH(return new PDFImageBench;)
248 DEF_BENCH(return new PDFJpegImageBench;)
249 DEF_BENCH(return new PDFCompressionBench;)
250 DEF_BENCH(return new PDFColorComponentBench;)
251 DEF_BENCH(return new PDFShaderBench;)
252 DEF_BENCH(return new WritePDFTextBenchmark;)
253
254 #ifdef SK_PDF_ENABLE_SLOW_TESTS
255 #include "SkExecutor.h"
256 namespace {
big_pdf_test(SkDocument * doc,const SkBitmap & background)257 void big_pdf_test(SkDocument* doc, const SkBitmap& background) {
258 static const char* kText[] = {
259 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do",
260 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
261 "minim veniam, quis nostrud exercitation ullamco laboris nisi ut",
262 "aliquip ex ea commodo consequat. Duis aute irure dolor in",
263 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla",
264 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in",
265 "culpa qui officia deserunt mollit anim id est laborum.",
266 "",
267 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
268 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
269 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
270 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
271 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
272 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
273 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
274 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
275 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
276 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
277 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
278 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
279 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
280 "pariatur?",
281 "",
282 "At vero eos et accusamus et iusto odio dignissimos ducimus, qui",
283 "blanditiis praesentium voluptatum deleniti atque corrupti, quos",
284 "dolores et quas molestias excepturi sint, obcaecati cupiditate non",
285 "provident, similique sunt in culpa, qui officia deserunt mollitia",
286 "animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis",
287 "est et expedita distinctio. Nam libero tempore, cum soluta nobis est",
288 "eligendi optio, cumque nihil impedit, quo minus id, quod maxime",
289 "placeat, facere possimus, omnis voluptas assumenda est, omnis dolor",
290 "repellendus. Temporibus autem quibusdam et aut officiis debitis aut",
291 "rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint",
292 "et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente",
293 "delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut",
294 "perferendis doloribus asperiores repellat",
295 "",
296 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
297 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
298 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
299 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
300 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
301 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
302 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
303 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
304 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
305 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
306 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
307 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
308 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
309 "pariatur?",
310 "",
311 };
312 SkCanvas* canvas = nullptr;
313 float x = 36;
314 float y = 36;
315 constexpr size_t kLineCount = SK_ARRAY_COUNT(kText);
316 constexpr int kLoopCount = 200;
317 SkFont font;
318 SkPaint paint;
319 for (int loop = 0; loop < kLoopCount; ++loop) {
320 for (size_t line = 0; line < kLineCount; ++line) {
321 y += font.getSpacing();
322 if (!canvas || y > 792 - 36) {
323 y = 36 + font.getSpacing();
324 canvas = doc->beginPage(612, 792);
325 background.notifyPixelsChanged();
326 canvas->drawBitmap(background, 0, 0);
327 }
328 canvas->drawString(kText[line], x, y, font, paint);
329 }
330 }
331 }
332
make_background()333 SkBitmap make_background() {
334 SkBitmap background;
335 SkBitmap bitmap;
336 bitmap.allocN32Pixels(32, 32);
337 bitmap.eraseColor(SK_ColorWHITE);
338 SkCanvas tmp(bitmap);
339 SkPaint gray;
340 gray.setColor(SkColorSetARGB(0xFF, 0xEE, 0xEE, 0xEE));
341 tmp.drawRect({0,0,16,16}, gray);
342 tmp.drawRect({16,16,32,32}, gray);
343 SkPaint shader;
344 shader.setShader(
345 SkShader::MakeBitmapShader(
346 bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
347 background.allocN32Pixels(612, 792);
348 SkCanvas tmp2(background);
349 tmp2.drawPaint(shader);
350 return background;
351 }
352
353 struct PDFBigDocBench : public Benchmark {
354 bool fFast;
355 SkBitmap fBackground;
356 std::unique_ptr<SkExecutor> fExecutor;
PDFBigDocBench__anone3b05aab0411::PDFBigDocBench357 PDFBigDocBench(bool fast) : fFast(fast) {}
onDelayedSetup__anone3b05aab0411::PDFBigDocBench358 void onDelayedSetup() override {
359 fBackground = make_background();
360 fExecutor = fFast ? SkExecutor::MakeFIFOThreadPool() : nullptr;
361 }
onGetName__anone3b05aab0411::PDFBigDocBench362 const char* onGetName() override {
363 static const char kNameFast[] = "PDFBigDocBench_fast";
364 static const char kNameSlow[] = "PDFBigDocBench_slow";
365 return fFast ? kNameFast : kNameSlow;
366 }
isSuitableFor__anone3b05aab0411::PDFBigDocBench367 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
onDraw__anone3b05aab0411::PDFBigDocBench368 void onDraw(int loops, SkCanvas*) override {
369 while (loops-- > 0) {
370 #ifdef SK_PDF_TEST_BIGDOCBENCH_OUTPUT
371 SkFILEWStream wStream("/tmp/big_pdf.pdf");
372 #else
373 SkNullWStream wStream;
374 #endif
375 SkPDF::Metadata metadata;
376 metadata.fExecutor = fExecutor.get();
377 auto doc = SkPDF::MakeDocument(&wStream, metadata);
378 big_pdf_test(doc.get(), fBackground);
379 }
380 }
381 };
382 } // namespace
383 DEF_BENCH(return new PDFBigDocBench(false);)
384 DEF_BENCH(return new PDFBigDocBench(true);)
385 #endif
386
387 #endif // SK_SUPPORT_PDF
388