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 "Benchmark.h"
9
10#include "Resources.h"
11#include "SkAutoPixmapStorage.h"
12#include "SkData.h"
13#include "SkFloatToDecimal.h"
14#include "SkGradientShader.h"
15#include "SkImage.h"
16#include "SkPixmap.h"
17#include "SkRandom.h"
18#include "SkStream.h"
19
20namespace {
21struct WStreamWriteTextBenchmark : public Benchmark {
22    std::unique_ptr<SkWStream> fWStream;
23    WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {}
24    const char* onGetName() override { return "WStreamWriteText"; }
25    bool isSuitableFor(Backend backend) override {
26        return backend == kNonRendering_Backend;
27    }
28    void onDraw(int loops, SkCanvas*) override {
29        while (loops-- > 0) {
30            for (int i = 1000; i-- > 0;) {
31                fWStream->writeText("HELLO SKIA!\n");
32            }
33        }
34    }
35};
36}  // namespace
37
38DEF_BENCH(return new WStreamWriteTextBenchmark;)
39
40// Test speed of SkFloatToDecimal for typical floats that
41// might be found in a PDF document.
42struct PDFScalarBench : public Benchmark {
43    bool isSuitableFor(Backend b) override {
44        return b == kNonRendering_Backend;
45    }
46    const char* onGetName() override { return "PDFScalar"; }
47    void onDraw(int loops, SkCanvas*) override {
48        SkRandom random;
49        char dst[kMaximumSkFloatToDecimalLength];
50        while (loops-- > 0) {
51            auto f = random.nextRangeF(-500.0f, 1500.0f);
52            (void)SkFloatToDecimal(f, dst);
53        }
54    }
55};
56
57DEF_BENCH(return new PDFScalarBench;)
58
59#ifdef SK_SUPPORT_PDF
60
61#include "SkPDFBitmap.h"
62#include "SkPDFDocument.h"
63#include "SkPDFShader.h"
64
65namespace {
66static void test_pdf_object_serialization(const sk_sp<SkPDFObject> object) {
67    // SkDebugWStream wStream;
68    SkNullWStream wStream;
69    SkPDFObjNumMap objNumMap;
70    objNumMap.addObjectRecursively(object.get());
71    for (int i = 0; i < objNumMap.objects().count(); ++i) {
72        SkPDFObject* object = objNumMap.objects()[i].get();
73        wStream.writeDecAsText(i + 1);
74        wStream.writeText(" 0 obj\n");
75        object->emitObject(&wStream, objNumMap);
76        wStream.writeText("\nendobj\n");
77    }
78}
79
80class PDFImageBench : public Benchmark {
81public:
82    PDFImageBench() {}
83    ~PDFImageBench() override {}
84
85protected:
86    const char* onGetName() override { return "PDFImage"; }
87    bool isSuitableFor(Backend backend) override {
88        return backend == kNonRendering_Backend;
89    }
90    void onDelayedSetup() override {
91        sk_sp<SkImage> img(GetResourceAsImage("images/color_wheel.png"));
92        if (img) {
93            // force decoding, throw away reference to encoded data.
94            SkAutoPixmapStorage pixmap;
95            pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions()));
96            if (img->readPixels(pixmap, 0, 0)) {
97                fImage = SkImage::MakeRasterCopy(pixmap);
98            }
99        }
100    }
101    void onDraw(int loops, SkCanvas*) override {
102        if (!fImage) {
103            return;
104        }
105        while (loops-- > 0) {
106            auto object = SkPDFCreateBitmapObject(fImage);
107            SkASSERT(object);
108            if (!object) {
109                return;
110            }
111            test_pdf_object_serialization(object);
112        }
113    }
114
115private:
116    sk_sp<SkImage> fImage;
117};
118
119class PDFJpegImageBench : public Benchmark {
120public:
121    PDFJpegImageBench() {}
122    ~PDFJpegImageBench() override {}
123
124protected:
125    const char* onGetName() override { return "PDFJpegImage"; }
126    bool isSuitableFor(Backend backend) override {
127        return backend == kNonRendering_Backend;
128    }
129    void onDelayedSetup() override {
130        sk_sp<SkImage> img(GetResourceAsImage("images/mandrill_512_q075.jpg"));
131        if (!img) { return; }
132        sk_sp<SkData> encoded = img->refEncodedData();
133        SkASSERT(encoded);
134        if (!encoded) { return; }
135        fImage = img;
136    }
137    void onDraw(int loops, SkCanvas*) override {
138        if (!fImage) {
139            SkDEBUGFAIL("");
140            return;
141        }
142        while (loops-- > 0) {
143            auto object = SkPDFCreateBitmapObject(fImage);
144            SkASSERT(object);
145            if (!object) {
146                return;
147            }
148            test_pdf_object_serialization(object);
149        }
150    }
151
152private:
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. */
158class PDFCompressionBench : public Benchmark {
159public:
160    PDFCompressionBench() {}
161    ~PDFCompressionBench() override {}
162
163protected:
164    const char* onGetName() override { return "PDFCompression"; }
165    bool isSuitableFor(Backend backend) override {
166        return backend == kNonRendering_Backend;
167    }
168    void onDelayedSetup() override {
169        fAsset = GetResourceAsStream("pdf_command_stream.txt");
170    }
171    void onDraw(int loops, SkCanvas*) override {
172        SkASSERT(fAsset);
173        if (!fAsset) { return; }
174        while (loops-- > 0) {
175            sk_sp<SkPDFObject> object =
176                sk_make_sp<SkPDFSharedStream>(
177                        std::unique_ptr<SkStreamAsset>(fAsset->duplicate()));
178            test_pdf_object_serialization(object);
179        }
180    }
181
182private:
183    std::unique_ptr<SkStreamAsset> fAsset;
184};
185
186struct PDFColorComponentBench : public Benchmark {
187    bool isSuitableFor(Backend b) override {
188        return b == kNonRendering_Backend;
189    }
190    const char* onGetName() override { return "PDFColorComponent"; }
191    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
201struct PDFShaderBench : public Benchmark {
202    sk_sp<SkShader> fShader;
203    const char* onGetName() final { return "PDFShader"; }
204    bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
205    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                SkShader::kClamp_TileMode);
214    }
215    void onDraw(int loops, SkCanvas*) final {
216        SkASSERT(fShader);
217        while (loops-- > 0) {
218            SkNullWStream nullStream;
219            SkPDFDocument doc(&nullStream, SkDocument::PDFMetadata());
220            sk_sp<SkPDFObject> shader = SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(),
221                                                        {0, 0, 400, 400}, SK_ColorBLACK);
222        }
223    }
224};
225
226struct WritePDFTextBenchmark : public Benchmark {
227    std::unique_ptr<SkWStream> fWStream;
228    WritePDFTextBenchmark() : fWStream(new SkNullWStream) {}
229    const char* onGetName() override { return "WritePDFText"; }
230    bool isSuitableFor(Backend backend) override {
231        return backend == kNonRendering_Backend;
232    }
233    void onDraw(int loops, SkCanvas*) override {
234        static const char kHello[] = "HELLO SKIA!\n";
235        static const char kBinary[] = "\001\002\003\004\005\006";
236        while (loops-- > 0) {
237            for (int i = 1000; i-- > 0;) {
238                SkPDFUtils::WriteString(fWStream.get(), kHello, strlen(kHello));
239                SkPDFUtils::WriteString(fWStream.get(), kBinary, strlen(kBinary));
240            }
241        }
242    }
243};
244
245}  // namespace
246DEF_BENCH(return new PDFImageBench;)
247DEF_BENCH(return new PDFJpegImageBench;)
248DEF_BENCH(return new PDFCompressionBench;)
249DEF_BENCH(return new PDFColorComponentBench;)
250DEF_BENCH(return new PDFShaderBench;)
251DEF_BENCH(return new WritePDFTextBenchmark;)
252
253#endif
254
255