diff options
-rw-r--r-- | src/gpu/GrColorSpaceInfo.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrColorSpaceXform.cpp | 231 | ||||
-rw-r--r-- | src/gpu/GrColorSpaceXform.h | 51 | ||||
-rw-r--r-- | src/gpu/SkGr.cpp | 2 | ||||
-rw-r--r-- | src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp | 8 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLColorSpaceXformHelper.h | 56 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLShaderBuilder.cpp | 66 | ||||
-rw-r--r-- | src/shaders/SkColorShader.cpp | 8 |
8 files changed, 171 insertions, 254 deletions
diff --git a/src/gpu/GrColorSpaceInfo.cpp b/src/gpu/GrColorSpaceInfo.cpp index 73218b26c5..60c848b8cf 100644 --- a/src/gpu/GrColorSpaceInfo.cpp +++ b/src/gpu/GrColorSpaceInfo.cpp @@ -17,7 +17,8 @@ GrColorSpaceXform* GrColorSpaceInfo::colorSpaceXformFromSRGB() const { if (!fInitializedColorSpaceXformFromSRGB) { // sRGB sources are very common (SkColor, etc...), so we cache that transformation auto srgbColorSpace = SkColorSpace::MakeSRGB(); - fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get()); + fColorXformFromSRGB = GrColorSpaceXform::MakeUnpremulToUnpremul(srgbColorSpace.get(), + fColorSpace.get()); fInitializedColorSpaceXformFromSRGB = true; } // You can't be color-space aware in legacy mode diff --git a/src/gpu/GrColorSpaceXform.cpp b/src/gpu/GrColorSpaceXform.cpp index baa17df7bd..4ccca52185 100644 --- a/src/gpu/GrColorSpaceXform.cpp +++ b/src/gpu/GrColorSpaceXform.cpp @@ -9,135 +9,44 @@ #include "SkColorSpace.h" #include "SkColorSpacePriv.h" #include "SkMatrix44.h" -#include "SkSpinlock.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" #include "glsl/GrGLSLFragmentProcessor.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" -class GrColorSpaceXformCache { -public: - using NewValueFn = std::function<sk_sp<GrColorSpaceXform>(void)>; - - GrColorSpaceXformCache() : fSequence(0) {} - - sk_sp<GrColorSpaceXform> findOrAdd(uint64_t key, NewValueFn newValue) { - int oldest = 0; - for (int i = 0; i < kEntryCount; ++i) { - if (fEntries[i].fKey == key) { - fEntries[i].fLastUse = fSequence++; - return fEntries[i].fXform; - } - if (fEntries[i].fLastUse < fEntries[oldest].fLastUse) { - oldest = i; - } - } - fEntries[oldest].fKey = key; - fEntries[oldest].fXform = newValue(); - fEntries[oldest].fLastUse = fSequence++; - return fEntries[oldest].fXform; - } - -private: - enum { kEntryCount = 32 }; - - struct Entry { - // The default Entry is "valid". Any 64-bit key that is the same 32-bit value repeated - // implies no xform is necessary, so nullptr should be returned. This particular case should - // never happen, but by initializing all entries with this data, we can avoid special cases - // for the array not yet being full. - Entry() : fKey(0), fXform(nullptr), fLastUse(0) {} - - uint64_t fKey; - sk_sp<GrColorSpaceXform> fXform; - uint64_t fLastUse; - }; - - Entry fEntries[kEntryCount]; - uint64_t fSequence; -}; - -GrColorSpaceXform::GrColorSpaceXform(const SkColorSpaceTransferFn& srcTransferFn, - const SkMatrix44& gamutXform, uint32_t flags) - : fSrcTransferFn(srcTransferFn), fGamutXform(gamutXform), fFlags(flags) {} - -static SkSpinlock gColorSpaceXformCacheSpinlock; - sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace* dst) { + // No transformation is performed in legacy mode, until SkColorSpaceXformCanvas is gone if (!dst) { - // No transformation is performed in legacy mode return nullptr; } - // Treat null sources as sRGB + // Treat null sources as sRGB (safe because sRGB is a global singleton) if (!src) { src = SkColorSpace::MakeSRGB().get(); } - uint32_t flags = 0; - SkColorSpaceTransferFn srcTransferFn; - - if (src->gammaIsLinear()) { - // Linear sampling does the right thing - } else if (src->isNumericalTransferFn(&srcTransferFn)) { - // Need to manually apply some transfer function - flags |= kApplyTransferFn_Flag; - } else { - // We don't (yet) support more complex transfer functions - return nullptr; - } + // TODO: Plumb source alpha type + SkColorSpaceXformSteps steps(src, kPremul_SkAlphaType, dst); - if (src == dst && (0 == flags)) { - // Quick equality check - no conversion (or transfer function) needed in this case - return nullptr; - } + return steps.flags.mask() == 0 ? nullptr /* Noop transform */ + : sk_make_sp<GrColorSpaceXform>(steps); +} - const SkMatrix44* toXYZD50 = src->toXYZD50(); - const SkMatrix44* fromXYZD50 = dst->fromXYZD50(); - if (!toXYZD50 || !fromXYZD50) { - // Unsupported colour spaces -- cannot specify gamut as a matrix +sk_sp<GrColorSpaceXform> GrColorSpaceXform::MakeUnpremulToUnpremul(SkColorSpace* src, + SkColorSpace* dst) { + // No transformation is performed in legacy mode, until SkColorSpaceXformCanvas is gone + if (!dst) { return nullptr; } - // Determine if a gamut xform is needed - uint32_t srcHash = src->toXYZD50Hash(); - uint32_t dstHash = dst->toXYZD50Hash(); - if (srcHash != dstHash) { - flags |= kApplyGamutXform_Flag; - } else { - SkASSERT(*toXYZD50 == *dst->toXYZD50() && "Hash collision"); - } - - if (0 == flags) { - // Identical gamut and no transfer function - no conversion needed in this case - return nullptr; + // Treat null sources as sRGB (safe because sRGB is a global singleton) + if (!src) { + src = SkColorSpace::MakeSRGB().get(); } - auto makeXform = [srcTransferFn, fromXYZD50, toXYZD50, flags]() { - SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); - if (SkToBool(flags & kApplyGamutXform_Flag)) { - srcToDst.setConcat(*fromXYZD50, *toXYZD50); - } else { - srcToDst.setIdentity(); - } - return sk_make_sp<GrColorSpaceXform>(srcTransferFn, srcToDst, flags); - }; - - // For now, we only cache pure gamut xforms (no transfer functions) - // TODO: Fold a hash of the transfer function into the cache key - if ((kApplyGamutXform_Flag == flags) && gColorSpaceXformCacheSpinlock.tryAcquire()) { - static GrColorSpaceXformCache* gCache; - if (nullptr == gCache) { - gCache = new GrColorSpaceXformCache(); - } + SkColorSpaceXformSteps steps = SkColorSpaceXformSteps::UnpremulToUnpremul(src, dst); - uint64_t key = static_cast<uint64_t>(srcHash) << 32 | static_cast<uint64_t>(dstHash); - sk_sp<GrColorSpaceXform> xform = gCache->findOrAdd(key, makeXform); - gColorSpaceXformCacheSpinlock.release(); - return xform; - } else { - // If our xform has non-gamut components, or we can't get the spin lock, just build it - return makeXform(); - } + return steps.flags.mask() == 0 ? nullptr /* Noop transform */ + : sk_make_sp<GrColorSpaceXform>(steps); } bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) { @@ -145,45 +54,32 @@ bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXfo return true; } - if (!a || !b || a->fFlags != b->fFlags) { + if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) { + return false; + } + + if (a->fSteps.flags.linearize && + 0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) { return false; } - if (SkToBool(a->fFlags & kApplyTransferFn_Flag) && - 0 != memcmp(&a->fSrcTransferFn, &b->fSrcTransferFn, sizeof(SkColorSpaceTransferFn))) { + if (a->fSteps.flags.gamut_transform && + 0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix, + sizeof(a->fSteps.src_to_dst_matrix))) { return false; } - if (SkToBool(a->fFlags & kApplyGamutXform_Flag) && a->fGamutXform != b->fGamutXform) { + if (a->fSteps.flags.encode && + 0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) { return false; } return true; } -GrColor4f GrColorSpaceXform::unclampedXform(const GrColor4f& srcColor) { - // This transform step should only happen with textures (not CPU xform of individual values) - SkASSERT(!SkToBool(fFlags & kApplyInverseSRGB_Flag)); - +GrColor4f GrColorSpaceXform::apply(const GrColor4f& srcColor) { GrColor4f result = srcColor; - if (fFlags & kApplyTransferFn_Flag) { - // Only transform RGB (not alpha) - for (int i = 0; i < 3; ++i) { - result.fRGBA[i] = fSrcTransferFn(result.fRGBA[i]); - } - } - if (fFlags & kApplyGamutXform_Flag) { - fGamutXform.mapScalars(result.fRGBA, result.fRGBA); - } - return result; -} - -GrColor4f GrColorSpaceXform::clampedXform(const GrColor4f& srcColor) { - GrColor4f result = this->unclampedXform(srcColor); - for (int i = 0; i < 4; ++i) { - // We always operate on unpremul colors, so clamp to [0,1]. - result.fRGBA[i] = SkTPin(result.fRGBA[i], 0.0f, 1.0f); - } + fSteps.apply(result.fRGBA); return result; } @@ -198,13 +94,22 @@ public: fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform()); - SkString childColor("src_color"); - this->emitChild(0, &childColor, args); + if (this->numChildProcessors()) { + SkString childColor("src_color"); + this->emitChild(0, &childColor, args); - SkString xformedColor; - fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper); - fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(), - args.fInputColor); + SkString xformedColor; + fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper); + fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(), + args.fInputColor); + } else { + if (nullptr == args.fInputColor) { + args.fInputColor = "half4(1)"; + } + SkString xformedColor; + fragBuilder->appendColorGamutXform(&xformedColor, args.fInputColor, &fColorSpaceHelper); + fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str()); + } } private: @@ -225,12 +130,16 @@ GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProce sk_sp<GrColorSpaceXform> colorXform) : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get())) , fColorXform(std::move(colorXform)) { - this->registerChildProcessor(std::move(child)); + if (child) { + this->registerChildProcessor(std::move(child)); + } } std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const { + std::unique_ptr<GrFragmentProcessor> child = + this->numChildProcessors() ? this->childProcessor(0).clone() : nullptr; return std::unique_ptr<GrFragmentProcessor>( - new GrColorSpaceXformEffect(this->childProcessor(0).clone(), fColorXform)); + new GrColorSpaceXformEffect(std::move(child), fColorXform)); } bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const { @@ -250,14 +159,30 @@ GrGLSLFragmentProcessor* GrColorSpaceXformEffect::onCreateGLSLInstance() const { GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags( const GrFragmentProcessor* child) { // TODO: Implement constant output for constant input - OptimizationFlags flags = kNone_OptimizationFlags; - if (child->compatibleWithCoverageAsAlpha()) { - flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag; + if (child) { + OptimizationFlags flags = kNone_OptimizationFlags; + if (child->compatibleWithCoverageAsAlpha()) { + flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag; + } + if (child->preservesOpaqueInput()) { + flags |= kPreservesOpaqueInput_OptimizationFlag; + } + return flags; + } else { + return kCompatibleWithCoverageAsAlpha_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag; } - if (child->preservesOpaqueInput()) { - flags |= kPreservesOpaqueInput_OptimizationFlag; +} + +std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(SkColorSpace* src, + SkColorSpace* dst) { + auto xform = GrColorSpaceXform::Make(src, dst); + if (!xform) { + return nullptr; } - return flags; + + return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(nullptr, + std::move(xform))); } std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make( @@ -267,11 +192,11 @@ std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make( return nullptr; } - auto colorXform = GrColorSpaceXform::Make(src, dst); - if (colorXform) { - return std::unique_ptr<GrFragmentProcessor>( - new GrColorSpaceXformEffect(std::move(child), std::move(colorXform))); - } else { + auto xform = GrColorSpaceXform::Make(src, dst); + if (!xform) { return child; } + + return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child), + std::move(xform))); } diff --git a/src/gpu/GrColorSpaceXform.h b/src/gpu/GrColorSpaceXform.h index b925fb2b87..2dca9c75cf 100644 --- a/src/gpu/GrColorSpaceXform.h +++ b/src/gpu/GrColorSpaceXform.h @@ -10,72 +10,51 @@ #include "GrColor.h" #include "GrFragmentProcessor.h" -#include "SkColorSpace.h" -#include "SkMatrix44.h" +#include "SkColorSpaceXformSteps.h" #include "SkRefCnt.h" +class SkColorSpace; + /** * Represents a color space transformation */ class GrColorSpaceXform : public SkRefCnt { public: - GrColorSpaceXform(const SkColorSpaceTransferFn&, const SkMatrix44&, uint32_t); + GrColorSpaceXform(const SkColorSpaceXformSteps& steps) : fSteps(steps) {} static sk_sp<GrColorSpaceXform> Make(SkColorSpace* src, SkColorSpace* dst); - static sk_sp<GrColorSpaceXform> MakeGamutXform(SkColorSpace* src, SkColorSpace* dst) { - sk_sp<SkColorSpace> linearSrc = sk_ref_sp(src); - if (!linearSrc) { - linearSrc = SkColorSpace::MakeSRGBLinear(); - } - linearSrc = linearSrc->makeLinearGamma(); - auto result = Make(linearSrc.get(), dst); - SkASSERT(!result || 0 == (result->fFlags & ~kApplyGamutXform_Flag)); - return result; - } - const SkColorSpaceTransferFn& transferFn() const { return fSrcTransferFn; } - const float* transferFnCoeffs() const { - static_assert(0 == offsetof(SkColorSpaceTransferFn, fG), "TransferFn layout"); - return &fSrcTransferFn.fG; - } + static sk_sp<GrColorSpaceXform> MakeUnpremulToUnpremul(SkColorSpace* src, SkColorSpace* dst); - const SkMatrix44& gamutXform() const { return fGamutXform; } + const SkColorSpaceXformSteps& steps() const { return fSteps; } /** * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its * computed key. */ static uint32_t XformKey(const GrColorSpaceXform* xform) { - // Code generation depends on which steps we apply (as encoded by fFlags) - return SkToBool(xform) ? xform->fFlags : 0; + // Code generation depends on which steps we apply + return xform ? xform->fSteps.flags.mask() : 0; } static bool Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b); - GrColor4f unclampedXform(const GrColor4f& srcColor); - GrColor4f clampedXform(const GrColor4f& srcColor); + GrColor4f apply(const GrColor4f& srcColor); private: friend class GrGLSLColorSpaceXformHelper; - enum Flags { - kApplyTransferFn_Flag = 0x1, - kApplyGamutXform_Flag = 0x2, - - // Almost never used. This handles the case where the src data is sRGB pixel config, - // but the color space has a different transfer function. In that case, we first undo - // the HW sRGB -> Linear conversion, before applying any other steps. - kApplyInverseSRGB_Flag = 0x4, - }; - - SkColorSpaceTransferFn fSrcTransferFn; - SkMatrix44 fGamutXform; - uint32_t fFlags; + SkColorSpaceXformSteps fSteps; }; class GrColorSpaceXformEffect : public GrFragmentProcessor { public: /** + * Returns a fragment processor that converts the input's color space from src to dst. + */ + static std::unique_ptr<GrFragmentProcessor> Make(SkColorSpace* src, SkColorSpace* dst); + + /** * Returns a fragment processor that calls the passed in fragment processor, and then converts * the color space of the output from src to dst. */ diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index 9a13398c33..f872756159 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -221,7 +221,7 @@ GrColor4f SkColorToPremulGrColor4fLegacy(SkColor c) { GrColor4f SkColorToUnpremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) { GrColor4f color = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c)); if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) { - color = xform->clampedXform(color); + color = xform->apply(color); } return color; } diff --git a/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp b/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp index 5471f563fb..cec9da3590 100644 --- a/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp +++ b/src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp @@ -227,12 +227,12 @@ std::unique_ptr<GrFragmentProcessor> GrNonlinearColorSpaceXformEffect::Make(SkCo uint32_t ops = 0; - // We rely on GrColorSpaceXform to build the gamut xform matrix for us (to get caching) - auto gamutXform = GrColorSpaceXform::MakeGamutXform(src, dst); + const SkMatrix44* toXYZ = src->toXYZD50(); + const SkMatrix44* fromXYZ = dst->fromXYZD50(); SkMatrix44 srcToDstMtx(SkMatrix44::kUninitialized_Constructor); - if (gamutXform) { + if (toXYZ && fromXYZ && src->toXYZD50Hash() != dst->toXYZD50Hash()) { + srcToDstMtx.setConcat(*fromXYZ, *toXYZ); ops |= kGamutXform_Op; - srcToDstMtx = gamutXform->gamutXform(); } SkColorSpaceTransferFn srcTransferFn; diff --git a/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h b/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h index 0cc9da1012..397a656c88 100644 --- a/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h +++ b/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h @@ -10,6 +10,7 @@ #include "GrColorSpaceXform.h" #include "GrGLSLUniformHandler.h" +#include "SkColorSpaceXformSteps.h" /** * Helper class to assist with using GrColorSpaceXform within an FP. This manages all of the @@ -18,56 +19,61 @@ */ class GrGLSLColorSpaceXformHelper : public SkNoncopyable { public: - GrGLSLColorSpaceXformHelper() : fFlags(0) {} + GrGLSLColorSpaceXformHelper() { + memset(&fFlags, 0, sizeof(fFlags)); + } void emitCode(GrGLSLUniformHandler* uniformHandler, const GrColorSpaceXform* colorSpaceXform, uint32_t visibility = kFragment_GrShaderFlag) { SkASSERT(uniformHandler); if (colorSpaceXform) { - fFlags = colorSpaceXform->fFlags; + fFlags = colorSpaceXform->fSteps.flags; + if (this->applySrcTF()) { + fSrcTFVar = uniformHandler->addUniformArray(visibility, kHalf_GrSLType, + "SrcTF", kNumTransferFnCoeffs); + } if (this->applyGamutXform()) { - fGamutXformVar = uniformHandler->addUniform(visibility, - kHalf4x4_GrSLType, + fGamutXformVar = uniformHandler->addUniform(visibility, kHalf3x3_GrSLType, "ColorXform"); } - if (this->applyTransferFn()) { - fTransferFnVar = uniformHandler->addUniformArray(visibility, - kHalf_GrSLType, - "TransferFn", - kNumTransferFnCoeffs); + if (this->applyDstTF()) { + fDstTFVar = uniformHandler->addUniformArray(visibility, kHalf_GrSLType, + "DstTF", kNumTransferFnCoeffs); } } } void setData(const GrGLSLProgramDataManager& pdman, const GrColorSpaceXform* colorSpaceXform) { + if (this->applySrcTF()) { + pdman.set1fv(fSrcTFVar, kNumTransferFnCoeffs, &colorSpaceXform->fSteps.srcTF.fG); + } if (this->applyGamutXform()) { - pdman.setSkMatrix44(fGamutXformVar, colorSpaceXform->gamutXform()); + pdman.setMatrix3f(fGamutXformVar, colorSpaceXform->fSteps.src_to_dst_matrix); } - if (this->applyTransferFn()) { - pdman.set1fv(fTransferFnVar, kNumTransferFnCoeffs, colorSpaceXform->transferFnCoeffs()); + if (this->applyDstTF()) { + pdman.set1fv(fDstTFVar, kNumTransferFnCoeffs, &colorSpaceXform->fSteps.dstTFInv.fG); } } - bool isNoop() const { return (0 == fFlags); } - bool applyInverseSRGB() const { - return SkToBool(fFlags & GrColorSpaceXform::kApplyInverseSRGB_Flag); - } - bool applyTransferFn() const { - return SkToBool(fFlags & GrColorSpaceXform::kApplyTransferFn_Flag); - } - bool applyGamutXform() const { - return SkToBool(fFlags & GrColorSpaceXform::kApplyGamutXform_Flag); - } + bool isNoop() const { return (0 == fFlags.mask()); } + + bool applyUnpremul() const { return fFlags.unpremul; } + bool applySrcTF() const { return fFlags.linearize; } + bool applyGamutXform() const { return fFlags.gamut_transform; } + bool applyDstTF() const { return fFlags.encode; } + bool applyPremul() const { return fFlags.premul; } + GrGLSLProgramDataManager::UniformHandle srcTFUniform() const { return fSrcTFVar; } GrGLSLProgramDataManager::UniformHandle gamutXformUniform() const { return fGamutXformVar; } - GrGLSLProgramDataManager::UniformHandle transferFnUniform() const { return fTransferFnVar; } + GrGLSLProgramDataManager::UniformHandle dstTFUniform() const { return fDstTFVar; } private: static const int kNumTransferFnCoeffs = 7; + GrGLSLProgramDataManager::UniformHandle fSrcTFVar; GrGLSLProgramDataManager::UniformHandle fGamutXformVar; - GrGLSLProgramDataManager::UniformHandle fTransferFnVar; - uint32_t fFlags; + GrGLSLProgramDataManager::UniformHandle fDstTFVar; + SkColorSpaceXformSteps::Flags fFlags; }; #endif diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp index db0be21f01..e2b1c559bc 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -109,24 +109,13 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler(); - // We define up to three helper functions, to keep things clearer. One does inverse sRGB, - // one does an arbitrary transfer function, and the last does gamut xform. Any combination of - // these may be present, although some configurations are much more likely. + // We define up to three helper functions, to keep things clearer. One for the source transfer + // function, one for the (inverse) destination transfer function, and one for the gamut xform. + // Any combination of these may be present, although some configurations are much more likely. - SkString inverseSrgbFuncName; - if (colorXformHelper->applyInverseSRGB()) { - static const GrShaderVar gInverseSRGBArgs[] = { GrShaderVar("x", kHalf_GrSLType) }; - SkString body; - body.append("return (x <= 0.0031308) ? (x * 12.92) : (1.055 * pow(x, 0.4166667) - 0.055);"); - this->emitFunction(kHalf_GrSLType, "inverse_srgb", SK_ARRAY_COUNT(gInverseSRGBArgs), - gInverseSRGBArgs, body.c_str(), &inverseSrgbFuncName); - - } - - SkString transferFnFuncName; - if (colorXformHelper->applyTransferFn()) { - static const GrShaderVar gTransferFnArgs[] = { GrShaderVar("x", kHalf_GrSLType) }; - const char* coeffs = uniformHandler->getUniformCStr(colorXformHelper->transferFnUniform()); + auto emitTFFunc = [=](const char* name, GrGLSLProgramDataManager::UniformHandle uniform) { + static const GrShaderVar gTFArgs[] = { GrShaderVar("x", kHalf_GrSLType) }; + const char* coeffs = uniformHandler->getUniformCStr(uniform); SkString body; // Temporaries to make evaluation line readable body.appendf("half G = %s[0];", coeffs); @@ -139,18 +128,28 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, body.append("half s = sign(x);"); body.append("x = abs(x);"); body.appendf("return s * ((x < D) ? (C * x) + F : pow(A * x + B, G) + E);"); - this->emitFunction(kHalf_GrSLType, "transfer_fn", SK_ARRAY_COUNT(gTransferFnArgs), - gTransferFnArgs, body.c_str(), &transferFnFuncName); + SkString funcName; + this->emitFunction(kHalf_GrSLType, name, SK_ARRAY_COUNT(gTFArgs), gTFArgs, body.c_str(), + &funcName); + return funcName; + }; + + SkString srcTFFuncName; + if (colorXformHelper->applySrcTF()) { + srcTFFuncName = emitTFFunc("src_tf", colorXformHelper->srcTFUniform()); + } + + SkString dstTFFuncName; + if (colorXformHelper->applyDstTF()) { + dstTFFuncName = emitTFFunc("dst_tf", colorXformHelper->dstTFUniform()); } SkString gamutXformFuncName; if (colorXformHelper->applyGamutXform()) { - // Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then - // re-insert the original alpha. static const GrShaderVar gGamutXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) }; const char* xform = uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform()); SkString body; - body.appendf("color.rgb = clamp((%s * half4(color.rgb, 1.0)).rgb, 0.0, color.a);", xform); + body.appendf("color.rgb = (%s * color.rgb);", xform); body.append("return color;"); this->emitFunction(kHalf4_GrSLType, "gamut_xform", SK_ARRAY_COUNT(gGamutXformArgs), gGamutXformArgs, body.c_str(), &gamutXformFuncName); @@ -160,19 +159,26 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, { static const GrShaderVar gColorXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) }; SkString body; - if (colorXformHelper->applyInverseSRGB()) { - body.appendf("color.r = %s(color.r);", inverseSrgbFuncName.c_str()); - body.appendf("color.g = %s(color.g);", inverseSrgbFuncName.c_str()); - body.appendf("color.b = %s(color.b);", inverseSrgbFuncName.c_str()); + if (colorXformHelper->applyUnpremul()) { + body.append("half nonZeroAlpha = max(color.a, 0.00001);"); + body.append("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);"); } - if (colorXformHelper->applyTransferFn()) { - body.appendf("color.r = %s(color.r);", transferFnFuncName.c_str()); - body.appendf("color.g = %s(color.g);", transferFnFuncName.c_str()); - body.appendf("color.b = %s(color.b);", transferFnFuncName.c_str()); + if (colorXformHelper->applySrcTF()) { + body.appendf("color.r = %s(color.r);", srcTFFuncName.c_str()); + body.appendf("color.g = %s(color.g);", srcTFFuncName.c_str()); + body.appendf("color.b = %s(color.b);", srcTFFuncName.c_str()); } if (colorXformHelper->applyGamutXform()) { body.appendf("color = %s(color);", gamutXformFuncName.c_str()); } + if (colorXformHelper->applyDstTF()) { + body.appendf("color.r = %s(color.r);", dstTFFuncName.c_str()); + body.appendf("color.g = %s(color.g);", dstTFFuncName.c_str()); + body.appendf("color.b = %s(color.b);", dstTFFuncName.c_str()); + } + if (colorXformHelper->applyPremul()) { + body.append("color.rgb *= color.a;"); + } body.append("return color;"); SkString colorXformFuncName; this->emitFunction(kHalf4_GrSLType, "color_xform", SK_ARRAY_COUNT(gColorXformArgs), diff --git a/src/shaders/SkColorShader.cpp b/src/shaders/SkColorShader.cpp index 482c731d00..b0387e5046 100644 --- a/src/shaders/SkColorShader.cpp +++ b/src/shaders/SkColorShader.cpp @@ -198,11 +198,11 @@ SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const { std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor( const GrFPArgs& args) const { - auto colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(), - args.fDstColorSpaceInfo->colorSpace()); + auto xform = GrColorSpaceXform::MakeUnpremulToUnpremul(fColorSpace.get(), + args.fDstColorSpaceInfo->colorSpace()); GrColor4f color = GrColor4f::FromSkColor4f(fColor4); - if (colorSpaceXform) { - color = colorSpaceXform->clampedXform(color); + if (xform) { + color = xform->apply(color); } return GrConstColorProcessor::Make(color.premul(), GrConstColorProcessor::InputMode::kModulateA); |