diff options
author | scroggo <scroggo@google.com> | 2015-10-08 12:01:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-08 12:01:39 -0700 |
commit | ab12c2715886e7f04c415028a7db49fb0b1e67f3 (patch) | |
tree | 11fadb9c46bf034ae7824da722aaba77983036b7 /bench | |
parent | 33366974d43eae80e22284a2e445225c343859da (diff) |
Update Subset benches to support interlacing and fix bugs
Instead of decoding one line at a time, if the ScanlineOrder is kNone,
decode all of the lines in one pass, and then copy the subset into the
output. This will allow us to more realistically test subset decodes
for interlaced png. It also makes running them not take forever.
Do *not* support other modes (besides kTopDown), since they are not
used by the big three we need to replace BitmapRegionDecoder
implementation (skbug.com/4428).
Fix a bug in SubsetTranslateBench and SubsetZoomBench:
When we decode another subset, we need to reset the scanline decode
first. This bug appears to have been present since the introduction of
these tests in crrev.com/1160953002
BUG=skia:4205
BUG=skia:3418
Review URL: https://codereview.chromium.org/1387233002
Diffstat (limited to 'bench')
-rw-r--r-- | bench/nanobench.cpp | 27 | ||||
-rw-r--r-- | bench/subset/SubsetSingleBench.cpp | 53 | ||||
-rw-r--r-- | bench/subset/SubsetTranslateBench.cpp | 69 | ||||
-rw-r--r-- | bench/subset/SubsetZoomBench.cpp | 56 |
4 files changed, 175 insertions, 30 deletions
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index 4ab6ca0b88..b16fb13b57 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -501,6 +501,27 @@ static Target* is_enabled(Benchmark* bench, const Config& config) { } /* + * We only run our subset benches on files that are supported by BitmapRegionDecoder: + * i.e. PNG, JPEG, and WEBP. We do *not* test WEBP when using codec, since we do not + * have a scanline decoder for WEBP, which is necessary for running the subset bench. + * (Another bench must be used to test WEBP, which decodes subsets natively.) + */ +static bool run_subset_bench(const SkString& path, bool useCodec) { + static const char* const exts[] = { + "jpg", "jpeg", "png", + "JPG", "JPEG", "PNG", + }; + + for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { + if (path.endsWith(exts[i])) { + return true; + } + } + + return !useCodec && (path.endsWith("webp") || path.endsWith("WEBP")); +} + +/* * Returns true if set up for a subset decode succeeds, false otherwise * If the set-up succeeds, the width and height parameters will be set */ @@ -872,8 +893,12 @@ public: fSourceType = "image"; fBenchType = useCodec ? "skcodec" : "skimagedecoder"; while (fCurrentSubsetImage < fImages.count()) { + const SkString& path = fImages[fCurrentSubsetImage]; + if (!run_subset_bench(path, useCodec)) { + fCurrentSubsetImage++; + continue; + } while (fCurrentColorType < fColorTypes.count()) { - const SkString& path = fImages[fCurrentSubsetImage]; SkColorType colorType = fColorTypes[fCurrentColorType]; while (fCurrentSubsetType <= kLast_SubsetType) { int width = 0; diff --git a/bench/subset/SubsetSingleBench.cpp b/bench/subset/SubsetSingleBench.cpp index 232c159a0b..735effa100 100644 --- a/bench/subset/SubsetSingleBench.cpp +++ b/bench/subset/SubsetSingleBench.cpp @@ -66,30 +66,65 @@ void SubsetSingleBench::onDraw(int n, SkCanvas* canvas) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); - SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]); + + SkDEBUGCODE(SkCodec::Result result =) codec->startScanlineDecode(info, nullptr, colors, &colorCount); + SkASSERT(result == SkCodec::kSuccess); SkBitmap bitmap; SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight); alloc_pixels(&bitmap, subsetInfo, colors, colorCount); - codec->skipScanlines(fOffsetTop); - uint32_t bpp = info.bytesPerPixel(); - for (uint32_t y = 0; y < fSubsetHeight; y++) { - codec->getScanlines(row.get(), 1, 0); - memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * bpp, - fSubsetWidth * bpp); + SkDEBUGCODE(result = ) codec->skipScanlines(fOffsetTop); + SkASSERT(result == SkCodec::kSuccess); + + const uint32_t bpp = info.bytesPerPixel(); + + switch (codec->getScanlineOrder()) { + case SkCodec::kTopDown_SkScanlineOrder: { + SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]); + for (uint32_t y = 0; y < fSubsetHeight; y++) { + SkDEBUGCODE(result = ) codec->getScanlines(row.get(), 1, 0); + SkASSERT(result == SkCodec::kSuccess); + + memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * bpp, + fSubsetWidth * bpp); + } + break; + } + case SkCodec::kNone_SkScanlineOrder: { + // decode all scanlines that intersect the subset, and copy the subset + // into the output. + SkImageInfo stripeInfo = info.makeWH(info.width(), fSubsetHeight); + SkBitmap stripeBm; + alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); + + SkDEBUGCODE(result = ) codec->getScanlines(stripeBm.getPixels(), fSubsetHeight, + stripeBm.rowBytes()); + SkASSERT(result == SkCodec::kSuccess); + + for (uint32_t y = 0; y < fSubsetHeight; y++) { + memcpy(bitmap.getAddr(0, y), stripeBm.getAddr(fOffsetLeft, y), + fSubsetWidth * bpp); + } + break; + } + default: + // We currently are only testing kTopDown and kNone, which are the only + // two used by the subsets we care about. skbug.com/4428 + SkASSERT(false); + } } } else { for (int count = 0; count < n; count++) { SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); int width, height; - decoder->buildTileIndex(fStream->duplicate(), &width, &height); + SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height)); SkBitmap bitmap; SkIRect rect = SkIRect::MakeXYWH(fOffsetLeft, fOffsetTop, fSubsetWidth, fSubsetHeight); - decoder->decodeSubset(&bitmap, rect, fColorType); + SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType)); } } } diff --git a/bench/subset/SubsetTranslateBench.cpp b/bench/subset/SubsetTranslateBench.cpp index 8f29ba8fa0..d13f31a86d 100644 --- a/bench/subset/SubsetTranslateBench.cpp +++ b/bench/subset/SubsetTranslateBench.cpp @@ -53,17 +53,29 @@ bool SubsetTranslateBench::isSuitableFor(Backend backend) { return kNonRendering_Backend == backend; } +// Allows allocating the bitmap first, and then writing to them later (in startScanlineDecode) +static SkPMColor* get_colors(SkBitmap* bm) { + SkColorTable* ct = bm->getColorTable(); + if (!ct) { + return nullptr; + } + + return const_cast<SkPMColor*>(ct->readColors()); +} + void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { // When the color type is kIndex8, we will need to store the color table. If it is // used, it will be initialized by the codec. - int colorCount; + int colorCount = 256; SkPMColor colors[256]; if (fUseCodec) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); - SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]); - codec->startScanlineDecode(info, nullptr, colors, &colorCount); + SkAutoTDeleteArray<uint8_t> row(nullptr); + if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) { + row.reset(new uint8_t[info.minRowBytes()]); + } SkBitmap bitmap; // Note that we use the same bitmap for all of the subsets. @@ -71,20 +83,55 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight); alloc_pixels(&bitmap, subsetInfo, colors, colorCount); + const uint32_t bpp = info.bytesPerPixel(); + for (int x = 0; x < info.width(); x += fSubsetWidth) { for (int y = 0; y < info.height(); y += fSubsetHeight) { - codec->skipScanlines(y); + SkDEBUGCODE(SkCodec::Result result =) + codec->startScanlineDecode(info, nullptr, get_colors(&bitmap), &colorCount); + SkASSERT(SkCodec::kSuccess == result); + + SkDEBUGCODE(result =) codec->skipScanlines(y); + SkASSERT(SkCodec::kSuccess == result); + const uint32_t currSubsetWidth = x + (int) fSubsetWidth > info.width() ? info.width() - x : fSubsetWidth; const uint32_t currSubsetHeight = y + (int) fSubsetHeight > info.height() ? info.height() - y : fSubsetHeight; - const uint32_t bpp = info.bytesPerPixel(); - for (uint32_t y = 0; y < currSubsetHeight; y++) { - codec->getScanlines(row.get(), 1, 0); - memcpy(bitmap.getAddr(0, y), row.get() + x * bpp, - currSubsetWidth * bpp); + + switch (codec->getScanlineOrder()) { + case SkCodec::kTopDown_SkScanlineOrder: + for (uint32_t y = 0; y < currSubsetHeight; y++) { + SkDEBUGCODE(result =) codec->getScanlines(row.get(), 1, 0); + SkASSERT(SkCodec::kSuccess == result); + + memcpy(bitmap.getAddr(0, y), row.get() + x * bpp, + currSubsetWidth * bpp); + } + break; + case SkCodec::kNone_SkScanlineOrder: { + // decode all scanlines that intersect the subset, and copy the subset + // into the output. + SkImageInfo stripeInfo = info.makeWH(info.width(), currSubsetHeight); + SkBitmap stripeBm; + alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); + + SkDEBUGCODE(result =) codec->getScanlines(stripeBm.getPixels(), + currSubsetHeight, stripeBm.rowBytes()); + SkASSERT(SkCodec::kSuccess == result); + + for (uint32_t subsetY = 0; subsetY < currSubsetHeight; subsetY++) { + memcpy(bitmap.getAddr(0, subsetY), stripeBm.getAddr(x, subsetY), + currSubsetWidth * bpp); + } + break; + } + default: + // We currently are only testing kTopDown and kNone, which are the only + // two used by the subsets we care about. skbug.com/4428 + SkASSERT(false); } } } @@ -97,7 +144,7 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { for (int count = 0; count < n; count++) { int width, height; SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); - decoder->buildTileIndex(fStream->duplicate(), &width, &height); + SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height)); SkBitmap bitmap; // Note that we use the same bitmap for all of the subsets. // It might be larger than necessary for the end subsets. @@ -117,7 +164,7 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { height - y : fSubsetHeight; SkIRect rect = SkIRect::MakeXYWH(x, y, currSubsetWidth, currSubsetHeight); - decoder->decodeSubset(&bitmap, rect, fColorType); + SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType)); } } } diff --git a/bench/subset/SubsetZoomBench.cpp b/bench/subset/SubsetZoomBench.cpp index ffd86703ec..901fbb6082 100644 --- a/bench/subset/SubsetZoomBench.cpp +++ b/bench/subset/SubsetZoomBench.cpp @@ -62,14 +62,20 @@ void SubsetZoomBench::onDraw(int n, SkCanvas* canvas) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); - SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]); - codec->startScanlineDecode(info, nullptr, colors, &colorCount); + SkAutoTDeleteArray<uint8_t> row(nullptr); + if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) { + row.reset(new uint8_t[info.minRowBytes()]); + } const int centerX = info.width() / 2; const int centerY = info.height() / 2; int w = fSubsetWidth; int h = fSubsetHeight; do { + SkDEBUGCODE(SkCodec::Result result = ) + codec->startScanlineDecode(info, nullptr, colors, &colorCount); + SkASSERT(SkCodec::kSuccess == result); + const int subsetStartX = SkTMax(0, centerX - w / 2); const int subsetStartY = SkTMax(0, centerY - h / 2); const int subsetWidth = SkTMin(w, info.width() - subsetStartX); @@ -81,12 +87,44 @@ void SubsetZoomBench::onDraw(int n, SkCanvas* canvas) { alloc_pixels(&bitmap, subsetInfo, colors, colorCount); uint32_t bpp = info.bytesPerPixel(); - codec->skipScanlines(subsetStartY); - for (int y = 0; y < subsetHeight; y++) { - codec->getScanlines(row.get(), 1, 0); - memcpy(bitmap.getAddr(0, y), row.get() + subsetStartX * bpp, - subsetWidth * bpp); + + SkDEBUGCODE(result = ) codec->skipScanlines(subsetStartY); + SkASSERT(SkCodec::kSuccess == result); + + switch (codec->getScanlineOrder()) { + case SkCodec::kTopDown_SkScanlineOrder: + for (int y = 0; y < subsetHeight; y++) { + SkDEBUGCODE(result = ) codec->getScanlines(row.get(), 1, 0); + SkASSERT(SkCodec::kSuccess == result); + + memcpy(bitmap.getAddr(0, y), row.get() + subsetStartX * bpp, + subsetWidth * bpp); + } + break; + case SkCodec::kNone_SkScanlineOrder: { + // decode all scanlines that intersect the subset, and copy the subset + // into the output. + SkImageInfo stripeInfo = info.makeWH(info.width(), subsetHeight); + SkBitmap stripeBm; + alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); + + SkDEBUGCODE(result = ) codec->getScanlines(stripeBm.getPixels(), + subsetHeight, stripeBm.rowBytes()); + SkASSERT(SkCodec::kSuccess == result); + + for (int y = 0; y < subsetHeight; y++) { + memcpy(bitmap.getAddr(0, y), + stripeBm.getAddr(subsetStartX, y), + subsetWidth * bpp); + } + break; + } + default: + // We currently are only testing kTopDown and kNone, which are the only + // two used by the subsets we care about. skbug.com/4428 + SkASSERT(false); } + w <<= 1; h <<= 1; } while (w < 2 * info.width() || h < 2 * info.height()); @@ -95,7 +133,7 @@ void SubsetZoomBench::onDraw(int n, SkCanvas* canvas) { for (int count = 0; count < n; count++) { int width, height; SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); - decoder->buildTileIndex(fStream->duplicate(), &width, &height); + SkAssertResult(decoder->buildTileIndex(fStream->duplicate(), &width, &height)); const int centerX = width / 2; const int centerY = height / 2; @@ -109,7 +147,7 @@ void SubsetZoomBench::onDraw(int n, SkCanvas* canvas) { SkBitmap bitmap; SkIRect rect = SkIRect::MakeXYWH(subsetStartX, subsetStartY, subsetWidth, subsetHeight); - decoder->decodeSubset(&bitmap, rect, fColorType); + SkAssertResult(decoder->decodeSubset(&bitmap, rect, fColorType)); w <<= 1; h <<= 1; } while (w < 2 * width || h < 2 * height); |