Index: src/image/SkImage_Gpu.cpp |
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp |
index 0c4769fa95bab5308cb1786fdba1e5e1d4fcd0dc..87bbe2ab5a89381885fab922028fad956b236a81 100644 |
--- a/src/image/SkImage_Gpu.cpp |
+++ b/src/image/SkImage_Gpu.cpp |
@@ -16,6 +16,7 @@ |
#include "SkGrPixelRef.h" |
#include "SkGrPriv.h" |
#include "SkImage_Gpu.h" |
+#include "SkMipMap.h" |
#include "SkPixelRef.h" |
SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex, |
@@ -351,15 +352,44 @@ private: |
}; |
size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy, |
- const DeferredTextureImageUsageParams[], |
+ const DeferredTextureImageUsageParams params[], |
int paramCnt, void* buffer) const { |
+ // Extract relevant min/max values from the params array. |
+ int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel; |
+ SkFilterQuality highestFilterQuality = params[0].fQuality; |
+ for (int i = 1; i < paramCnt; ++i) { |
+ if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel) |
+ lowestPreScaleMipLevel = params[i].fPreScaleMipLevel; |
+ if (highestFilterQuality < params[i].fQuality) |
+ highestFilterQuality = params[i].fQuality; |
+ } |
+ |
const bool fillMode = SkToBool(buffer); |
if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) { |
return 0; |
} |
+ // Calculate scaling parameters. |
+ bool isScaled = lowestPreScaleMipLevel != 0; |
+ |
+ SkISize scaledSize; |
+ if (isScaled) { |
+ // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the |
+ // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level. |
+ scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(), |
+ lowestPreScaleMipLevel - 1); |
+ } else { |
+ scaledSize = SkISize::Make(this->width(), this->height()); |
+ } |
+ |
+ // We never want to scale at higher than SW medium quality, as SW medium matches GPU high. |
+ SkFilterQuality scaleFilterQuality = highestFilterQuality; |
+ if (scaleFilterQuality > kMedium_SkFilterQuality) { |
+ scaleFilterQuality = kMedium_SkFilterQuality; |
+ } |
+ |
const int maxTextureSize = proxy.fCaps->maxTextureSize(); |
- if (width() > maxTextureSize || height() > maxTextureSize) { |
+ if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) { |
return 0; |
} |
@@ -368,7 +398,7 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox |
size_t pixelSize = 0; |
size_t ctSize = 0; |
int ctCount = 0; |
- if (this->peekPixels(&pixmap)) { |
+ if (!isScaled && this->peekPixels(&pixmap)) { |
info = pixmap.info(); |
pixelSize = SkAlign8(pixmap.getSafeSize()); |
if (pixmap.ctable()) { |
@@ -380,16 +410,23 @@ size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& prox |
// In the future we will access the cacherator and get the exact data that we want to (e.g. |
// yuv planes) upload. |
SkAutoTUnref<SkData> data(this->refEncoded()); |
- if (!data) { |
+ if (!data && !this->peekPixels(nullptr)) { |
return 0; |
} |
SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; |
- info = SkImageInfo::MakeN32(this->width(), this->height(), at); |
+ info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), at); |
pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr)); |
if (fillMode) { |
pixmap.alloc(info); |
- if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) { |
- return 0; |
+ if (isScaled) { |
+ if (!this->scalePixels(pixmap, scaleFilterQuality, |
+ SkImage::kDisallow_CachingHint)) { |
+ return 0; |
+ } |
+ } else { |
+ if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) { |
+ return 0; |
+ } |
} |
SkASSERT(!pixmap.ctable()); |
} |