• 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/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