aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/gpu/GrColorSpaceInfo.cpp3
-rw-r--r--src/gpu/GrColorSpaceXform.cpp231
-rw-r--r--src/gpu/GrColorSpaceXform.h51
-rw-r--r--src/gpu/SkGr.cpp2
-rw-r--r--src/gpu/effects/GrNonlinearColorSpaceXformEffect.cpp8
-rw-r--r--src/gpu/glsl/GrGLSLColorSpaceXformHelper.h56
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.cpp66
-rw-r--r--src/shaders/SkColorShader.cpp8
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);