diff options
author | Brian Osman <brianosman@google.com> | 2018-06-18 10:20:32 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-18 14:55:48 +0000 |
commit | 3567c14a41cd55860fcc836af32d8748c1e3c856 (patch) | |
tree | 8a9428dd0c25e3dcee1ccf2e6008c1f665dcaa26 /src/gpu/glsl | |
parent | 1bb47df4fc8edf62b0463d088214ed1ffb909ca9 (diff) |
Implement nonlinear (as-encoded) blending in GrColorSpaceXform
Make GrColorSpaceXform a wrapper over SkColorSpaceXformSteps, and
removed the xform cache. The shader code does up to five steps to
correctly transform (unpremul, linearize, gamut, encode, premul).
Remove all clamping, so we can support sRGB encoded F16.
Most of https://skia-review.googlesource.com/c/skia/+/132090,
except that GrNonlinearColorSpaceXformEffect is still used for
SkColorSpaceXformCanvas and a few other places. As a result,
this doesn't trigger any layout test failures.
Change-Id: I789a5e327a419b5f7634c00d1b355912046c07b7
Reviewed-on: https://skia-review.googlesource.com/135326
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Diffstat (limited to 'src/gpu/glsl')
-rw-r--r-- | src/gpu/glsl/GrGLSLColorSpaceXformHelper.h | 56 | ||||
-rw-r--r-- | src/gpu/glsl/GrGLSLShaderBuilder.cpp | 66 |
2 files changed, 67 insertions, 55 deletions
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), |