Chromium Code Reviews| Index: src/gpu/SkGr.cpp |
| diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp |
| index 3c3f3e8fab99e9836564c571d912003901991c2e..c628067c39edbb4ab1b9304c86c719212cdd3a0d 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" |
| @@ -48,7 +51,7 @@ GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) { |
| return desc; |
| } |
| -void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) { |
| +void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds, bool isMipMapped) { |
| SkASSERT(key); |
| SkASSERT(imageID); |
| SkASSERT(!imageBounds.isEmpty()); |
| @@ -59,6 +62,12 @@ void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& ima |
| builder[2] = imageBounds.fTop; |
| builder[3] = imageBounds.fRight; |
| builder[4] = imageBounds.fBottom; |
| + builder[5] = isMipMapped; |
|
bsalomon
2015/10/28 16:40:45
This will cause us to potentially create two versi
|
| +} |
| + |
| +void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, const SkIRect& imageBounds) { |
| + const bool isMipMapped = false; |
| + GrMakeKeyFromImageID(key, imageID, imageBounds, isMipMapped); |
| } |
| GrPixelConfig GrIsCompressedTextureDataSupported(GrContext* ctx, SkData* data, |
| @@ -276,6 +285,77 @@ GrTexture* GrUploadBitmapToTexture(GrContext* ctx, const SkBitmap& bmp) { |
| //////////////////////////////////////////////////////////////////////////////// |
| +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 Bitmap_GrTextureParamsAdjuster : public GrTextureParamsAdjuster { |
| public: |
| Bitmap_GrTextureParamsAdjuster(const SkBitmap& bitmap) |
| @@ -293,7 +373,7 @@ public: |
| protected: |
| GrTexture* peekOriginalTexture() override { return fBitmap.getTexture(); } |
| - GrTexture* refOriginalTexture(GrContext* ctx) override { |
| + GrTexture* refOriginalTexture(GrContext* ctx, const GrTextureParams& params) override { |
| GrTexture* tex = fBitmap.getTexture(); |
| if (tex) { |
| return SkRef(tex); |
| @@ -306,7 +386,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); |
| + tex = generate_mipmaps(ctx, fBitmap); |
| + } else { |
| + tex = GrUploadBitmapToTexture(ctx, fBitmap); |
| + } |
| if (tex && fOriginalKey.isValid()) { |
| tex->resourcePriv().setUniqueKey(fOriginalKey); |
| InstallInvalidator(fOriginalKey, fBitmap.pixelRef()); |