From 71bf78604ba1b1327c90d09ddf4f3f9325c0e50f Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Thu, 17 Jun 2021 16:39:08 -0400 Subject: [PATCH] Replace RGB <-> HSL FPs with runtime FPs Awkwardly, there is still two copies of (some of) this SkSL. We have helper functions in SkRuntimeEffectPriv.h that implement these transformations, and those are used by the high contrast color filter. However: The RGB to HSL code is fairly different, and produces results that are visibly different. For this CL, I didn't want to impact either use case, so this is just a migration of the existing .fp code (only used by HSLA color matrices). We can/should look at merging the implementation in the future. Change-Id: I8a9aa6a2d8563ab4333af79a528e406c08b0e1ba Reviewed-on: https://skia-review.googlesource.com/c/skia/+/419497 Commit-Queue: Brian Osman Reviewed-by: John Stiles --- gn/gpu.gni | 4 - gn/sksl.gni | 2 - src/core/SkColorFilter_Matrix.cpp | 80 ++++++++++++++++++- src/gpu/GrProcessor.h | 2 - src/gpu/effects/GrHSLToRGBFilterEffect.fp | 55 ------------- src/gpu/effects/GrRGBToHSLFilterEffect.fp | 77 ------------------ .../generated/GrHSLToRGBFilterEffect.cpp | 65 --------------- .../generated/GrHSLToRGBFilterEffect.h | 59 -------------- .../generated/GrRGBToHSLFilterEffect.cpp | 67 ---------------- .../generated/GrRGBToHSLFilterEffect.h | 61 -------------- 10 files changed, 76 insertions(+), 396 deletions(-) delete mode 100644 src/gpu/effects/GrHSLToRGBFilterEffect.fp delete mode 100644 src/gpu/effects/GrRGBToHSLFilterEffect.fp delete mode 100644 src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp delete mode 100644 src/gpu/effects/generated/GrHSLToRGBFilterEffect.h delete mode 100644 src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp delete mode 100644 src/gpu/effects/generated/GrRGBToHSLFilterEffect.h diff --git a/gn/gpu.gni b/gn/gpu.gni index 08fe6afea0..3363a3e0e1 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -324,12 +324,8 @@ skia_gpu_sources = [ "$_src/gpu/effects/generated/GrDitherEffect.h", "$_src/gpu/effects/generated/GrEllipseEffect.cpp", "$_src/gpu/effects/generated/GrEllipseEffect.h", - "$_src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp", - "$_src/gpu/effects/generated/GrHSLToRGBFilterEffect.h", "$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp", "$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h", - "$_src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp", - "$_src/gpu/effects/generated/GrRGBToHSLFilterEffect.h", "$_src/gpu/effects/generated/GrRRectBlurEffect.cpp", "$_src/gpu/effects/generated/GrRRectBlurEffect.h", "$_src/gpu/effects/generated/GrRectBlurEffect.cpp", diff --git a/gn/sksl.gni b/gn/sksl.gni index 31b89b1f10..f50b9cf573 100644 --- a/gn/sksl.gni +++ b/gn/sksl.gni @@ -215,9 +215,7 @@ skia_gpu_processor_sources = [ "$_src/gpu/effects/GrDeviceSpaceEffect.fp", "$_src/gpu/effects/GrDitherEffect.fp", "$_src/gpu/effects/GrEllipseEffect.fp", - "$_src/gpu/effects/GrHSLToRGBFilterEffect.fp", "$_src/gpu/effects/GrOverrideInputFragmentProcessor.fp", - "$_src/gpu/effects/GrRGBToHSLFilterEffect.fp", "$_src/gpu/effects/GrRRectBlurEffect.fp", "$_src/gpu/effects/GrRectBlurEffect.fp", "$_src/gpu/gradients/GrClampedGradientEffect.fp", diff --git a/src/core/SkColorFilter_Matrix.cpp b/src/core/SkColorFilter_Matrix.cpp index d5aacb91f3..9e18cb1fef 100644 --- a/src/core/SkColorFilter_Matrix.cpp +++ b/src/core/SkColorFilter_Matrix.cpp @@ -120,8 +120,80 @@ skvm::Color SkColorFilter_Matrix::onProgram(skvm::Builder* p, skvm::Color c, } #if SK_SUPPORT_GPU -#include "src/gpu/effects/generated/GrHSLToRGBFilterEffect.h" -#include "src/gpu/effects/generated/GrRGBToHSLFilterEffect.h" +#include "src/gpu/effects/GrSkSLFP.h" + +// Convert RGBA -> HSLA (including unpremul). +// +// Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. High-level ideas: +// +// - minimize the number of branches by sorting and computing the hue phase in parallel (vec4s) +// +// - trade the third sorting branch for a potentially faster std::min and leaving 2nd/3rd +// channels unsorted (based on the observation that swapping both the channels and the bias sign +// has no effect under abs) +// +// - use epsilon offsets for denominators, to avoid explicit zero-checks +// +// An additional trick we employ is deferring premul->unpremul conversion until the very end: the +// alpha factor gets naturally simplified for H and S, and only L requires a dedicated unpremul +// division (so we trade three divs for one). +// +// [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +// [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl +// [3] http://www.chilliant.com/rgb2hsv.html +static std::unique_ptr rgb_to_hsl(std::unique_ptr child) { + static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"( + half4 main(half4 c) { + half4 p = (c.g < c.b) ? half4(c.bg, -1, 2/3.0) + : half4(c.gb, 0, -1/3.0); + half4 q = (c.r < p.x) ? half4(p.x, c.r, p.yw) + : half4(c.r, p.x, p.yz); + + // q.x -> max channel value + // q.yz -> 2nd/3rd channel values (unsorted) + // q.w -> bias value dependent on max channel selection + + half eps = 0.0001; + half pmV = q.x; + half pmC = pmV - min(q.y, q.z); + half pmL = pmV - pmC * 0.5; + half H = abs(q.w + (q.y - q.z) / (pmC * 6 + eps)); + half S = pmC / (c.a + eps - abs(pmL * 2 - c.a)); + half L = pmL / (c.a + eps); + + return half4(H, S, L, c.a); + } + )"); + return GrSkSLFP::Make( + effect, "RgbToHsl", std::move(child), GrSkSLFP::OptFlags::kPreservesOpaqueInput); +} + +// Convert HSLA -> RGBA (including clamp and premul). +// +// Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. +// +// [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +// [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl +// [3] http://www.chilliant.com/rgb2hsv.html +static std::unique_ptr hsl_to_rgb(std::unique_ptr child) { + static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"( + half4 main(half4 color) { + half3 hsl = color.rgb; + + half C = (1 - abs(2 * hsl.z - 1)) * hsl.y; + half3 p = hsl.xxx + half3(0, 2/3.0, 1/3.0); + half3 q = saturate(abs(fract(p) * 6 - 3) - 1); + half3 rgb = (q - 0.5) * C + hsl.z; + + color = saturate(half4(rgb, color.a)); + color.rgb *= color.a; + return color; + } + )"); + return GrSkSLFP::Make( + effect, "HslToRgb", std::move(child), GrSkSLFP::OptFlags::kPreservesOpaqueInput); +} + GrFPResult SkColorFilter_Matrix::asFragmentProcessor(std::unique_ptr fp, GrRecordingContext*, const GrColorInfo&) const { @@ -134,12 +206,12 @@ GrFPResult SkColorFilter_Matrix::asFragmentProcessor(std::unique_ptr RGBA (including clamp and premul). -// -// Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. -// -// [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv -// [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl -// [3] http://www.chilliant.com/rgb2hsv.html - -in fragmentProcessor inputFP; - -half4 main() { - half4 color = sample(inputFP); - half3 hsl = color.rgb; - - half C = (1 - abs(2 * hsl.z - 1)) * hsl.y; - half3 p = hsl.xxx + half3(0, 2/3.0, 1/3.0); - half3 q = saturate(abs(fract(p) * 6 - 3) - 1); - half3 rgb = (q - 0.5) * C + hsl.z; - - color = saturate(half4(rgb, color.a)); - color.rgb *= color.a; - return color; -} - -@optimizationFlags { - ProcessorOptimizationFlags(inputFP.get()) & (kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag) -} - -@class { - #include "include/private/SkColorData.h" - #include "include/private/SkNx.h" - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { - SkPMColor4f c = ConstantOutputForConstantInput(this->childProcessor(0), inColor); - const auto H = c[0], - S = c[1], - L = c[2], - C = (1 - std::abs(2 * L - 1)) * S; - - const auto p = H + Sk4f(0, 2/3.f, 1/3.f, 0), - q = Sk4f::Min(Sk4f::Max(((p - p.floor()) * 6 - 3).abs() - 1, 0), 1), - rgb = (q - 0.5f) * C + L, - rgba = Sk4f::Min(Sk4f::Max(Sk4f(rgb[0], rgb[1], rgb[2], c.fA), 0), 1); - - return SkColor4f{rgba[0], rgba[1], rgba[2], rgba[3]}.premul(); - } -} diff --git a/src/gpu/effects/GrRGBToHSLFilterEffect.fp b/src/gpu/effects/GrRGBToHSLFilterEffect.fp deleted file mode 100644 index bdec81fb17..0000000000 --- a/src/gpu/effects/GrRGBToHSLFilterEffect.fp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2019 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -// Convert RGBA -> HSLA (including unpremul). -// -// Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. High-level ideas: -// -// - minimize the number of branches by sorting and computing the hue phase in parallel (vec4s) -// -// - trade the third sorting branch for a potentially faster std::min and leaving 2nd/3rd -// channels unsorted (based on the observation that swapping both the channels and the bias sign -// has no effect under abs) -// -// - use epsilon offsets for denominators, to avoid explicit zero-checks -// -// An additional trick we employ is deferring premul->unpremul conversion until the very end: the -// alpha factor gets naturally simplified for H and S, and only L requires a dedicated unpremul -// division (so we trade three divs for one). -// -// [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv -// [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl -// [3] http://www.chilliant.com/rgb2hsv.html - -in fragmentProcessor inputFP; - -half4 main() { - half4 c = sample(inputFP); - half4 p = (c.g < c.b) ? half4(c.bg, -1, 2/3.0) - : half4(c.gb, 0, -1/3.0); - half4 q = (c.r < p.x) ? half4(p.x, c.r, p.yw) - : half4(c.r, p.x, p.yz); - - // q.x -> max channel value - // q.yz -> 2nd/3rd channel values (unsorted) - // q.w -> bias value dependent on max channel selection - - half eps = 0.0001; - half pmV = q.x; - half pmC = pmV - min(q.y, q.z); - half pmL = pmV - pmC * 0.5; - half H = abs(q.w + (q.y - q.z) / (pmC * 6 + eps)); - half S = pmC / (c.a + eps - abs(pmL * 2 - c.a)); - half L = pmL / (c.a + eps); - - return half4(H, S, L, c.a); -} - -@optimizationFlags { - ProcessorOptimizationFlags(inputFP.get()) & (kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag) -} - -@class { - #include "include/private/SkColorData.h" - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { - SkPMColor4f c = ConstantOutputForConstantInput(this->childProcessor(0), inColor); - const auto p = (c.fG < c.fB) ? SkPMColor4f{ c.fB, c.fG, -1, 2/3.f } - : SkPMColor4f{ c.fG, c.fB, 0, -1/3.f }, - q = (c.fR < p[0]) ? SkPMColor4f{ p[0], c.fR, p[1], p[3] } - : SkPMColor4f{ c.fR, p[0], p[1], p[2] }; - - const auto eps = 0.0001f, // matching SkSL/ColorMatrix half4 epsilon - pmV = q[0], - pmC = pmV - std::min(q[1], q[2]), - pmL = pmV - pmC * 0.5f, - H = std::abs(q[3] + (q[1] - q[2]) / (pmC * 6 + eps)), - S = pmC / (c.fA + eps - std::abs(pmL * 2 - c.fA)), - L = pmL / (c.fA + eps); - - return { H, S, L, c.fA }; - } -} diff --git a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp b/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp deleted file mode 100644 index 6316223f80..0000000000 --- a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2019 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrHSLToRGBFilterEffect.fp; do not modify. - **************************************************************************************************/ -#include "GrHSLToRGBFilterEffect.h" - -#include "src/core/SkUtils.h" -#include "src/gpu/GrTexture.h" -#include "src/gpu/glsl/GrGLSLFragmentProcessor.h" -#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" -#include "src/gpu/glsl/GrGLSLProgramBuilder.h" -#include "src/sksl/SkSLCPP.h" -#include "src/sksl/SkSLUtil.h" -class GrGLSLHSLToRGBFilterEffect : public GrGLSLFragmentProcessor { -public: - GrGLSLHSLToRGBFilterEffect() {} - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const GrHSLToRGBFilterEffect& _outer = args.fFp.cast(); - (void)_outer; - SkString _sample0 = this->invokeChild(0, args); - fragBuilder->codeAppendf( - R"SkSL(half4 color = %s; -half3 hsl = color.xyz; -half C = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y; -half3 p = hsl.xxx + half3(0.0, 0.66666668653488159, 0.3333333432674408); -half3 q = clamp(abs(fract(p) * 6.0 - 3.0) - 1.0, 0.0, 1.0); -half3 rgb = (q - 0.5) * C + hsl.z; -color = clamp(half4(rgb, color.w), 0.0, 1.0); -color.xyz *= color.w; -return color; -)SkSL", - _sample0.c_str()); - } - -private: - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override {} -}; -std::unique_ptr GrHSLToRGBFilterEffect::onMakeProgramImpl() const { - return std::make_unique(); -} -void GrHSLToRGBFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const {} -bool GrHSLToRGBFilterEffect::onIsEqual(const GrFragmentProcessor& other) const { - const GrHSLToRGBFilterEffect& that = other.cast(); - (void)that; - return true; -} -GrHSLToRGBFilterEffect::GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src) - : INHERITED(kGrHSLToRGBFilterEffect_ClassID, src.optimizationFlags()) { - this->cloneAndRegisterAllChildProcessors(src); -} -std::unique_ptr GrHSLToRGBFilterEffect::clone() const { - return std::make_unique(*this); -} -#if GR_TEST_UTILS -SkString GrHSLToRGBFilterEffect::onDumpInfo() const { return SkString(); } -#endif diff --git a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h b/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h deleted file mode 100644 index 3757cfeb04..0000000000 --- a/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrHSLToRGBFilterEffect.fp; do not modify. - **************************************************************************************************/ -#ifndef GrHSLToRGBFilterEffect_DEFINED -#define GrHSLToRGBFilterEffect_DEFINED - -#include "include/core/SkM44.h" -#include "include/core/SkTypes.h" - -#include "src/gpu/GrFragmentProcessor.h" - -class GrHSLToRGBFilterEffect : public GrFragmentProcessor { -public: -#include "include/private/SkColorData.h" -#include "include/private/SkNx.h" - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { - SkPMColor4f c = ConstantOutputForConstantInput(this->childProcessor(0), inColor); - const auto H = c[0], S = c[1], L = c[2], C = (1 - std::abs(2 * L - 1)) * S; - - const auto p = H + Sk4f(0, 2 / 3.f, 1 / 3.f, 0), - q = Sk4f::Min(Sk4f::Max(((p - p.floor()) * 6 - 3).abs() - 1, 0), 1), - rgb = (q - 0.5f) * C + L, - rgba = Sk4f::Min(Sk4f::Max(Sk4f(rgb[0], rgb[1], rgb[2], c.fA), 0), 1); - - return SkColor4f{rgba[0], rgba[1], rgba[2], rgba[3]}.premul(); - } - static std::unique_ptr Make(std::unique_ptr inputFP) { - return std::unique_ptr(new GrHSLToRGBFilterEffect(std::move(inputFP))); - } - GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src); - std::unique_ptr clone() const override; - const char* name() const override { return "HSLToRGBFilterEffect"; } - -private: - GrHSLToRGBFilterEffect(std::unique_ptr inputFP) - : INHERITED(kGrHSLToRGBFilterEffect_ClassID, - (OptimizationFlags)ProcessorOptimizationFlags(inputFP.get()) & - (kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag)) { - this->registerChild(std::move(inputFP), SkSL::SampleUsage::PassThrough()); - } - std::unique_ptr onMakeProgramImpl() const override; - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - bool onIsEqual(const GrFragmentProcessor&) const override; -#if GR_TEST_UTILS - SkString onDumpInfo() const override; -#endif - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - using INHERITED = GrFragmentProcessor; -}; -#endif diff --git a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp b/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp deleted file mode 100644 index 39ef620929..0000000000 --- a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2019 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrRGBToHSLFilterEffect.fp; do not modify. - **************************************************************************************************/ -#include "GrRGBToHSLFilterEffect.h" - -#include "src/core/SkUtils.h" -#include "src/gpu/GrTexture.h" -#include "src/gpu/glsl/GrGLSLFragmentProcessor.h" -#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" -#include "src/gpu/glsl/GrGLSLProgramBuilder.h" -#include "src/sksl/SkSLCPP.h" -#include "src/sksl/SkSLUtil.h" -class GrGLSLRGBToHSLFilterEffect : public GrGLSLFragmentProcessor { -public: - GrGLSLRGBToHSLFilterEffect() {} - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const GrRGBToHSLFilterEffect& _outer = args.fFp.cast(); - (void)_outer; - SkString _sample0 = this->invokeChild(0, args); - fragBuilder->codeAppendf( - R"SkSL(half4 c = %s; -half4 p = c.y < c.z ? half4(c.zy, -1.0, 0.66666668653488159) : half4(c.yz, 0.0, -0.3333333432674408); -half4 q = c.x < p.x ? half4(p.x, c.x, p.yw) : half4(c.x, p.x, p.yz); -half eps = 9.9999997473787516e-05; -half pmV = q.x; -half pmC = pmV - min(q.y, q.z); -half pmL = pmV - pmC * 0.5; -half H = abs(q.w + (q.y - q.z) / (pmC * 6.0 + eps)); -half S = pmC / ((c.w + eps) - abs(pmL * 2.0 - c.w)); -half L = pmL / (c.w + eps); -return half4(H, S, L, c.w); -)SkSL", - _sample0.c_str()); - } - -private: - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override {} -}; -std::unique_ptr GrRGBToHSLFilterEffect::onMakeProgramImpl() const { - return std::make_unique(); -} -void GrRGBToHSLFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const {} -bool GrRGBToHSLFilterEffect::onIsEqual(const GrFragmentProcessor& other) const { - const GrRGBToHSLFilterEffect& that = other.cast(); - (void)that; - return true; -} -GrRGBToHSLFilterEffect::GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src) - : INHERITED(kGrRGBToHSLFilterEffect_ClassID, src.optimizationFlags()) { - this->cloneAndRegisterAllChildProcessors(src); -} -std::unique_ptr GrRGBToHSLFilterEffect::clone() const { - return std::make_unique(*this); -} -#if GR_TEST_UTILS -SkString GrRGBToHSLFilterEffect::onDumpInfo() const { return SkString(); } -#endif diff --git a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h b/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h deleted file mode 100644 index 1a73d4624b..0000000000 --- a/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrRGBToHSLFilterEffect.fp; do not modify. - **************************************************************************************************/ -#ifndef GrRGBToHSLFilterEffect_DEFINED -#define GrRGBToHSLFilterEffect_DEFINED - -#include "include/core/SkM44.h" -#include "include/core/SkTypes.h" - -#include "src/gpu/GrFragmentProcessor.h" - -class GrRGBToHSLFilterEffect : public GrFragmentProcessor { -public: -#include "include/private/SkColorData.h" - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { - SkPMColor4f c = ConstantOutputForConstantInput(this->childProcessor(0), inColor); - const auto p = (c.fG < c.fB) ? SkPMColor4f{c.fB, c.fG, -1, 2 / 3.f} - : SkPMColor4f{c.fG, c.fB, 0, -1 / 3.f}, - q = (c.fR < p[0]) ? SkPMColor4f{p[0], c.fR, p[1], p[3]} - : SkPMColor4f{c.fR, p[0], p[1], p[2]}; - - const auto eps = 0.0001f, // matching SkSL/ColorMatrix half4 epsilon - pmV = q[0], pmC = pmV - std::min(q[1], q[2]), pmL = pmV - pmC * 0.5f, - H = std::abs(q[3] + (q[1] - q[2]) / (pmC * 6 + eps)), - S = pmC / (c.fA + eps - std::abs(pmL * 2 - c.fA)), L = pmL / (c.fA + eps); - - return {H, S, L, c.fA}; - } - static std::unique_ptr Make(std::unique_ptr inputFP) { - return std::unique_ptr(new GrRGBToHSLFilterEffect(std::move(inputFP))); - } - GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src); - std::unique_ptr clone() const override; - const char* name() const override { return "RGBToHSLFilterEffect"; } - -private: - GrRGBToHSLFilterEffect(std::unique_ptr inputFP) - : INHERITED(kGrRGBToHSLFilterEffect_ClassID, - (OptimizationFlags)ProcessorOptimizationFlags(inputFP.get()) & - (kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag)) { - this->registerChild(std::move(inputFP), SkSL::SampleUsage::PassThrough()); - } - std::unique_ptr onMakeProgramImpl() const override; - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - bool onIsEqual(const GrFragmentProcessor&) const override; -#if GR_TEST_UTILS - SkString onDumpInfo() const override; -#endif - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - using INHERITED = GrFragmentProcessor; -}; -#endif