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