/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Benchmark.h" #include "Resources.h" #include "SkAutoPixmapStorage.h" #include "SkData.h" #include "SkFloatToDecimal.h" #include "SkGradientShader.h" #include "SkImage.h" #include "SkPixmap.h" #include "SkRandom.h" #include "SkStream.h" #include "SkTo.h" namespace { struct WStreamWriteTextBenchmark : public Benchmark { std::unique_ptr fWStream; WStreamWriteTextBenchmark() : fWStream(new SkNullWStream) {} const char* onGetName() override { return "WStreamWriteText"; } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDraw(int loops, SkCanvas*) override { while (loops-- > 0) { for (int i = 1000; i-- > 0;) { fWStream->writeText("HELLO SKIA!\n"); } } } }; } // namespace DEF_BENCH(return new WStreamWriteTextBenchmark;) // Test speed of SkFloatToDecimal for typical floats that // might be found in a PDF document. struct PDFScalarBench : public Benchmark { PDFScalarBench(const char* n, float (*f)(SkRandom*)) : fName(n), fNextFloat(f) {} const char* fName; float (*fNextFloat)(SkRandom*); bool isSuitableFor(Backend b) override { return b == kNonRendering_Backend; } const char* onGetName() override { return fName; } void onDraw(int loops, SkCanvas*) override { SkRandom random; char dst[kMaximumSkFloatToDecimalLength]; while (loops-- > 0) { auto f = fNextFloat(&random); (void)SkFloatToDecimal(f, dst); } } }; float next_common(SkRandom* random) { return random->nextRangeF(-500.0f, 1500.0f); } float next_any(SkRandom* random) { union { uint32_t u; float f; }; u = random->nextU(); static_assert(sizeof(float) == sizeof(uint32_t), ""); return f; } DEF_BENCH(return new PDFScalarBench("PDFScalar_common", next_common);) DEF_BENCH(return new PDFScalarBench("PDFScalar_random", next_any);) #ifdef SK_SUPPORT_PDF #include "SkPDFBitmap.h" #include "SkPDFDocument.h" #include "SkPDFShader.h" namespace { static void test_pdf_object_serialization(const sk_sp object) { // SkDebugWStream wStream; SkNullWStream wStream; SkPDFObjNumMap objNumMap; objNumMap.addObjectRecursively(object.get()); for (int i = 0; i < objNumMap.objects().count(); ++i) { SkPDFObject* object = objNumMap.objects()[i].get(); wStream.writeDecAsText(i + 1); wStream.writeText(" 0 obj\n"); object->emitObject(&wStream, objNumMap); wStream.writeText("\nendobj\n"); } } class PDFImageBench : public Benchmark { public: PDFImageBench() {} ~PDFImageBench() override {} protected: const char* onGetName() override { return "PDFImage"; } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDelayedSetup() override { sk_sp img(GetResourceAsImage("images/color_wheel.png")); if (img) { // force decoding, throw away reference to encoded data. SkAutoPixmapStorage pixmap; pixmap.alloc(SkImageInfo::MakeN32Premul(img->dimensions())); if (img->readPixels(pixmap, 0, 0)) { fImage = SkImage::MakeRasterCopy(pixmap); } } } void onDraw(int loops, SkCanvas*) override { if (!fImage) { return; } while (loops-- > 0) { auto object = SkPDFCreateBitmapObject(fImage); SkASSERT(object); if (!object) { return; } test_pdf_object_serialization(object); } } private: sk_sp fImage; }; class PDFJpegImageBench : public Benchmark { public: PDFJpegImageBench() {} ~PDFJpegImageBench() override {} protected: const char* onGetName() override { return "PDFJpegImage"; } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDelayedSetup() override { sk_sp img(GetResourceAsImage("images/mandrill_512_q075.jpg")); if (!img) { return; } sk_sp encoded = img->refEncodedData(); SkASSERT(encoded); if (!encoded) { return; } fImage = img; } void onDraw(int loops, SkCanvas*) override { if (!fImage) { SkDEBUGFAIL(""); return; } while (loops-- > 0) { auto object = SkPDFCreateBitmapObject(fImage); SkASSERT(object); if (!object) { return; } test_pdf_object_serialization(object); } } private: sk_sp fImage; }; /** Test calling DEFLATE on a 78k PDF command stream. Used for measuring alternate zlib settings, usage, and library versions. */ class PDFCompressionBench : public Benchmark { public: PDFCompressionBench() {} ~PDFCompressionBench() override {} protected: const char* onGetName() override { return "PDFCompression"; } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDelayedSetup() override { fAsset = GetResourceAsStream("pdf_command_stream.txt"); } void onDraw(int loops, SkCanvas*) override { SkASSERT(fAsset); if (!fAsset) { return; } while (loops-- > 0) { sk_sp object = sk_make_sp( std::unique_ptr(fAsset->duplicate())); test_pdf_object_serialization(object); } } private: std::unique_ptr fAsset; }; struct PDFColorComponentBench : public Benchmark { bool isSuitableFor(Backend b) override { return b == kNonRendering_Backend; } const char* onGetName() override { return "PDFColorComponent"; } void onDraw(int loops, SkCanvas*) override { char dst[5]; while (loops-- > 0) { for (int i = 0; i < 256; ++i) { (void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst); } } } }; struct PDFShaderBench : public Benchmark { sk_sp fShader; const char* onGetName() final { return "PDFShader"; } bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; } void onDelayedSetup() final { const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}}; const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, }; fShader = SkGradientShader::MakeLinear( pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode); } void onDraw(int loops, SkCanvas*) final { SkASSERT(fShader); while (loops-- > 0) { SkNullWStream nullStream; SkPDFDocument doc(&nullStream, SkDocument::PDFMetadata()); sk_sp shader = SkPDFMakeShader(&doc, fShader.get(), SkMatrix::I(), {0, 0, 400, 400}, SK_ColorBLACK); } } }; struct WritePDFTextBenchmark : public Benchmark { std::unique_ptr fWStream; WritePDFTextBenchmark() : fWStream(new SkNullWStream) {} const char* onGetName() override { return "WritePDFText"; } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDraw(int loops, SkCanvas*) override { static const char kHello[] = "HELLO SKIA!\n"; static const char kBinary[] = "\001\002\003\004\005\006"; while (loops-- > 0) { for (int i = 1000; i-- > 0;) { SkPDFUtils::WriteString(fWStream.get(), kHello, strlen(kHello)); SkPDFUtils::WriteString(fWStream.get(), kBinary, strlen(kBinary)); } } } }; } // namespace DEF_BENCH(return new PDFImageBench;) DEF_BENCH(return new PDFJpegImageBench;) DEF_BENCH(return new PDFCompressionBench;) DEF_BENCH(return new PDFColorComponentBench;) DEF_BENCH(return new PDFShaderBench;) DEF_BENCH(return new WritePDFTextBenchmark;) #endif