| Index: src/effects/gradients/SkGradientShader.cpp
|
| diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
|
| index 4f174d72b9f120f4bf967c6744b270cc4eb7e1a1..27f6136403a6186faea1c7e0444d6ff151b8e8e5 100644
|
| --- a/src/effects/gradients/SkGradientShader.cpp
|
| +++ b/src/effects/gradients/SkGradientShader.cpp
|
| @@ -7,6 +7,7 @@
|
|
|
| #include "Sk4fLinearGradient.h"
|
| #include "SkGradientShaderPriv.h"
|
| +#include "SkHalf.h"
|
| #include "SkLinearGradient.h"
|
| #include "SkRadialGradient.h"
|
| #include "SkTwoPointConicalGradient.h"
|
| @@ -544,6 +545,62 @@ void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache*
|
| }
|
| }
|
|
|
| +void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap) const {
|
| + const bool interpInPremul = SkToBool(fGradFlags &
|
| + SkGradientShader::kInterpolateColorsInPremul_Flag);
|
| + bitmap->lockPixels();
|
| + SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels());
|
| + uint32_t* pixelsS32 = reinterpret_cast<uint32_t*>(bitmap->getPixels());
|
| +
|
| + typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t;
|
| +
|
| + pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) {
|
| + Sk4h c = SkFloatToHalf_finite_ftz(x);
|
| + pixelsF16[4*index+0] = c[0];
|
| + pixelsF16[4*index+1] = c[1];
|
| + pixelsF16[4*index+2] = c[2];
|
| + pixelsF16[4*index+3] = c[3];
|
| + };
|
| + pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) {
|
| + pixelsS32[index] = Sk4f_toS32(c);
|
| + };
|
| +
|
| + pixelWriteFn_t writeSizedPixel =
|
| + (kRGBA_F16_SkColorType == bitmap->colorType()) ? writeF16Pixel : writeS32Pixel;
|
| + pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) {
|
| + writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index);
|
| + };
|
| +
|
| + pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel;
|
| +
|
| + int prevIndex = 0;
|
| + for (int i = 1; i < fColorCount; i++) {
|
| + int nextIndex = (fColorCount == 2) ? (kCache32Count - 1)
|
| + : SkFixedToFFFF(fRecs[i].fPos) >> kCache32Shift;
|
| + SkASSERT(nextIndex < kCache32Count);
|
| +
|
| + if (nextIndex > prevIndex) {
|
| + Sk4f c0 = Sk4f::Load(fOrigColors4f[i - 1].vec());
|
| + Sk4f c1 = Sk4f::Load(fOrigColors4f[i].vec());
|
| + if (interpInPremul) {
|
| + c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f);
|
| + c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f);
|
| + }
|
| +
|
| + Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex));
|
| + Sk4f delta = (c1 - c0) * step;
|
| +
|
| + for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) {
|
| + writePixel(c0, curIndex);
|
| + c0 += delta;
|
| + }
|
| + }
|
| + prevIndex = nextIndex;
|
| + }
|
| + SkASSERT(prevIndex == kCache32Count - 1);
|
| + bitmap->unlockPixels();
|
| +}
|
| +
|
| /*
|
| * The gradient holds a cache for the most recent value of alpha. Successive
|
| * callers with the same alpha value will share the same cache.
|
| @@ -570,13 +627,13 @@ SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
|
| * colors and positions. Note: we don't try to flatten the fMapper, so if one
|
| * is present, we skip the cache for now.
|
| */
|
| -void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
|
| - // our caller assumes no external alpha, so we ensure that our cache is
|
| - // built with 0xFF
|
| +void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap,
|
| + GradientBitmapType bitmapType) const {
|
| + // our caller assumes no external alpha, so we ensure that our cache is built with 0xFF
|
| SkAutoTUnref<GradientShaderCache> cache(this->refCache(0xFF, true));
|
|
|
| - // build our key: [numColors + colors[] + {positions[]} + flags ]
|
| - int count = 1 + fColorCount + 1;
|
| + // build our key: [numColors + colors[] + {positions[]} + flags + colorType ]
|
| + int count = 1 + fColorCount + 1 + 1;
|
| if (fColorCount > 2) {
|
| count += fColorCount - 1; // fRecs[].fPos
|
| }
|
| @@ -593,12 +650,13 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
|
| }
|
| }
|
| *buffer++ = fGradFlags;
|
| + *buffer++ = static_cast<int32_t>(bitmapType);
|
| SkASSERT(buffer - storage.get() == count);
|
|
|
| ///////////////////////////////////
|
|
|
| static SkGradientBitmapCache* gCache;
|
| - // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
|
| + // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp
|
| static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
|
| SkAutoMutexAcquire ama(gGradientCacheMutex);
|
|
|
| @@ -608,11 +666,35 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
|
| size_t size = count * sizeof(int32_t);
|
|
|
| if (!gCache->find(storage.get(), size, bitmap)) {
|
| - // force our cahce32pixelref to be built
|
| - (void)cache->getCache32();
|
| - bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
|
| - bitmap->setPixelRef(cache->getCache32PixelRef());
|
| -
|
| + if (GradientBitmapType::kLegacy == bitmapType) {
|
| + // force our cache32pixelref to be built
|
| + (void)cache->getCache32();
|
| + bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
|
| + bitmap->setPixelRef(cache->getCache32PixelRef());
|
| + } else {
|
| + // For these cases we use the bitmap cache, but not the GradientShaderCache. So just
|
| + // allocate and populate the bitmap's data directly.
|
| +
|
| + SkImageInfo info;
|
| + switch (bitmapType) {
|
| + case GradientBitmapType::kSRGB:
|
| + info = SkImageInfo::Make(kCache32Count, 1, kRGBA_8888_SkColorType,
|
| + kPremul_SkAlphaType,
|
| + SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named));
|
| + break;
|
| + case GradientBitmapType::kHalfFloat:
|
| + info = SkImageInfo::Make(kCache32Count, 1, kRGBA_F16_SkColorType,
|
| + kPremul_SkAlphaType,
|
| + SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)
|
| + ->makeLinearGamma());
|
| + break;
|
| + default:
|
| + SkFAIL("Unexpected bitmap type");
|
| + return;
|
| + }
|
| + bitmap->allocPixels(info);
|
| + this->initLinearBitmap(bitmap);
|
| + }
|
| gCache->add(storage.get(), size, *bitmap);
|
| }
|
| }
|
| @@ -902,6 +984,7 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
| #include "GrInvariantOutput.h"
|
| #include "GrTextureStripAtlas.h"
|
| #include "gl/GrGLContext.h"
|
| +#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
| #include "glsl/GrGLSLFragmentShaderBuilder.h"
|
| #include "glsl/GrGLSLProgramDataManager.h"
|
| #include "glsl/GrGLSLUniformHandler.h"
|
| @@ -1113,6 +1196,9 @@ void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager&
|
| pdman.set1f(fFSYUni, yCoord);
|
| fCachedYCoord = yCoord;
|
| }
|
| + if (SkToBool(e.fColorSpaceXform)) {
|
| + pdman.setSkMatrix44(fColorSpaceXformUni, e.fColorSpaceXform->srcToDst());
|
| + }
|
| break;
|
| }
|
| }
|
| @@ -1150,6 +1236,8 @@ uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor&
|
| }
|
| #endif
|
|
|
| + key |= GrColorSpaceXform::XformKey(e.fColorSpaceXform.get()) << kReservedBits;
|
| +
|
| return key;
|
| }
|
|
|
| @@ -1331,11 +1419,15 @@ void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBui
|
| }
|
|
|
| case kTexture_ColorType: {
|
| + GrGLSLColorSpaceXformHelper colorSpaceHelper(uniformHandler, ge.fColorSpaceXform.get(),
|
| + &fColorSpaceXformUni);
|
| +
|
| const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
|
|
|
| fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni);
|
| fragBuilder->codeAppendf("%s = ", outputColor);
|
| - fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord");
|
| + fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord",
|
| + kVec2f_GrSLType, &colorSpaceHelper);
|
| fragBuilder->codeAppend(";");
|
|
|
| break;
|
| @@ -1351,12 +1443,12 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) {
|
| fIsOpaque = shader.isOpaque();
|
|
|
| fColorType = this->determineColorType(shader);
|
| + fColorSpaceXform = std::move(args.fColorSpaceXform);
|
|
|
| if (kTexture_ColorType != fColorType) {
|
| SkASSERT(shader.fOrigColors && shader.fOrigColors4f);
|
| if (args.fGammaCorrect) {
|
| fColors4f = SkTDArray<SkColor4f>(shader.fOrigColors4f, shader.fColorCount);
|
| - fColorSpaceXform = std::move(args.fColorSpaceXform);
|
| } else {
|
| fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
|
| }
|
| @@ -1397,8 +1489,22 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) {
|
| // effect key.
|
| fPremulType = kBeforeInterp_PremulType;
|
|
|
| + SkGradientShaderBase::GradientBitmapType bitmapType =
|
| + SkGradientShaderBase::GradientBitmapType::kLegacy;
|
| + if (args.fGammaCorrect) {
|
| + // Try to use F16 if we can
|
| + if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
|
| + bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat;
|
| + } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) {
|
| + bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB;
|
| + } else {
|
| + // This should never happen, but just fall back to legacy behavior
|
| + SkDEBUGFAIL("Requesting a gamma-correct gradient FP without F16 or sRGB");
|
| + }
|
| + }
|
| +
|
| SkBitmap bitmap;
|
| - shader.getGradientTableBitmap(&bitmap);
|
| + shader.getGradientTableBitmap(&bitmap, bitmapType);
|
|
|
| GrTextureStripAtlas::Desc desc;
|
| desc.fWidth = bitmap.width();
|
|
|