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 "bench/Benchmark.h"
9
10 #include "include/core/SkData.h"
11 #include "include/core/SkExecutor.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkPixmap.h"
14 #include "include/core/SkStream.h"
15 #include "include/effects/SkGradientShader.h"
16 #include "include/private/SkTo.h"
17 #include "include/utils/SkRandom.h"
18 #include "src/core/SkAutoPixmapStorage.h"
19 #include "src/pdf/SkPDFUnion.h"
20 #include "src/utils/SkFloatToDecimal.h"
21 #include "tools/Resources.h"
22
23 namespace {
24 struct WStreamWriteTextBenchmark : public Benchmark {
25 std::unique_ptr<SkWStream> fWStream;
WStreamWriteTextBenchmark__anon06586a2a0111::WStreamWriteTextBenchmark26 WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anon06586a2a0111::WStreamWriteTextBenchmark27 const char* onGetName() override { return "WStreamWriteText"; }
isSuitableFor__anon06586a2a0111::WStreamWriteTextBenchmark28 bool isSuitableFor(Backend backend) override {
29 return backend == kNonRendering_Backend;
30 }
onDraw__anon06586a2a0111::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 "src/pdf/SkPDFBitmap.h"
79 #include "src/pdf/SkPDFDocumentPriv.h"
80 #include "src/pdf/SkPDFShader.h"
81 #include "src/pdf/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__anon06586a2a0311::PDFColorComponentBench187 bool isSuitableFor(Backend b) override {
188 return b == kNonRendering_Backend;
189 }
onGetName__anon06586a2a0311::PDFColorComponentBench190 const char* onGetName() override { return "PDFColorComponent"; }
onDraw__anon06586a2a0311::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__anon06586a2a0311::PDFShaderBench203 const char* onGetName() final { return "PDFShader"; }
isSuitableFor__anon06586a2a0311::PDFShaderBench204 bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
onDelayedSetup__anon06586a2a0311::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 SkTileMode::kClamp);
214 }
onDraw__anon06586a2a0311::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}, SkColors::kBlack);
223 }
224 }
225 };
226
227 struct WritePDFTextBenchmark : public Benchmark {
228 std::unique_ptr<SkWStream> fWStream;
WritePDFTextBenchmark__anon06586a2a0311::WritePDFTextBenchmark229 WritePDFTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anon06586a2a0311::WritePDFTextBenchmark230 const char* onGetName() override { return "WritePDFText"; }
isSuitableFor__anon06586a2a0311::WritePDFTextBenchmark231 bool isSuitableFor(Backend backend) override {
232 return backend == kNonRendering_Backend;
233 }
onDraw__anon06586a2a0311::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 // Test for regression chromium:947381
247 // with 5c83ae81aa : 2364.99 microsec
248 // without 5c83ae81aa : 302821.78 microsec
249 struct PDFClipPathBenchmark : public Benchmark {
250 SkPath fPath;
onDelayedSetup__anon06586a2a0311::PDFClipPathBenchmark251 void onDelayedSetup() override {
252 SkBitmap bitmap;
253 bitmap.allocN32Pixels(256, 256);
254 bitmap.eraseColor(SK_ColorWHITE);
255 {
256 SkCanvas tmp(bitmap);
257 SkPaint paint;
258 paint.setAntiAlias(false);
259 paint.setStyle(SkPaint::kStroke_Style);
260 paint.setStrokeWidth(10);
261 for (int r : {20, 40, 60, 80, 100, 120}) {
262 tmp.drawCircle(128, 128, (float)r, paint);
263 }
264 }
265 fPath.reset();
266 for (int y = 0; y < 256; ++y) {
267 SkColor current = bitmap.getColor(0, y);
268 int start = 0;
269 for (int x = 0; x < 256; ++x) {
270 SkColor color = bitmap.getColor(x, y);
271 if (color == current) {
272 continue;
273 }
274 if (color == SK_ColorBLACK) {
275 start = x;
276 } else {
277 fPath.addRect(SkRect::Make(SkIRect{start, y, x, y + 1}));
278 }
279 current = color;
280 }
281 if (current == SK_ColorBLACK) {
282 fPath.addRect(SkRect::Make(SkIRect{start, y, 256, y + 1}));
283 }
284 }
285 }
onGetName__anon06586a2a0311::PDFClipPathBenchmark286 const char* onGetName() override { return "PDFClipPath"; }
isSuitableFor__anon06586a2a0311::PDFClipPathBenchmark287 bool isSuitableFor(Backend backend) override {
288 return backend == kNonRendering_Backend;
289 }
onDraw__anon06586a2a0311::PDFClipPathBenchmark290 void onDraw(int loops, SkCanvas*) override {
291 while (loops-- > 0) {
292 SkNullWStream wStream;
293 SkPDFDocument doc(&wStream, SkPDF::Metadata());
294 SkCanvas* canvas = doc.beginPage(256, 256);
295 canvas->clipPath(fPath);
296 canvas->translate(4.0f/3, 4.0f/3);
297 canvas->clipPath(fPath);
298 canvas->clear(SK_ColorRED);
299 doc.endPage();
300 }
301 }
302 };
303
304 } // namespace
305 DEF_BENCH(return new PDFImageBench;)
306 DEF_BENCH(return new PDFJpegImageBench;)
307 DEF_BENCH(return new PDFCompressionBench;)
308 DEF_BENCH(return new PDFColorComponentBench;)
309 DEF_BENCH(return new PDFShaderBench;)
310 DEF_BENCH(return new WritePDFTextBenchmark;)
311 DEF_BENCH(return new PDFClipPathBenchmark;)
312
313 #ifdef SK_PDF_ENABLE_SLOW_TESTS
314 #include "include/core/SkExecutor.h"
315 namespace {
big_pdf_test(SkDocument * doc,const SkBitmap & background)316 void big_pdf_test(SkDocument* doc, const SkBitmap& background) {
317 static const char* kText[] = {
318 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do",
319 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
320 "minim veniam, quis nostrud exercitation ullamco laboris nisi ut",
321 "aliquip ex ea commodo consequat. Duis aute irure dolor in",
322 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla",
323 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in",
324 "culpa qui officia deserunt mollit anim id est laborum.",
325 "",
326 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
327 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
328 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
329 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
330 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
331 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
332 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
333 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
334 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
335 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
336 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
337 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
338 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
339 "pariatur?",
340 "",
341 "At vero eos et accusamus et iusto odio dignissimos ducimus, qui",
342 "blanditiis praesentium voluptatum deleniti atque corrupti, quos",
343 "dolores et quas molestias excepturi sint, obcaecati cupiditate non",
344 "provident, similique sunt in culpa, qui officia deserunt mollitia",
345 "animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis",
346 "est et expedita distinctio. Nam libero tempore, cum soluta nobis est",
347 "eligendi optio, cumque nihil impedit, quo minus id, quod maxime",
348 "placeat, facere possimus, omnis voluptas assumenda est, omnis dolor",
349 "repellendus. Temporibus autem quibusdam et aut officiis debitis aut",
350 "rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint",
351 "et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente",
352 "delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut",
353 "perferendis doloribus asperiores repellat",
354 "",
355 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
356 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
357 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
358 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
359 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
360 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
361 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
362 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
363 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
364 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
365 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
366 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
367 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
368 "pariatur?",
369 "",
370 };
371 SkCanvas* canvas = nullptr;
372 float x = 36;
373 float y = 36;
374 constexpr size_t kLineCount = SK_ARRAY_COUNT(kText);
375 constexpr int kLoopCount = 200;
376 SkFont font;
377 SkPaint paint;
378 for (int loop = 0; loop < kLoopCount; ++loop) {
379 for (size_t line = 0; line < kLineCount; ++line) {
380 y += font.getSpacing();
381 if (!canvas || y > 792 - 36) {
382 y = 36 + font.getSpacing();
383 canvas = doc->beginPage(612, 792);
384 background.notifyPixelsChanged();
385 canvas->drawBitmap(background, 0, 0);
386 }
387 canvas->drawString(kText[line], x, y, font, paint);
388 }
389 }
390 }
391
make_background()392 SkBitmap make_background() {
393 SkBitmap background;
394 SkBitmap bitmap;
395 bitmap.allocN32Pixels(32, 32);
396 bitmap.eraseColor(SK_ColorWHITE);
397 SkCanvas tmp(bitmap);
398 SkPaint gray;
399 gray.setColor(SkColorSetARGB(0xFF, 0xEE, 0xEE, 0xEE));
400 tmp.drawRect({0,0,16,16}, gray);
401 tmp.drawRect({16,16,32,32}, gray);
402 SkPaint shader;
403 shader.setShader(
404 SkShader::MakeBitmapShader(
405 bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
406 background.allocN32Pixels(612, 792);
407 SkCanvas tmp2(background);
408 tmp2.drawPaint(shader);
409 return background;
410 }
411
412 struct PDFBigDocBench : public Benchmark {
413 bool fFast;
414 SkBitmap fBackground;
415 std::unique_ptr<SkExecutor> fExecutor;
PDFBigDocBench__anon06586a2a0411::PDFBigDocBench416 PDFBigDocBench(bool fast) : fFast(fast) {}
onDelayedSetup__anon06586a2a0411::PDFBigDocBench417 void onDelayedSetup() override {
418 fBackground = make_background();
419 fExecutor = fFast ? SkExecutor::MakeFIFOThreadPool() : nullptr;
420 }
onGetName__anon06586a2a0411::PDFBigDocBench421 const char* onGetName() override {
422 static const char kNameFast[] = "PDFBigDocBench_fast";
423 static const char kNameSlow[] = "PDFBigDocBench_slow";
424 return fFast ? kNameFast : kNameSlow;
425 }
isSuitableFor__anon06586a2a0411::PDFBigDocBench426 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
onDraw__anon06586a2a0411::PDFBigDocBench427 void onDraw(int loops, SkCanvas*) override {
428 while (loops-- > 0) {
429 #ifdef SK_PDF_TEST_BIGDOCBENCH_OUTPUT
430 SkFILEWStream wStream("/tmp/big_pdf.pdf");
431 #else
432 SkNullWStream wStream;
433 #endif
434 SkPDF::Metadata metadata;
435 metadata.fExecutor = fExecutor.get();
436 auto doc = SkPDF::MakeDocument(&wStream, metadata);
437 big_pdf_test(doc.get(), fBackground);
438 }
439 }
440 };
441 } // namespace
442 DEF_BENCH(return new PDFBigDocBench(false);)
443 DEF_BENCH(return new PDFBigDocBench(true);)
444 #endif
445
446 #endif // SK_SUPPORT_PDF
447