Index: src/gpu/SkGr.cpp |
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp |
index 469ef5bbe2d2bd149aa3a79875f078824427b536..7f608febe2af72a23b57e4d1a040536a37620f14 100644 |
--- a/src/gpu/SkGr.cpp |
+++ b/src/gpu/SkGr.cpp |
@@ -22,9 +22,12 @@ |
#include "SkErrorInternals.h" |
#include "SkGrPixelRef.h" |
#include "SkMessageBus.h" |
+#include "SkMath.h" |
+#include "SkMipMapLevel.h" |
#include "SkPixelRef.h" |
#include "SkResourceCache.h" |
#include "SkTextureCompressor.h" |
+#include "SkTypes.h" |
#include "SkYUVPlanesCache.h" |
#include "effects/GrBicubicEffect.h" |
#include "effects/GrConstColorProcessor.h" |
@@ -284,6 +287,77 @@ static void install_bmp_key_invalidator(const GrUniqueKey& key, SkPixelRef* pixe |
pixelRef->addGenIDChangeListener(new Invalidator(key)); |
} |
+static GrTexture* generate_mipmaps(GrContext* ctx, |
+ const SkBitmap& bitmap) { |
+ SkASSERT(sizeof(int) <= sizeof(uint32_t)); |
+ const uint32_t baseWidth = static_cast<uint32_t>(bitmap.width()); |
+ const uint32_t baseHeight = static_cast<uint32_t>(bitmap.height()); |
+ |
+ // OpenGL's spec requires that each mipmap level has height/width equal to |
+ // max(1, floor(original_height / 2^i) |
+ // (or original_height) where i is the mipmap level. |
+ // Keep scaling down until both axes are size 1. |
+ |
+ const uint32_t largestAxis = SkTMax(baseWidth, baseHeight); |
+ const int leadingZeros = SkCLZ(largestAxis); |
+ // If the value 00011010 has 3 leading 0s, it has 5 significant bits |
+ // (the bits which are not leading zeros) |
+ const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; |
+ if (significantBits < 0) |
+ { |
+ return nullptr; |
+ } |
+ const uint32_t unsignedSignificantBits = static_cast<uint32_t>(significantBits); |
+ const uint32_t mipLevelCount = unsignedSignificantBits; |
+ |
+ GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info()); |
+ const bool isMipMapped = mipLevelCount > 1; |
+ desc.fIsMipMapped = isMipMapped; |
+ |
+ SkAutoPixmapUnlock srcUnlocker; |
+ if (!bitmap.requestLock(&srcUnlocker)) { |
+ return nullptr; |
+ } |
+ const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
+ if (nullptr == srcPixmap.addr()) { |
+ return nullptr; |
+ } |
+ |
+ SkTArray<SkMipMapLevel> texels(mipLevelCount); |
+ SkMipMapLevel baseLevel(srcPixmap.addr(), bitmap.rowBytes(), baseWidth, baseHeight); |
+ texels.push_back(baseLevel); |
+ |
+ SkTArray<SkBitmap> mipLevelBitmaps(mipLevelCount - 1); |
+ mipLevelBitmaps.push_back_n(mipLevelCount - 1); |
+ |
+ for (uint32_t i = 1; i < mipLevelCount; i++) { |
+ SkBitmap& currentMipBitmap = mipLevelBitmaps[i - 1]; |
+ |
+ uint32_t twoToTheMipLevel = 1 << (i + 1); |
+ uint32_t currentMipLevelWidth = SkTMax(1u, baseWidth / twoToTheMipLevel); |
+ uint32_t currentMipLevelHeight = SkTMax(1u, baseHeight / twoToTheMipLevel); |
+ |
+ SkImageInfo info = SkImageInfo::Make(currentMipLevelWidth, currentMipLevelHeight, |
+ currentMipBitmap.colorType(), |
+ bitmap.alphaType()); |
+ if (!currentMipBitmap.tryAllocPixels(info)) |
+ { |
+ return nullptr; |
+ } |
+ |
+ SkCanvas canvas(currentMipBitmap); |
+ canvas.clear(SK_ColorTRANSPARENT); |
+ canvas.drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0)); |
+ |
+ SkMipMapLevel currentMipLevel(currentMipBitmap.getPixels(), |
+ currentMipBitmap.rowBytes(), |
+ currentMipLevelWidth, currentMipLevelHeight); |
+ texels.push_back(currentMipLevel); |
+ } |
+ |
+ return ctx->textureProvider()->createTexture(desc, true, texels); |
+} |
+ |
class RasterBitmap_GrTextureMaker : public GrTextureMaker { |
public: |
RasterBitmap_GrTextureMaker(const SkBitmap& bitmap) |
@@ -300,7 +374,7 @@ public: |
} |
protected: |
- GrTexture* refOriginalTexture(GrContext* ctx) override { |
+ GrTexture* refOriginalTexture(GrContext* ctx, const GrTextureParams& params) override { |
bsalomon
2015/11/02 16:01:28
Rather than passing the full params could be pass
cblume
2015/11/03 02:10:22
Done.
|
GrTexture* tex; |
if (fOriginalKey.isValid()) { |
@@ -310,7 +384,14 @@ protected: |
} |
} |
- tex = GrUploadBitmapToTexture(ctx, fBitmap); |
+ if (params.filterMode() == GrTextureParams::kMipMap_FilterMode) { |
+ // If the SkBitmap is already backed by a texture, we do not want to read the contents |
+ // back to the cpu and generate the mipmap only to send it back to the GPU. |
+ SkASSERT(!tex); |
bsalomon
2015/11/02 16:01:28
How does this assert work? It seems like if we get
cblume
2015/11/03 02:10:22
I think this is a mistake on my part. This assert
|
+ tex = generate_mipmaps(ctx, fBitmap); |
+ } else { |
+ tex = GrUploadBitmapToTexture(ctx, fBitmap); |
+ } |
if (tex && fOriginalKey.isValid()) { |
tex->resourcePriv().setUniqueKey(fOriginalKey); |
install_bmp_key_invalidator(fOriginalKey, fBitmap.pixelRef()); |