Add timing SkCodec to nanobench.
CodecBench:
Add new class for timing using SkCodec.
DecodingBench:
Include creating a decoder inside the loop. This is to have a better
comparison against SkCodec. SkCodec's factory function does not
necessarily read the same amount as SkImageDecoder's, so in order to
have a meaningful comparison, read the entire stream from the
beginning. Also for comparison, create a new SkStream from the
SkData each time.
Add a debugging check to make sure we have an SkImageDecoder.
Add include guards.
nanobench.cpp:
Decode using SkCodec.
When decoding using SkImageDecoder, exclude benches where we decoded
to a different color type than requested. SkImageDecoder may decide to
decode to a different type, in which case the name is misleading.
TODOs:
Now that we ignore color types that do not match the desired
color type, we should add Index8. This also means calling the more
complex version of getPixels so CodecBench can support kIndex8.
BUG=skia:3257
Review URL: https://codereview.chromium.org/1044363002
diff --git a/bench/CodecBench.cpp b/bench/CodecBench.cpp
new file mode 100644
index 0000000..e68c5de
--- /dev/null
+++ b/bench/CodecBench.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "CodecBench.h"
+#include "SkBitmap.h"
+#include "SkCodec.h"
+#include "SkImageGenerator.h"
+#include "SkOSFile.h"
+
+CodecBench::CodecBench(SkString baseName, SkData* encoded, SkColorType colorType)
+ : fColorType(colorType)
+ , fData(SkRef(encoded))
+{
+ // Parse filename and the color type to give the benchmark a useful name
+ const char* colorName;
+ switch(colorType) {
+ case kN32_SkColorType:
+ colorName = "N32";
+ break;
+ case kRGB_565_SkColorType:
+ colorName = "565";
+ break;
+ case kAlpha_8_SkColorType:
+ colorName = "Alpha8";
+ break;
+ default:
+ colorName = "Unknown";
+ }
+ fName.printf("Codec_%s_%s", baseName.c_str(), colorName);
+#ifdef SK_DEBUG
+ // Ensure that we can create an SkCodec from this data.
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fData));
+ SkASSERT(codec);
+#endif
+}
+
+const char* CodecBench::onGetName() {
+ return fName.c_str();
+}
+
+bool CodecBench::isSuitableFor(Backend backend) {
+ return kNonRendering_Backend == backend;
+}
+
+void CodecBench::onPreDraw() {
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fData));
+ fBitmap.allocPixels(codec->getInfo().makeColorType(fColorType));
+}
+
+void CodecBench::onDraw(const int n, SkCanvas* canvas) {
+ SkAutoTDelete<SkCodec> codec;
+ for (int i = 0; i < n; i++) {
+ codec.reset(SkCodec::NewFromData(fData));
+#ifdef SK_DEBUG
+ const SkImageGenerator::Result result =
+#endif
+ // fBitmap.info() was set to use fColorType in onPreDraw.
+ codec->getPixels(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes());
+ SkASSERT(result == SkImageGenerator::kSuccess
+ || result == SkImageGenerator::kIncompleteInput);
+ }
+}
diff --git a/bench/CodecBench.h b/bench/CodecBench.h
new file mode 100644
index 0000000..2bc4ba9
--- /dev/null
+++ b/bench/CodecBench.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CodecBench_DEFINED
+#define CodecBench_DEFINED
+
+#include "Benchmark.h"
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkImageInfo.h"
+#include "SkRefCnt.h"
+#include "SkString.h"
+
+/**
+ * Time SkCodec.
+ */
+class CodecBench : public Benchmark {
+public:
+ // Calls encoded->ref()
+ CodecBench(SkString basename, SkData* encoded, SkColorType colorType);
+
+protected:
+ const char* onGetName() override;
+ bool isSuitableFor(Backend backend) override;
+ void onDraw(const int n, SkCanvas* canvas) override;
+ void onPreDraw() override;
+
+private:
+ SkString fName;
+ const SkColorType fColorType;
+ SkAutoTUnref<SkData> fData;
+ SkBitmap fBitmap;
+ typedef Benchmark INHERITED;
+};
+#endif // CodecBench_DEFINED
diff --git a/bench/DecodingBench.cpp b/bench/DecodingBench.cpp
index c8490ca..60535ce 100644
--- a/bench/DecodingBench.cpp
+++ b/bench/DecodingBench.cpp
@@ -8,7 +8,9 @@
#include "DecodingBench.h"
#include "SkData.h"
#include "SkImageDecoder.h"
+#include "SkMallocPixelRef.h"
#include "SkOSFile.h"
+#include "SkPixelRef.h"
#include "SkStream.h"
/*
@@ -19,6 +21,7 @@
*/
DecodingBench::DecodingBench(SkString path, SkColorType colorType)
: fColorType(colorType)
+ , fData(SkData::NewFromFileName(path.c_str()))
{
// Parse filename and the color type to give the benchmark a useful name
SkString baseName = SkOSPath::Basename(path.c_str());
@@ -38,10 +41,12 @@
}
fName.printf("Decode_%s_%s", baseName.c_str(), colorName);
- // Perform setup for the decode
- SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
- fStream.reset(new SkMemoryStream(encoded));
- fDecoder.reset(SkImageDecoder::Factory(fStream.get()));
+#ifdef SK_DEBUG
+ // Ensure that we can create a decoder.
+ SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData));
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
+ SkASSERT(decoder != NULL);
+#endif
}
const char* DecodingBench::onGetName() {
@@ -52,11 +57,53 @@
return kNonRendering_Backend == backend;
}
+void DecodingBench::onPreDraw() {
+ // Allocate the pixels now, to remove it from the loop.
+ SkAutoTDelete<SkStreamRewindable> stream(new SkMemoryStream(fData));
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
+#ifdef SK_DEBUG
+ SkImageDecoder::Result result =
+#endif
+ decoder->decode(stream, &fBitmap, fColorType,
+ SkImageDecoder::kDecodeBounds_Mode);
+ SkASSERT(SkImageDecoder::kFailure != result);
+ fBitmap.allocPixels(fBitmap.info());
+}
+
+// Allocator which just reuses the pixels from an existing SkPixelRef.
+class UseExistingAllocator : public SkBitmap::Allocator {
+public:
+ explicit UseExistingAllocator(SkPixelRef* pr)
+ : fPixelRef(SkRef(pr)) {}
+
+ bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) override {
+ // We depend on the fact that fPixelRef is an SkMallocPixelRef, which
+ // is always locked, and the fact that this will only ever be used to
+ // decode to a bitmap with the same settings used to create the
+ // original pixel ref.
+ bm->setPixelRef(SkMallocPixelRef::NewDirect(bm->info(),
+ fPixelRef->pixels(), bm->rowBytes(), ct))->unref();
+ return true;
+ }
+
+private:
+ SkAutoTUnref<SkPixelRef> fPixelRef;
+};
+
void DecodingBench::onDraw(const int n, SkCanvas* canvas) {
SkBitmap bitmap;
+ // Declare the allocator before the decoder, so it will outlive the
+ // decoder, which will unref it.
+ UseExistingAllocator allocator(fBitmap.pixelRef());
+ SkAutoTDelete<SkImageDecoder> decoder;
+ SkAutoTDelete<SkStreamRewindable> stream;
for (int i = 0; i < n; i++) {
- fStream->rewind();
- fDecoder->decode(fStream, &bitmap, fColorType,
- SkImageDecoder::kDecodePixels_Mode);
+ // create a new stream and a new decoder to mimic the behavior of
+ // CodecBench.
+ stream.reset(new SkMemoryStream(fData));
+ decoder.reset(SkImageDecoder::Factory(stream));
+ decoder->setAllocator(&allocator);
+ decoder->decode(stream, &bitmap, fColorType,
+ SkImageDecoder::kDecodePixels_Mode);
}
}
diff --git a/bench/DecodingBench.h b/bench/DecodingBench.h
index 80a474d..61b90a1 100644
--- a/bench/DecodingBench.h
+++ b/bench/DecodingBench.h
@@ -5,10 +5,15 @@
* found in the LICENSE file.
*/
+#ifndef DecodingBench_DEFINED
+#define DecodingBench_DEFINED
+
#include "Benchmark.h"
+#include "SkBitmap.h"
+#include "SkData.h"
#include "SkImageDecoder.h"
#include "SkImageInfo.h"
-#include "SkStream.h"
+#include "SkRefCnt.h"
#include "SkString.h"
/*
@@ -25,11 +30,13 @@
const char* onGetName() override;
bool isSuitableFor(Backend backend) override;
void onDraw(const int n, SkCanvas* canvas) override;
-
+ void onPreDraw() override;
+
private:
- SkString fName;
- SkColorType fColorType;
- SkAutoTDelete<SkMemoryStream> fStream;
- SkAutoTDelete<SkImageDecoder> fDecoder;
+ SkString fName;
+ SkColorType fColorType;
+ SkAutoTUnref<SkData> fData;
+ SkBitmap fBitmap;
typedef Benchmark INHERITED;
};
+#endif // DecodingBench_DEFINED
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 07600ef..a627b50 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -10,6 +10,7 @@
#include "nanobench.h"
#include "Benchmark.h"
+#include "CodecBench.h"
#include "CrashHandler.h"
#include "DecodingBench.h"
#include "DecodingSubsetBench.h"
@@ -23,6 +24,7 @@
#include "SkBBoxHierarchy.h"
#include "SkCanvas.h"
+#include "SkCodec.h"
#include "SkCommonFlags.h"
#include "SkData.h"
#include "SkForceLinking.h"
@@ -485,6 +487,7 @@
, fCurrentScale(0)
, fCurrentSKP(0)
, fCurrentUseMPD(0)
+ , fCurrentCodec(0)
, fCurrentImage(0)
, fCurrentSubsetImage(0)
, fCurrentColorType(0)
@@ -632,16 +635,57 @@
fCurrentScale++;
}
+ for (; fCurrentCodec < fImages.count(); fCurrentCodec++) {
+ const SkString& path = fImages[fCurrentCodec];
+ SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
+ SkASSERT(codec);
+ if (!codec) {
+ // Nothing to time.
+ continue;
+ }
+ while (fCurrentColorType < fColorTypes.count()) {
+ SkColorType colorType = fColorTypes[fCurrentColorType];
+ fCurrentColorType++;
+ // Make sure we can decode to this color type.
+ SkBitmap bitmap;
+ SkImageInfo info = codec->getInfo().makeColorType(colorType);
+ bitmap.allocPixels(info);
+ const SkImageGenerator::Result result = codec->getPixels(
+ bitmap.info(), bitmap.getPixels(), bitmap.rowBytes());
+ switch (result) {
+ case SkImageGenerator::kSuccess:
+ case SkImageGenerator::kIncompleteInput:
+ return new CodecBench(SkOSPath::Basename(path.c_str()),
+ encoded, colorType);
+ case SkImageGenerator::kInvalidConversion:
+ // This is okay. Not all conversions are valid.
+ break;
+ case SkImageGenerator::kCouldNotRewind:
+ // FIXME: This is due to a bug in some implementations
+ // of SkCodec. All should support rewinding.
+ break;
+ default:
+ // This represents some sort of failure.
+ SkASSERT(false);
+ break;
+ }
+ }
+ fCurrentColorType = 0;
+ }
+
// Run the DecodingBenches
while (fCurrentImage < fImages.count()) {
while (fCurrentColorType < fColorTypes.count()) {
const SkString& path = fImages[fCurrentImage];
SkColorType colorType = fColorTypes[fCurrentColorType];
fCurrentColorType++;
- // Check if the image decodes before creating the benchmark
+ // Check if the image decodes to the right color type
+ // before creating the benchmark
SkBitmap bitmap;
if (SkImageDecoder::DecodeFile(path.c_str(), &bitmap,
- colorType, SkImageDecoder::kDecodePixels_Mode)) {
+ colorType, SkImageDecoder::kDecodePixels_Mode)
+ && bitmap.colorType() == colorType) {
return new DecodingBench(path, colorType);
}
}
@@ -741,6 +785,7 @@
int fCurrentScale;
int fCurrentSKP;
int fCurrentUseMPD;
+ int fCurrentCodec;
int fCurrentImage;
int fCurrentSubsetImage;
int fCurrentColorType;