Index: src/core/SkPictureRecord.cpp |
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp |
index af1b8ffbc2134d0aa937c49429f61163e550d806..000365889348cf4262e75cdf21a6b4dffda6bd14 100644 |
--- a/src/core/SkPictureRecord.cpp |
+++ b/src/core/SkPictureRecord.cpp |
@@ -900,17 +900,75 @@ SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfac |
return NULL; |
} |
-int SkPictureRecord::addBitmap(const SkBitmap& bitmap) { |
+// If we already have a stored, can we reuse it instead of also storing b? |
+static bool equivalent(const SkBitmap& a, const SkBitmap& b) { |
+ if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) { |
+ // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch), |
+ // but it sure makes things easier to reason about below. |
+ return false; |
+ } |
+ if (a.pixelRef() == b.pixelRef()) { |
+ return true; // Same shape and same pixels -> same bitmap. |
+ } |
+ |
+ // From here down we're going to have to look at the bitmap data, so we require pixelRefs(). |
+ if (!a.pixelRef() || !b.pixelRef()) { |
+ return false; |
+ } |
+ |
+ // If the bitmaps have encoded data, check first before locking pixels so they don't decode. |
+ SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()), |
+ encB(b.pixelRef()->refEncodedData()); |
+ if (encA && encB) { |
+ return encA->equals(encB); |
+ } else if (encA || encB) { |
+ return false; // One has encoded data but the other does not. |
+ } |
+ |
+ // As a last resort, we have to look at the pixels. This will read back textures. |
+ SkAutoLockPixels al(a), bl(b); |
+ const char* ap = (const char*)a.getPixels(); |
+ const char* bp = (const char*)b.getPixels(); |
+ if (ap && bp) { |
+ // We check row by row; row bytes might differ. |
+ SkASSERT(a.info() == b.info()); // We checked this above. |
+ SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true. |
+ const SkImageInfo info = a.info(); |
+ const size_t bytesToCompare = info.width() * info.bytesPerPixel(); |
+ for (int row = 0; row < info.height(); row++) { |
+ if (0 != memcmp(ap, bp, bytesToCompare)) { |
+ return false; |
+ } |
+ ap += a.rowBytes(); |
+ bp += b.rowBytes(); |
+ } |
+ return true; |
+ } |
+ return false; // Couldn't get pixels for both bitmaps. |
+} |
+ |
+void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { |
+ // First see if we already have this bitmap. This deduplication should really |
+ // only be important for our tests, where bitmaps tend not to be tagged immutable. |
+ // In Chrome (and hopefully Android?) they're typically immutable. |
scroggo
2015/08/06 18:54:40
Alas, no, on Android, there is no Java API to make
|
+ for (int i = 0; i < fBitmaps.count(); i++) { |
+ if (equivalent(fBitmaps[i], bitmap)) { |
+ this->addInt(i); // Unlike the rest, bitmap indices are 0-based. |
+ return; |
+ } |
+ } |
+ // Don't have it. We'll add it to our list, making sure it's tagged as immutable. |
if (bitmap.isImmutable()) { |
+ // Shallow copies of bitmaps are cheap, so immutable == fast. |
fBitmaps.push_back(bitmap); |
} else { |
+ // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage. |
SkBitmap copy; |
bitmap.copyTo(©); |
copy.setImmutable(); |
fBitmaps.push_back(copy); |
} |
- this->addInt(fBitmaps.count()-1); // Unlike the rest, bitmap indicies are 0-based. |
- return fBitmaps.count(); |
+ this->addInt(fBitmaps.count()-1); // Remember, 0-based. |
} |
void SkPictureRecord::addMatrix(const SkMatrix& matrix) { |