Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2015 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 "CodecSubsetBench.h" | |
| 9 #include "SkData.h" | |
| 10 #include "SkCodec.h" | |
| 11 #include "SkImageDecoder.h" | |
| 12 #include "SkOSFile.h" | |
| 13 #include "SkStream.h" | |
| 14 | |
| 15 /* | |
| 16 * | |
| 17 * This benchmark is designed to test the performance of subset decoding. | |
| 18 * | |
| 19 */ | |
| 20 CodecSubsetBench::CodecSubsetBench(SkString* path, | |
| 21 SubsetMode subsetMode, | |
| 22 SkColorType colorType, | |
| 23 uint32_t subsetWidth, | |
| 24 uint32_t subsetHeight, | |
| 25 uint32_t offsetLeft, | |
| 26 uint32_t offsetTop, | |
| 27 uint32_t divisor, | |
| 28 bool useCodec) | |
| 29 : fSubsetMode(subsetMode) | |
| 30 , fColorType(colorType) | |
| 31 , fSubsetWidth(subsetWidth) | |
| 32 , fSubsetHeight(subsetHeight) | |
| 33 , fOffsetLeft(offsetLeft) | |
| 34 , fOffsetTop(offsetTop) | |
| 35 , fDivisor(divisor) | |
| 36 , fUseCodec(useCodec) | |
| 37 { | |
| 38 // Parse the filename | |
| 39 SkString baseName = SkOSPath::Basename(path->c_str()); | |
| 40 | |
| 41 // Choose an informative subset mode name | |
| 42 SkString modeName; | |
| 43 switch(fSubsetMode) { | |
| 44 case kSingle_SubsetMode: | |
| 45 SkASSERT(0 == divisor); | |
| 46 modeName.printf("Single_%dx%d +%d_+%d", fSubsetWidth, fSubsetHeight, fOffsetLeft, | |
| 47 fOffsetTop); | |
| 48 break; | |
| 49 case kDivisor_SubsetMode: | |
| 50 SkASSERT(0 == subsetWidth); | |
| 51 SkASSERT(0 == subsetHeight); | |
| 52 SkASSERT(0 == offsetLeft); | |
| 53 SkASSERT(0 == offsetTop); | |
| 54 modeName.printf("Divisor_%dx%d", fDivisor, fDivisor); | |
| 55 break; | |
| 56 case kTranslate_SubsetMode: | |
| 57 SkASSERT(0 == divisor); | |
| 58 SkASSERT(0 == offsetLeft); | |
| 59 SkASSERT(0 == offsetTop); | |
| 60 modeName.printf("Size_%dx%d", fSubsetWidth, fSubsetHeight); | |
| 61 break; | |
| 62 case kScale_SubsetMode: | |
| 63 SkASSERT(0 == divisor); | |
| 64 SkASSERT(0 == offsetLeft); | |
| 65 SkASSERT(0 == offsetTop); | |
| 66 modeName.printf("Scale_%dx%d", fSubsetWidth, fSubsetHeight); | |
| 67 break; | |
| 68 } | |
| 69 | |
| 70 // Choose an informative color name | |
| 71 const char* colorName; | |
| 72 switch(fColorType) { | |
|
scroggo
2015/05/29 15:36:02
What about kIndex8?
msarett
2015/06/01 14:03:25
Agreed!
| |
| 73 case kN32_SkColorType: | |
| 74 colorName = "N32"; | |
| 75 break; | |
| 76 case kRGB_565_SkColorType: | |
| 77 colorName = "565"; | |
| 78 break; | |
| 79 case kGray_8_SkColorType: | |
| 80 colorName = "Gray8"; | |
| 81 break; | |
| 82 case kAlpha_8_SkColorType: | |
| 83 colorName = "Alpha8"; | |
| 84 break; | |
| 85 default: | |
| 86 colorName = "Unknown"; | |
| 87 } | |
| 88 fName.printf("%sSubset%s_%s_%s", fUseCodec ? "Codec" : "Image", modeName.c_s tr(), | |
| 89 baseName.c_str(), colorName); | |
| 90 | |
| 91 // Perform the decode setup | |
| 92 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path->c_str())); | |
| 93 fStream.reset(new SkMemoryStream(encoded)); | |
| 94 } | |
| 95 | |
| 96 const char* CodecSubsetBench::onGetName() { | |
| 97 return fName.c_str(); | |
| 98 } | |
| 99 | |
| 100 bool CodecSubsetBench::isSuitableFor(Backend backend) { | |
| 101 return kNonRendering_Backend == backend; | |
| 102 } | |
| 103 | |
| 104 void CodecSubsetBench::onDraw(const int n, SkCanvas* canvas) { | |
| 105 // Choose a different benchmark depending on the mode | |
| 106 switch(fSubsetMode) { | |
|
scroggo
2015/05/29 15:36:02
This giant switch statement might argue for using
msarett
2015/06/01 14:03:25
Agreed.
| |
| 107 case kSingle_SubsetMode: | |
| 108 if (fUseCodec) { | |
| 109 for (int count = 0; count < n; count++) { | |
| 110 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream- >duplicate())); | |
| 111 const SkImageInfo info = codec->getInfo(); | |
| 112 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.mi nRowBytes())); | |
| 113 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecod er(info); | |
| 114 | |
| 115 SkBitmap bitmap; | |
| 116 if (!bitmap.tryAllocPixels(info.makeWH(fSubsetWidth, fSubset Height))) { | |
| 117 SkDebugf("Could not allocate memory. Aborting bench.\n" ); | |
| 118 return; | |
| 119 } | |
| 120 | |
| 121 scanlineDecoder->skipScanlines(fOffsetTop); | |
| 122 uint32_t bpp = info.bytesPerPixel(); | |
| 123 for (uint32_t y = 0; y < fSubsetHeight; y++) { | |
| 124 scanlineDecoder->getScanlines(row.get(), 1, 0); | |
| 125 memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * b pp, | |
| 126 fSubsetWidth * bpp); | |
| 127 } | |
| 128 } | |
| 129 } else { | |
| 130 for (int count = 0; count < n; count++) { | |
| 131 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factor y(fStream)); | |
| 132 int width, height; | |
| 133 decoder->buildTileIndex(fStream->duplicate(), &width, &heigh t); | |
|
scroggo
2015/05/29 15:36:02
Do we need to safely early exit in case buildTileI
msarett
2015/06/01 14:03:24
Let's check that the decode succeeds before creati
| |
| 134 SkBitmap bitmap; | |
| 135 SkIRect rect = SkIRect::MakeXYWH(fOffsetLeft, fOffsetTop, fS ubsetWidth, | |
| 136 fSubsetHeight); | |
| 137 decoder->decodeSubset(&bitmap, rect, fColorType); | |
| 138 } | |
| 139 } | |
| 140 break; | |
| 141 case kDivisor_SubsetMode: | |
| 142 if (fUseCodec) { | |
| 143 for (int count = 0; count < n; count++) { | |
| 144 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream- >duplicate())); | |
| 145 const SkImageInfo info = codec->getInfo(); | |
| 146 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.mi nRowBytes())); | |
| 147 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecod er(info); | |
| 148 | |
| 149 uint32_t subsetWidth = info.width() / fDivisor; | |
|
scroggo
2015/05/29 15:36:02
These variables could all be const?
msarett
2015/06/01 14:03:25
Done.
| |
| 150 uint32_t subsetHeight = info.height() / fDivisor; | |
| 151 uint32_t maxSubsetWidth = subsetWidth + info.width() % fDivi sor; | |
| 152 uint32_t maxSubsetHeight = subsetHeight + info.height() % fD ivisor; | |
| 153 SkBitmap bitmap; | |
| 154 // Note that we use the same bitmap for all of the subsets. | |
| 155 // It might be slightly larger than necessary for some of th e subsets. | |
| 156 if (!bitmap.tryAllocPixels(info.makeWH(maxSubsetWidth, maxSu bsetHeight))) { | |
| 157 SkDebugf("Could not allocate memory. Aborting bench.\n" ); | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 for (uint32_t blockX = 0; blockX < fDivisor; blockX++) { | |
| 162 for (uint32_t blockY = 0; blockY < fDivisor; blockY++) { | |
| 163 scanlineDecoder->skipScanlines(blockY * subsetHeight ); | |
| 164 uint32_t currSubsetWidth = | |
| 165 (blockX == fDivisor - 1) ? maxSubsetWidth : subsetWidth; | |
| 166 uint32_t currSubsetHeight = | |
| 167 (blockY == fDivisor - 1) ? maxSubsetHeight : subsetHeight; | |
| 168 uint32_t bpp = info.bytesPerPixel(); | |
| 169 for (uint32_t y = 0; y < currSubsetHeight; y++) { | |
| 170 scanlineDecoder->getScanlines(row.get(), 1, 0); | |
| 171 memcpy(bitmap.getAddr(0, y), row.get() + fOffset Left * bpp, | |
| 172 currSubsetWidth * bpp); | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 } else { | |
| 178 for (int count = 0; count < n; count++) { | |
| 179 int width, height; | |
| 180 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factor y(fStream)); | |
| 181 decoder->buildTileIndex(fStream->duplicate(), &width, &heigh t); | |
| 182 | |
| 183 uint32_t subsetWidth = width / fDivisor; | |
| 184 uint32_t subsetHeight = height / fDivisor; | |
| 185 uint32_t maxSubsetWidth = subsetWidth + width % fDivisor; | |
| 186 uint32_t maxSubsetHeight = subsetHeight + height % fDivisor; | |
| 187 SkBitmap bitmap; | |
| 188 // Note that we use the same bitmap for all of the subsets. | |
| 189 // It might be slightly larger than necessary for some of th e subsets. | |
| 190 if (!bitmap.tryAllocPixels(SkImageInfo::Make(maxSubsetWidth, maxSubsetHeight, | |
|
scroggo
2015/05/29 15:36:02
When using SkImageDecoder, you don't need to alloc
msarett
2015/06/01 14:03:24
The reason I allocate here is so that SkImageDecod
scroggo
2015/06/01 17:25:14
Got it. We talked about this in person and you con
msarett
2015/06/01 20:37:01
Done.
| |
| 191 fColorType, kOpaque_SkAlphaType))) { | |
| 192 SkDebugf("Could not allocate memory. Aborting bench.\n" ); | |
| 193 return; | |
| 194 } | |
| 195 | |
| 196 for (uint32_t blockX = 0; blockX < fDivisor; blockX++) { | |
| 197 for (uint32_t blockY = 0; blockY < fDivisor; blockY++) { | |
| 198 uint32_t currSubsetWidth = | |
| 199 (blockX == fDivisor - 1) ? maxSubsetWidth : subsetWidth; | |
| 200 uint32_t currSubsetHeight = | |
| 201 (blockY == fDivisor - 1) ? maxSubsetHeight : subsetHeight; | |
| 202 SkIRect rect = SkIRect::MakeXYWH(blockX * subsetWidt h, | |
| 203 blockY * subsetHeight, currSubsetWidth, curr SubsetHeight); | |
| 204 decoder->decodeSubset(&bitmap, rect, fColorType); | |
| 205 } | |
| 206 } | |
| 207 } | |
| 208 } | |
| 209 break; | |
| 210 case kTranslate_SubsetMode: | |
| 211 if (fUseCodec) { | |
| 212 for (int count = 0; count < n; count++) { | |
| 213 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream- >duplicate())); | |
| 214 const SkImageInfo info = codec->getInfo(); | |
| 215 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.mi nRowBytes())); | |
| 216 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecod er(info); | |
| 217 | |
| 218 SkBitmap bitmap; | |
| 219 // Note that we use the same bitmap for all of the subsets. | |
| 220 // It might be larger than necessary for the end subsets. | |
| 221 if (!bitmap.tryAllocPixels(info.makeWH(fSubsetWidth, fSubset Height))) { | |
| 222 SkDebugf("Could not allocate memory. Aborting bench.\n" ); | |
| 223 return; | |
| 224 } | |
| 225 | |
| 226 for (int x = 0; x < info.width(); x += fSubsetWidth) { | |
| 227 for (int y = 0; y < info.height(); y += fSubsetHeight) { | |
| 228 scanlineDecoder->skipScanlines(y); | |
| 229 uint32_t currSubsetWidth = x + (int) fSubsetWidth > info.width() ? | |
| 230 info.width() - x : fSubsetWidth; | |
| 231 uint32_t currSubsetHeight = y + (int) fSubsetHeight > info.height() ? | |
| 232 info.height() - y : fSubsetHeight; | |
| 233 uint32_t bpp = info.bytesPerPixel(); | |
| 234 for (uint32_t y = 0; y < currSubsetHeight; y++) { | |
| 235 scanlineDecoder->getScanlines(row.get(), 1, 0); | |
| 236 memcpy(bitmap.getAddr(0, y), row.get() + x * bpp , | |
| 237 currSubsetWidth * bpp); | |
| 238 } | |
| 239 } | |
| 240 } | |
| 241 } | |
| 242 } else { | |
| 243 for (int count = 0; count < n; count++) { | |
| 244 int width, height; | |
| 245 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factor y(fStream)); | |
| 246 decoder->buildTileIndex(fStream->duplicate(), &width, &heigh t); | |
| 247 SkBitmap bitmap; | |
| 248 // Note that we use the same bitmap for all of the subsets. | |
| 249 // It might be larger than necessary for the end subsets. | |
| 250 if (!bitmap.tryAllocPixels(SkImageInfo::Make(fSubsetWidth, f SubsetHeight, | |
|
scroggo
2015/05/29 15:36:02
Again, this is not necessary.
msarett
2015/06/01 14:03:25
Acknowledged.
| |
| 251 fColorType, kOpaque_SkAlphaType))) { | |
| 252 SkDebugf("Could not allocate memory. Aborting bench.\n" ); | |
| 253 return; | |
| 254 } | |
| 255 | |
| 256 for (int x = 0; x < width; x += fSubsetWidth) { | |
| 257 for (int y = 0; y < height; y += fSubsetHeight) { | |
| 258 uint32_t currSubsetWidth = x + (int) fSubsetWidth > width ? | |
| 259 width - x : fSubsetWidth; | |
| 260 uint32_t currSubsetHeight = y + (int) fSubsetHeight > height ? | |
| 261 height - y : fSubsetHeight; | |
| 262 SkIRect rect = SkIRect::MakeXYWH(x, y, currSubsetWid th, | |
| 263 currSubsetHeight); | |
| 264 decoder->decodeSubset(&bitmap, rect, fColorType); | |
| 265 } | |
| 266 } | |
| 267 } | |
| 268 } | |
| 269 break; | |
| 270 case kScale_SubsetMode: | |
| 271 if (fUseCodec) { | |
| 272 for (int count = 0; count < n; count++) { | |
| 273 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream- >duplicate())); | |
| 274 const SkImageInfo info = codec->getInfo(); | |
| 275 SkAutoTDeleteArray<uint8_t> row(SkNEW_ARRAY(uint8_t, info.mi nRowBytes())); | |
| 276 SkScanlineDecoder* scanlineDecoder = codec->getScanlineDecod er(info); | |
| 277 | |
| 278 int centerX = info.width() / 2; | |
| 279 int centerY = info.height() / 2; | |
| 280 int w = fSubsetWidth; | |
| 281 int h = fSubsetHeight; | |
| 282 do { | |
| 283 int subsetStartX = SkTMax(0, centerX - w / 2); | |
| 284 int subsetStartY = SkTMax(0, centerY - h / 2); | |
| 285 int subsetWidth = SkTMin(w, info.width() - subsetStartX) ; | |
| 286 int subsetHeight = SkTMin(h, info.height() - subsetStart Y); | |
| 287 // Note that if we subseted and scaled in a single step, we could use the | |
|
scroggo
2015/05/29 15:36:02
subsetted? (Technically not a verb, but it seems l
msarett
2015/06/01 14:03:25
Done.
| |
| 288 // same bitmap - as is often done in actual use cases. | |
| 289 SkBitmap bitmap; | |
| 290 if (!bitmap.tryAllocPixels(info.makeWH(subsetWidth, subs etHeight))) { | |
| 291 SkDebugf("Could not allocate memory. Aborting bench .\n"); | |
| 292 return; | |
| 293 } | |
| 294 | |
| 295 uint32_t bpp = info.bytesPerPixel(); | |
| 296 scanlineDecoder->skipScanlines(subsetStartY); | |
| 297 for (int y = 0; y < subsetHeight; y++) { | |
| 298 scanlineDecoder->getScanlines(row.get(), 1, 0); | |
| 299 memcpy(bitmap.getAddr(0, y), row.get() + subsetStart X * bpp, | |
| 300 subsetWidth * bpp); | |
| 301 } | |
| 302 w <<= 1; | |
| 303 h <<= 1; | |
| 304 } while (w < 2 * info.width() || h < 2 * info.height()); | |
| 305 } | |
| 306 } else { | |
| 307 for (int count = 0; count < n; count++) { | |
| 308 int width, height; | |
| 309 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factor y(fStream)); | |
| 310 decoder->buildTileIndex(fStream->duplicate(), &width, &heigh t); | |
| 311 | |
| 312 int centerX = width / 2; | |
| 313 int centerY = height / 2; | |
| 314 int w = fSubsetWidth; | |
| 315 int h = fSubsetHeight; | |
| 316 do { | |
| 317 int subsetStartX = SkTMax(0, centerX - w / 2); | |
| 318 int subsetStartY = SkTMax(0, centerY - h / 2); | |
| 319 int subsetWidth = SkTMin(w, width - subsetStartX); | |
| 320 int subsetHeight = SkTMin(h, height - subsetStartY); | |
| 321 // Note that if we subseted and scaled in a single step, we could use the | |
| 322 // same bitmap - as is often done in actual use cases. | |
| 323 SkBitmap bitmap; | |
| 324 if (!bitmap.tryAllocPixels(SkImageInfo::Make(subsetWidth , subsetHeight, | |
|
scroggo
2015/05/29 15:36:03
Again, not needed. There are some cases where a bi
msarett
2015/06/01 14:03:24
Agreed that this allocation is unnecessary here.
| |
| 325 fColorType, kOpaque_SkAlphaType))) { | |
| 326 SkDebugf("Could not allocate memory. Aborting bench .\n"); | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 SkIRect rect = SkIRect::MakeXYWH(subsetStartX, subsetSta rtY, subsetWidth, | |
| 331 subsetHeight); | |
| 332 decoder->decodeSubset(&bitmap, rect, fColorType); | |
| 333 w <<= 1; | |
| 334 h <<= 1; | |
| 335 } while (w < 2 * width || h < 2 * height); | |
| 336 } | |
| 337 } | |
| 338 break; | |
| 339 } | |
| 340 } | |
| OLD | NEW |