Index: src/core/SkMipMap.cpp |
diff --git a/src/core/SkMipMap.cpp b/src/core/SkMipMap.cpp |
index 7266dc6b21192c16019c0277ea4387244033d209..f3c152124dd2f0284435a52b6a049f9890308ef3 100644 |
--- a/src/core/SkMipMap.cpp |
+++ b/src/core/SkMipMap.cpp |
@@ -8,7 +8,9 @@ |
#include "SkMipMap.h" |
#include "SkBitmap.h" |
#include "SkColorPriv.h" |
+#include "SkMath.h" |
#include "SkNx.h" |
+#include "SkTypes.h" |
// |
// ColorTypeFilter is the "Type" we pass to some downsample template functions. |
@@ -249,6 +251,8 @@ SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { |
return nullptr; |
} |
+ SkASSERT(countLevels == SkMipMap::ComputeLevelCount(src.width(), src.height())); |
+ |
size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); |
if (0 == storageSize) { |
return nullptr; |
@@ -318,6 +322,46 @@ SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { |
return mipmap; |
} |
+int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { |
+ // OpenGL's spec requires that each mipmap level have height/width equal to |
+ // max(1, floor(original_height / 2^i) |
+ // (or original_width) where i is the mipmap level. |
+ // Continue scaling down until both axes are size 1. |
+ // |
+ // This means it maintains isotropic space (both axes scaling down |
+ // at the same rate) until one axis hits size 1. |
+ // At that point, OpenGL continues to scale down into anisotropic space |
+ // (where the scales are not the same between axes). |
+ // |
+ // Skia currently does not go into anisotropic space. |
+ // Once an axis hits size 1 we stop. |
+ // All this means is rather than use the largest axis we will use the |
+ // smallest axis. |
+ |
+ const int smallestAxis = SkTMin(baseWidth, baseHeight); |
+ if (smallestAxis < 2) { |
+ // SkMipMap::Build requires a minimum size of 2. |
+ return 0; |
+ } |
+ const int leadingZeros = SkCLZ(static_cast<uint32_t>(smallestAxis)); |
+ // If the value 00011010 has 3 leading 0s then it has 5 significant bits |
+ // (the bits which are not leading zeros) |
+ const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; |
+ // This is making the assumption that the size of a byte is 8 bits |
+ // and that sizeof(uint32_t)'s implementation-defined behavior is 4. |
+ int mipLevelCount = significantBits; |
+ |
+ // SkMipMap does not include the base mip level. |
+ // For example, it contains levels 1-x instead of 0-x. |
+ // This is because the image used to create SkMipMap is the base level. |
+ // So subtract 1 from the mip level count. |
+ if (mipLevelCount > 0) { |
+ --mipLevelCount; |
+ } |
+ |
+ return mipLevelCount; |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
bool SkMipMap::extractLevel(const SkSize& scaleSize, Level* levelPtr) const { |
@@ -371,3 +415,22 @@ SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) { |
return Build(srcPixmap, fact); |
} |
+int SkMipMap::countLevels() const { |
+ return fCount; |
+} |
+ |
+bool SkMipMap::getLevel(int index, Level* levelPtr) const { |
+ if (NULL == fLevels) { |
+ return false; |
+ } |
+ if (index < 0) { |
+ return false; |
+ } |
+ if (index > fCount - 1) { |
+ return false; |
+ } |
+ if (levelPtr) { |
+ *levelPtr = fLevels[index]; |
+ } |
+ return true; |
+} |