From 2139303e4c0a9cbcfac695977a80eb026a9296ab Mon Sep 17 00:00:00 2001 From: brianosman Date: Tue, 10 May 2016 20:29:15 -0700 Subject: Make GrGammaEffect have explicit sRGB modes, plus exponential mode. Convert it to a "standard" FP that just transforms the input color. For now, we still infer the sRGB transfer curves from the exponent, but I'm hoping that eventually SkGammas will provide us with the exact curve we're supposed to be applying. In any case, this adds support for doing the inverse transformation, as well, which will be needed in an upcoming Vulkan YUV change, among other things. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1954863002 Review-Url: https://codereview.chromium.org/1954863002 --- src/gpu/effects/GrGammaEffect.cpp | 106 +++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 47 deletions(-) (limited to 'src/gpu/effects/GrGammaEffect.cpp') diff --git a/src/gpu/effects/GrGammaEffect.cpp b/src/gpu/effects/GrGammaEffect.cpp index b2aa48aad2..454f057de5 100644 --- a/src/gpu/effects/GrGammaEffect.cpp +++ b/src/gpu/effects/GrGammaEffect.cpp @@ -23,54 +23,59 @@ public: GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; const char* gammaUniName = nullptr; - if (!ge.gammaIsSRGB()) { + if (GrGammaEffect::Mode::kExponential == ge.mode()) { fGammaUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, kDefault_GrSLPrecision, "Gamma", &gammaUniName); } - GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision); - SkString tmpDecl; - tmpVar.appendDecl(args.fGLSLCaps, &tmpDecl); - SkString srgbFuncName; - if (ge.gammaIsSRGB()) { - static const GrGLSLShaderVar gSrgbArgs[] = { - GrGLSLShaderVar("x", kFloat_GrSLType), - }; - - fragBuilder->emitFunction(kFloat_GrSLType, - "linear_to_srgb", - SK_ARRAY_COUNT(gSrgbArgs), - gSrgbArgs, - "return (x <= 0.0031308) ? (x * 12.92) " - ": (1.055 * pow(x, 0.416666667) - 0.055);", - &srgbFuncName); + static const GrGLSLShaderVar gSrgbArgs[] = { + GrGLSLShaderVar("x", kFloat_GrSLType), + }; + switch (ge.mode()) { + case GrGammaEffect::Mode::kLinearToSRGB: + fragBuilder->emitFunction(kFloat_GrSLType, + "linear_to_srgb", + SK_ARRAY_COUNT(gSrgbArgs), + gSrgbArgs, + "return (x <= 0.0031308) ? (x * 12.92) " + ": (1.055 * pow(x, 0.416666667) - 0.055);", + &srgbFuncName); + break; + case GrGammaEffect::Mode::kSRGBToLinear: + fragBuilder->emitFunction(kFloat_GrSLType, + "srgb_to_linear", + SK_ARRAY_COUNT(gSrgbArgs), + gSrgbArgs, + "return (x <= 0.04045) ? (x / 12.92) " + ": powf((x + 0.055) / 1.055, 2.4);", + &srgbFuncName); + default: + // No helper function needed + break; } - fragBuilder->codeAppendf("%s;", tmpDecl.c_str()); - - fragBuilder->codeAppendf("%s = ", tmpVar.c_str()); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fCoords[0].c_str(), - args.fCoords[0].getType()); - fragBuilder->codeAppend(";"); + if (nullptr == args.fInputColor) { + args.fInputColor = "vec4(1)"; + } - if (ge.gammaIsSRGB()) { - fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", - args.fOutputColor, - srgbFuncName.c_str(), tmpVar.c_str(), - srgbFuncName.c_str(), tmpVar.c_str(), - srgbFuncName.c_str(), tmpVar.c_str(), - tmpVar.c_str()); - } else { + if (GrGammaEffect::Mode::kExponential == ge.mode()) { fragBuilder->codeAppendf("%s = vec4(pow(%s.rgb, vec3(%s)), %s.a);", - args.fOutputColor, tmpVar.c_str(), gammaUniName, - tmpVar.c_str()); + args.fOutputColor, args.fInputColor, gammaUniName, + args.fInputColor); + } else { + fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);", + args.fOutputColor, + srgbFuncName.c_str(), args.fInputColor, + srgbFuncName.c_str(), args.fInputColor, + srgbFuncName.c_str(), args.fInputColor, + args.fInputColor); } } void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { const GrGammaEffect& ge = proc.cast(); - if (!ge.gammaIsSRGB()) { + if (GrGammaEffect::Mode::kExponential == ge.mode()) { pdman.set1f(fGammaUni, ge.gamma()); } } @@ -78,7 +83,7 @@ public: static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { const GrGammaEffect& ge = processor.cast(); - uint32_t key = ge.gammaIsSRGB() ? 0x1 : 0x0; + uint32_t key = static_cast(ge.mode()); b->add32(key); } @@ -90,19 +95,17 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrGammaEffect::GrGammaEffect(GrTexture* texture, SkScalar gamma) - : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) { +GrGammaEffect::GrGammaEffect(Mode mode, SkScalar gamma) + : fMode(mode) + , fGamma(gamma) { this->initClassID(); - - fGamma = gamma; - fGammaIsSRGB = SkScalarNearlyEqual(gamma, 1.0f / 2.2f); } bool GrGammaEffect::onIsEqual(const GrFragmentProcessor& s) const { const GrGammaEffect& other = s.cast(); return - other.fGammaIsSRGB == fGammaIsSRGB && - other.fGamma == fGamma; + other.fMode == fMode && + (fMode != Mode::kExponential || other.fGamma == fGamma); } void GrGammaEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { @@ -115,9 +118,9 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGammaEffect); const GrFragmentProcessor* GrGammaEffect::TestCreate(GrProcessorTestData* d) { // We want to be sure and test sRGB sometimes - bool srgb = d->fRandom->nextBool(); - return new GrGammaEffect(d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx], - srgb ? 1.0f / 2.2f : d->fRandom->nextRangeScalar(0.5f, 2.0f)); + Mode testMode = static_cast(d->fRandom->nextRangeU(0, 2)); + SkScalar gamma = d->fRandom->nextRangeScalar(0.5f, 2.0f); + return new GrGammaEffect(testMode, gamma); } /////////////////////////////////////////////////////////////////////////////// @@ -131,6 +134,15 @@ GrGLSLFragmentProcessor* GrGammaEffect::onCreateGLSLInstance() const { return new GrGLGammaEffect(); } -const GrFragmentProcessor* GrGammaEffect::Create(GrTexture* texture, SkScalar gamma) { - return new GrGammaEffect(texture, gamma); +const GrFragmentProcessor* GrGammaEffect::Create(SkScalar gamma) { + // TODO: Once our public-facing API for specifying gamma curves settles down, expose this, + // and allow clients to explicitly request sRGB, rather than inferring from the exponent. + // Note that AdobeRGB (for example) is speficied as x^2.2, not the Rec.709 curves. + if (SkScalarNearlyEqual(gamma, 2.2f)) { + return new GrGammaEffect(Mode::kSRGBToLinear, 2.2f); + } else if (SkScalarNearlyEqual(gamma, 1.0f / 2.2f)) { + return new GrGammaEffect(Mode::kLinearToSRGB, 1.0f / 2.2f); + } else { + return new GrGammaEffect(Mode::kExponential, gamma); + } } -- cgit v1.2.3