• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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