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/SkBitmap.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkExecutor.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkStream.h"
16 #include "include/effects/SkGradientShader.h"
17 #include "include/private/SkTo.h"
18 #include "include/utils/SkRandom.h"
19 #include "src/core/SkAutoPixmapStorage.h"
20 #include "src/pdf/SkPDFUnion.h"
21 #include "src/utils/SkFloatToDecimal.h"
22 #include "tools/Resources.h"
23
24 namespace {
25 struct WStreamWriteTextBenchmark : public Benchmark {
26 std::unique_ptr<SkWStream> fWStream;
WStreamWriteTextBenchmark__anon4fc58f200111::WStreamWriteTextBenchmark27 WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anon4fc58f200111::WStreamWriteTextBenchmark28 const char* onGetName() override { return "WStreamWriteText"; }
isSuitableFor__anon4fc58f200111::WStreamWriteTextBenchmark29 bool isSuitableFor(Backend backend) override {
30 return backend == kNonRendering_Backend;
31 }
onDraw__anon4fc58f200111::WStreamWriteTextBenchmark32 void onDraw(int loops, SkCanvas*) override {
33 while (loops-- > 0) {
34 for (int i = 1000; i-- > 0;) {
35 fWStream->writeText("HELLO SKIA!\n");
36 }
37 }
38 }
39 };
40 } // namespace
41
42 DEF_BENCH(return new WStreamWriteTextBenchmark;)
43
44 // Test speed of SkFloatToDecimal for typical floats that
45 // might be found in a PDF document.
46 struct PDFScalarBench : public Benchmark {
PDFScalarBenchPDFScalarBench47 PDFScalarBench(const char* n, float (*f)(SkRandom*)) : fName(n), fNextFloat(f) {}
48 const char* fName;
49 float (*fNextFloat)(SkRandom*);
isSuitableForPDFScalarBench50 bool isSuitableFor(Backend b) override {
51 return b == kNonRendering_Backend;
52 }
onGetNamePDFScalarBench53 const char* onGetName() override { return fName; }
onDrawPDFScalarBench54 void onDraw(int loops, SkCanvas*) override {
55 SkRandom random;
56 char dst[kMaximumSkFloatToDecimalLength];
57 while (loops-- > 0) {
58 auto f = fNextFloat(&random);
59 (void)SkFloatToDecimal(f, dst);
60 }
61 }
62 };
63
next_common(SkRandom * random)64 float next_common(SkRandom* random) {
65 return random->nextRangeF(-500.0f, 1500.0f);
66 }
next_any(SkRandom * random)67 float next_any(SkRandom* random) {
68 union { uint32_t u; float f; };
69 u = random->nextU();
70 static_assert(sizeof(float) == sizeof(uint32_t), "");
71 return f;
72 }
73
74 DEF_BENCH(return new PDFScalarBench("PDFScalar_common", next_common);)
75 DEF_BENCH(return new PDFScalarBench("PDFScalar_random", next_any);)
76
77 #ifdef SK_SUPPORT_PDF
78
79 #include "src/pdf/SkPDFBitmap.h"
80 #include "src/pdf/SkPDFDocumentPriv.h"
81 #include "src/pdf/SkPDFShader.h"
82 #include "src/pdf/SkPDFUtils.h"
83
84 namespace {
85 class PDFImageBench : public Benchmark {
86 public:
PDFImageBench()87 PDFImageBench() {}
~PDFImageBench()88 ~PDFImageBench() override {}
89
90 protected:
onGetName()91 const char* onGetName() override { return "PDFImage"; }
isSuitableFor(Backend backend)92 bool isSuitableFor(Backend backend) override {
93 return backend == kNonRendering_Backend;
94 }
onDelayedSetup()95 void onDelayedSetup() override {
96 sk_sp<SkImage> img(GetResourceAsImage("images/color_wheel.png"));
97 if (img) {
98 // force decoding, throw away reference to encoded data.
99 SkAutoPixmapStorage pixmap;
100 pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions()));
101 if (img->readPixels(nullptr, pixmap, 0, 0)) {
102 fImage = SkImage::MakeRasterCopy(pixmap);
103 }
104 }
105 }
onDraw(int loops,SkCanvas *)106 void onDraw(int loops, SkCanvas*) override {
107 if (!fImage) {
108 return;
109 }
110 while (loops-- > 0) {
111 SkNullWStream nullStream;
112 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
113 doc.beginPage(256, 256);
114 (void)SkPDFSerializeImage(fImage.get(), &doc);
115 }
116 }
117
118 private:
119 sk_sp<SkImage> fImage;
120 };
121
122 class PDFJpegImageBench : public Benchmark {
123 public:
PDFJpegImageBench()124 PDFJpegImageBench() {}
~PDFJpegImageBench()125 ~PDFJpegImageBench() override {}
126
127 protected:
onGetName()128 const char* onGetName() override { return "PDFJpegImage"; }
isSuitableFor(Backend backend)129 bool isSuitableFor(Backend backend) override {
130 return backend == kNonRendering_Backend;
131 }
onDelayedSetup()132 void onDelayedSetup() override {
133 sk_sp<SkImage> img(GetResourceAsImage("images/mandrill_512_q075.jpg"));
134 if (!img) { return; }
135 sk_sp<SkData> encoded = img->refEncodedData();
136 SkASSERT(encoded);
137 if (!encoded) { return; }
138 fImage = img;
139 }
onDraw(int loops,SkCanvas *)140 void onDraw(int loops, SkCanvas*) override {
141 if (!fImage) {
142 SkDEBUGFAIL("");
143 return;
144 }
145 while (loops-- > 0) {
146 SkNullWStream nullStream;
147 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
148 doc.beginPage(256, 256);
149 (void)SkPDFSerializeImage(fImage.get(), &doc);
150 }
151 }
152
153 private:
154 sk_sp<SkImage> fImage;
155 };
156
157 /** Test calling DEFLATE on a 78k PDF command stream. Used for measuring
158 alternate zlib settings, usage, and library versions. */
159 class PDFCompressionBench : public Benchmark {
160 public:
PDFCompressionBench()161 PDFCompressionBench() {}
~PDFCompressionBench()162 ~PDFCompressionBench() override {}
163
164 protected:
onGetName()165 const char* onGetName() override { return "PDFCompression"; }
isSuitableFor(Backend backend)166 bool isSuitableFor(Backend backend) override {
167 return backend == kNonRendering_Backend;
168 }
onDelayedSetup()169 void onDelayedSetup() override {
170 fAsset = GetResourceAsStream("pdf_command_stream.txt");
171 }
onDraw(int loops,SkCanvas *)172 void onDraw(int loops, SkCanvas*) override {
173 SkASSERT(fAsset);
174 if (!fAsset) { return; }
175 while (loops-- > 0) {
176 SkNullWStream wStream;
177 SkPDFDocument doc(&wStream, SkPDF::Metadata());
178 doc.beginPage(256, 256);
179 (void)SkPDFStreamOut(nullptr, fAsset->duplicate(), &doc, true);
180 }
181 }
182
183 private:
184 std::unique_ptr<SkStreamAsset> fAsset;
185 };
186
187 struct PDFColorComponentBench : public Benchmark {
isSuitableFor__anon4fc58f200311::PDFColorComponentBench188 bool isSuitableFor(Backend b) override {
189 return b == kNonRendering_Backend;
190 }
onGetName__anon4fc58f200311::PDFColorComponentBench191 const char* onGetName() override { return "PDFColorComponent"; }
onDraw__anon4fc58f200311::PDFColorComponentBench192 void onDraw(int loops, SkCanvas*) override {
193 char dst[5];
194 while (loops-- > 0) {
195 for (int i = 0; i < 256; ++i) {
196 (void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst);
197 }
198 }
199 }
200 };
201
202 struct PDFShaderBench : public Benchmark {
203 sk_sp<SkShader> fShader;
onGetName__anon4fc58f200311::PDFShaderBench204 const char* onGetName() final { return "PDFShader"; }
isSuitableFor__anon4fc58f200311::PDFShaderBench205 bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
onDelayedSetup__anon4fc58f200311::PDFShaderBench206 void onDelayedSetup() final {
207 const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}};
208 const SkColor colors[] = {
209 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
210 SK_ColorWHITE, SK_ColorBLACK,
211 };
212 fShader = SkGradientShader::MakeLinear(
213 pts, colors, nullptr, SK_ARRAY_COUNT(colors),
214 SkTileMode::kClamp);
215 }
onDraw__anon4fc58f200311::PDFShaderBench216 void onDraw(int loops, SkCanvas*) final {
217 SkASSERT(fShader);
218 while (loops-- > 0) {
219 SkNullWStream nullStream;
220 SkPDFDocument doc(&nullStream, SkPDF::Metadata());
221 doc.beginPage(256, 256);
222 (void) SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(),
223 {0, 0, 400, 400}, SkColors::kBlack);
224 }
225 }
226 };
227
228 struct WritePDFTextBenchmark : public Benchmark {
229 std::unique_ptr<SkWStream> fWStream;
WritePDFTextBenchmark__anon4fc58f200311::WritePDFTextBenchmark230 WritePDFTextBenchmark() : fWStream(new SkNullWStream) {}
onGetName__anon4fc58f200311::WritePDFTextBenchmark231 const char* onGetName() override { return "WritePDFText"; }
isSuitableFor__anon4fc58f200311::WritePDFTextBenchmark232 bool isSuitableFor(Backend backend) override {
233 return backend == kNonRendering_Backend;
234 }
onDraw__anon4fc58f200311::WritePDFTextBenchmark235 void onDraw(int loops, SkCanvas*) override {
236 static const char kHello[] = "HELLO SKIA!\n";
237 static const char kBinary[] = "\001\002\003\004\005\006";
238 while (loops-- > 0) {
239 for (int i = 1000; i-- > 0;) {
240 SkPDFWriteString(fWStream.get(), kHello, strlen(kHello));
241 SkPDFWriteString(fWStream.get(), kBinary, strlen(kBinary));
242 }
243 }
244 }
245 };
246
247 // Test for regression chromium:947381
248 // with 5c83ae81aa : 2364.99 microsec
249 // without 5c83ae81aa : 302821.78 microsec
250 struct PDFClipPathBenchmark : public Benchmark {
251 SkPath fPath;
onDelayedSetup__anon4fc58f200311::PDFClipPathBenchmark252 void onDelayedSetup() override {
253 SkBitmap bitmap;
254 bitmap.allocN32Pixels(256, 256);
255 bitmap.eraseColor(SK_ColorWHITE);
256 {
257 SkCanvas tmp(bitmap);
258 SkPaint paint;
259 paint.setAntiAlias(false);
260 paint.setStyle(SkPaint::kStroke_Style);
261 paint.setStrokeWidth(10);
262 for (int r : {20, 40, 60, 80, 100, 120}) {
263 tmp.drawCircle(128, 128, (float)r, paint);
264 }
265 }
266 fPath.reset();
267 for (int y = 0; y < 256; ++y) {
268 SkColor current = bitmap.getColor(0, y);
269 int start = 0;
270 for (int x = 0; x < 256; ++x) {
271 SkColor color = bitmap.getColor(x, y);
272 if (color == current) {
273 continue;
274 }
275 if (color == SK_ColorBLACK) {
276 start = x;
277 } else {
278 fPath.addRect(SkRect::Make(SkIRect{start, y, x, y + 1}));
279 }
280 current = color;
281 }
282 if (current == SK_ColorBLACK) {
283 fPath.addRect(SkRect::Make(SkIRect{start, y, 256, y + 1}));
284 }
285 }
286 }
onGetName__anon4fc58f200311::PDFClipPathBenchmark287 const char* onGetName() override { return "PDFClipPath"; }
isSuitableFor__anon4fc58f200311::PDFClipPathBenchmark288 bool isSuitableFor(Backend backend) override {
289 return backend == kNonRendering_Backend;
290 }
onDraw__anon4fc58f200311::PDFClipPathBenchmark291 void onDraw(int loops, SkCanvas*) override {
292 while (loops-- > 0) {
293 SkNullWStream wStream;
294 SkPDFDocument doc(&wStream, SkPDF::Metadata());
295 SkCanvas* canvas = doc.beginPage(256, 256);
296 canvas->clipPath(fPath);
297 canvas->translate(4.0f/3, 4.0f/3);
298 canvas->clipPath(fPath);
299 canvas->clear(SK_ColorRED);
300 doc.endPage();
301 }
302 }
303 };
304
305 } // namespace
306 DEF_BENCH(return new PDFImageBench;)
307 DEF_BENCH(return new PDFJpegImageBench;)
308 DEF_BENCH(return new PDFCompressionBench;)
309 DEF_BENCH(return new PDFColorComponentBench;)
310 DEF_BENCH(return new PDFShaderBench;)
311 DEF_BENCH(return new WritePDFTextBenchmark;)
312 DEF_BENCH(return new PDFClipPathBenchmark;)
313
314 #ifdef SK_PDF_ENABLE_SLOW_TESTS
315 #include "include/core/SkExecutor.h"
316 namespace {
big_pdf_test(SkDocument * doc,const SkBitmap & background)317 void big_pdf_test(SkDocument* doc, const SkBitmap& background) {
318 static const char* kText[] = {
319 "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do",
320 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad",
321 "minim veniam, quis nostrud exercitation ullamco laboris nisi ut",
322 "aliquip ex ea commodo consequat. Duis aute irure dolor in",
323 "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla",
324 "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in",
325 "culpa qui officia deserunt mollit anim id est laborum.",
326 "",
327 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
328 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
329 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
330 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
331 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
332 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
333 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
334 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
335 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
336 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
337 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
338 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
339 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
340 "pariatur?",
341 "",
342 "At vero eos et accusamus et iusto odio dignissimos ducimus, qui",
343 "blanditiis praesentium voluptatum deleniti atque corrupti, quos",
344 "dolores et quas molestias excepturi sint, obcaecati cupiditate non",
345 "provident, similique sunt in culpa, qui officia deserunt mollitia",
346 "animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis",
347 "est et expedita distinctio. Nam libero tempore, cum soluta nobis est",
348 "eligendi optio, cumque nihil impedit, quo minus id, quod maxime",
349 "placeat, facere possimus, omnis voluptas assumenda est, omnis dolor",
350 "repellendus. Temporibus autem quibusdam et aut officiis debitis aut",
351 "rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint",
352 "et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente",
353 "delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut",
354 "perferendis doloribus asperiores repellat",
355 "",
356 "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem",
357 "accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae",
358 "ab illo inventore veritatis et quasi architecto beatae vitae dicta",
359 "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit,",
360 "aspernatur aut odit aut fugit, sed quia consequuntur magni dolores",
361 "eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est,",
362 "qui dolorem ipsum, quia dolor sit amet consectetur adipiscing velit,",
363 "sed quia non numquam do eius modi tempora incididunt, ut labore et",
364 "dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,",
365 "quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi",
366 "ut aliquid ex ea commodi consequatur? Quis autem vel eum iure",
367 "reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae",
368 "consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla",
369 "pariatur?",
370 "",
371 };
372 SkCanvas* canvas = nullptr;
373 float x = 36;
374 float y = 36;
375 constexpr size_t kLineCount = SK_ARRAY_COUNT(kText);
376 constexpr int kLoopCount = 200;
377 SkFont font;
378 SkPaint paint;
379 for (int loop = 0; loop < kLoopCount; ++loop) {
380 for (size_t line = 0; line < kLineCount; ++line) {
381 y += font.getSpacing();
382 if (!canvas || y > 792 - 36) {
383 y = 36 + font.getSpacing();
384 canvas = doc->beginPage(612, 792);
385 background.notifyPixelsChanged();
386 canvas->drawBitmap(background, 0, 0);
387 }
388 canvas->drawString(kText[line], x, y, font, paint);
389 }
390 }
391 }
392
make_background()393 SkBitmap make_background() {
394 SkBitmap background;
395 SkBitmap bitmap;
396 bitmap.allocN32Pixels(32, 32);
397 bitmap.eraseColor(SK_ColorWHITE);
398 SkCanvas tmp(bitmap);
399 SkPaint gray;
400 gray.setColor(SkColorSetARGB(0xFF, 0xEE, 0xEE, 0xEE));
401 tmp.drawRect({0,0,16,16}, gray);
402 tmp.drawRect({16,16,32,32}, gray);
403 SkPaint shader;
404 shader.setShader(
405 SkShader::MakeBitmapShader(
406 bitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
407 background.allocN32Pixels(612, 792);
408 SkCanvas tmp2(background);
409 tmp2.drawPaint(shader);
410 return background;
411 }
412
413 struct PDFBigDocBench : public Benchmark {
414 bool fFast;
415 SkBitmap fBackground;
416 std::unique_ptr<SkExecutor> fExecutor;
PDFBigDocBench__anon4fc58f200411::PDFBigDocBench417 PDFBigDocBench(bool fast) : fFast(fast) {}
onDelayedSetup__anon4fc58f200411::PDFBigDocBench418 void onDelayedSetup() override {
419 fBackground = make_background();
420 fExecutor = fFast ? SkExecutor::MakeFIFOThreadPool() : nullptr;
421 }
onGetName__anon4fc58f200411::PDFBigDocBench422 const char* onGetName() override {
423 static const char kNameFast[] = "PDFBigDocBench_fast";
424 static const char kNameSlow[] = "PDFBigDocBench_slow";
425 return fFast ? kNameFast : kNameSlow;
426 }
isSuitableFor__anon4fc58f200411::PDFBigDocBench427 bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
onDraw__anon4fc58f200411::PDFBigDocBench428 void onDraw(int loops, SkCanvas*) override {
429 while (loops-- > 0) {
430 #ifdef SK_PDF_TEST_BIGDOCBENCH_OUTPUT
431 SkFILEWStream wStream("/tmp/big_pdf.pdf");
432 #else
433 SkNullWStream wStream;
434 #endif
435 SkPDF::Metadata metadata;
436 metadata.fExecutor = fExecutor.get();
437 auto doc = SkPDF::MakeDocument(&wStream, metadata);
438 big_pdf_test(doc.get(), fBackground);
439 }
440 }
441 };
442 } // namespace
443 DEF_BENCH(return new PDFBigDocBench(false);)
444 DEF_BENCH(return new PDFBigDocBench(true);)
445 #endif
446
447 #endif // SK_SUPPORT_PDF
448