aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar brianosman <brianosman@google.com>2016-09-22 12:31:58 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-22 12:31:59 -0700
commitd454609f621471998edc382cdbd25bd2f05f0bde (patch)
tree5233a4c93ad5e6feae0fc0749ab0b9408443bc39 /src/effects
parentecbc526418414f6f9d29b176ea0ad8037fff2e2d (diff)
Support for color-spaces with multi-stop (texture) gradients
Texture is F16 linear, unless that's not supported. In that case, we pack down to sRGB. Added more test patches to the gamut GM with many stops, to test this case. Now they render correctly. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2343253002 Review-Url: https://codereview.chromium.org/2343253002
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/gradients/SkGradientShader.cpp134
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h12
2 files changed, 131 insertions, 15 deletions
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 4f174d72b9..27f6136403 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();
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index aeb1301c7f..d8d50e8fa0 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -175,7 +175,13 @@ public:
bool isOpaque() const override;
- void getGradientTableBitmap(SkBitmap*) const;
+ enum class GradientBitmapType : uint8_t {
+ kLegacy,
+ kSRGB,
+ kHalfFloat,
+ };
+
+ void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
enum {
/// Seems like enough for visual accuracy. TODO: if pos[] deserves
@@ -214,6 +220,9 @@ protected:
bool onAsLuminanceColor(SkColor*) const override;
+
+ void initLinearBitmap(SkBitmap* bitmap) const;
+
/*
* Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
* Count is the number of colors in the gradient
@@ -490,6 +499,7 @@ private:
SkScalar fCachedYCoord;
GrGLSLProgramDataManager::UniformHandle fColorsUni;
GrGLSLProgramDataManager::UniformHandle fFSYUni;
+ GrGLSLProgramDataManager::UniformHandle fColorSpaceXformUni;
typedef GrGLSLFragmentProcessor INHERITED;
};