GPU support for SkColorFilters::HSLAMatrix

Change-Id: I5b762811b44861fcedd2fa5c0e48a82718458605
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/232398
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2019-10-23 11:44:22 -04:00 committed by Skia Commit-Bot
parent 32803ff744
commit 36031207dc
10 changed files with 361 additions and 7 deletions

View File

@ -381,6 +381,8 @@ skia_gpu_sources = [
"$_src/gpu/effects/generated/GrConstColorProcessor.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/GrLumaColorFilterEffect.cpp",
"$_src/gpu/effects/generated/GrLumaColorFilterEffect.h",
"$_src/gpu/effects/generated/GrMagnifierEffect.cpp",
@ -393,6 +395,8 @@ skia_gpu_sources = [
"$_src/gpu/effects/generated/GrPremulInputFragmentProcessor.h",
"$_src/gpu/effects/generated/GrRectBlurEffect.cpp",
"$_src/gpu/effects/generated/GrRectBlurEffect.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/GrSaturateProcessor.cpp",

View File

@ -47,12 +47,14 @@ skia_gpu_processor_sources = [
"$_src/gpu/effects/GrConstColorProcessor.fp",
"$_src/gpu/effects/GrColorMatrixFragmentProcessor.fp",
"$_src/gpu/effects/GrEllipseEffect.fp",
"$_src/gpu/effects/GrHSLToRGBFilterEffect.fp",
"$_src/gpu/effects/GrLumaColorFilterEffect.fp",
"$_src/gpu/effects/GrMagnifierEffect.fp",
"$_src/gpu/effects/GrMixerEffect.fp",
"$_src/gpu/effects/GrOverrideInputFragmentProcessor.fp",
"$_src/gpu/effects/GrPremulInputFragmentProcessor.fp",
"$_src/gpu/effects/GrRectBlurEffect.fp",
"$_src/gpu/effects/GrRGBToHSLFilterEffect.fp",
"$_src/gpu/effects/GrRRectBlurEffect.fp",
"$_src/gpu/effects/GrSaturateProcessor.fp",
"$_src/gpu/effects/GrSimpleTextureEffect.fp",

View File

@ -81,16 +81,30 @@ bool SkColorFilter_Matrix::onAppendStages(const SkStageRec& rec, bool shaderIsOp
#if SK_SUPPORT_GPU
#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
#include "src/gpu/effects/generated/GrHSLToRGBFilterEffect.h"
#include "src/gpu/effects/generated/GrRGBToHSLFilterEffect.h"
std::unique_ptr<GrFragmentProcessor> SkColorFilter_Matrix::asFragmentProcessor(
GrRecordingContext*, const GrColorInfo&) const {
if (fDomain == Domain::kHSLA) {
// TODO
return nullptr;
}
switch (fDomain) {
case Domain::kRGBA:
return GrColorMatrixFragmentProcessor::Make(fMatrix,
/* premulInput = */ true,
/* clampRGBOutput = */ true,
/* premulOutput = */ true);
case Domain::kHSLA: {
std::unique_ptr<GrFragmentProcessor> series[] = {
GrRGBToHSLFilterEffect::Make(),
GrColorMatrixFragmentProcessor::Make(fMatrix,
/* premulInput = */ false,
/* clampRGBOutput = */ false,
/* premulOutput = */ false),
GrHSLToRGBFilterEffect::Make(),
};
return GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
}
}
SkUNREACHABLE;
}
#endif

View File

@ -110,6 +110,7 @@ public:
kGrFillRRectOp_Processor_ClassID,
kGrGaussianConvolutionFragmentProcessor_ClassID,
kGrGSCoverageProcessor_ClassID,
kGrHSLToRGBFilterEffect_ClassID,
kGrImprovedPerlinNoiseEffect_ClassID,
kGrLinearGradientLayout_ClassID,
kGrLumaColorFilterEffect_ClassID,
@ -126,6 +127,7 @@ public:
kGrQuadEffect_ClassID,
kGrRadialGradientLayout_ClassID,
kGrRectBlurEffect_ClassID,
kGrRGBToHSLFilterEffect_ClassID,
kGrRRectBlurEffect_ClassID,
kGrRRectShadowGeoProc_ClassID,
kGrSimpleTextureEffect_ClassID,

View File

@ -0,0 +1,49 @@
/*
* 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 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
void main() {
half3 hsl = sk_InColor.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;
sk_OutColor = saturate(half4(rgb, sk_InColor.a));
sk_OutColor.rgb *= sk_OutColor.a;
}
@optimizationFlags {
(kConstantOutputForConstantInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag)
}
@class {
#include "include/private/SkColorData.h"
#include "include/private/SkNx.h"
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override {
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();
}
}

View File

@ -0,0 +1,73 @@
/*
* 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
void main() {
half4 c = sk_InColor;
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);
sk_OutColor = half4(H, S, L, c.a);
}
@optimizationFlags {
(kConstantOutputForConstantInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag)
}
@class {
#include "include/private/SkColorData.h"
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override {
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 };
}
}

View File

@ -0,0 +1,53 @@
/*
* 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 "include/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<GrHSLToRGBFilterEffect>();
(void)_outer;
fragBuilder->codeAppendf(
"half3 hsl = %s.xyz;\nhalf C = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;\nhalf3 p = "
"hsl.xxx + half3(0.0, 0.66666666666666663, 0.33333333333333331);\nhalf3 q = "
"clamp(abs(fract(p) * 6.0 - 3.0) - 1.0, 0.0, 1.0);\nhalf3 rgb = (q - 0.5) * C + "
"hsl.z;\n%s = clamp(half4(rgb, %s.w), 0.0, 1.0);\n%s.xyz *= %s.w;\n",
args.fInputColor, args.fOutputColor, args.fInputColor, args.fOutputColor,
args.fOutputColor);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {}
};
GrGLSLFragmentProcessor* GrHSLToRGBFilterEffect::onCreateGLSLInstance() const {
return new GrGLSLHSLToRGBFilterEffect();
}
void GrHSLToRGBFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrHSLToRGBFilterEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrHSLToRGBFilterEffect& that = other.cast<GrHSLToRGBFilterEffect>();
(void)that;
return true;
}
GrHSLToRGBFilterEffect::GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src)
: INHERITED(kGrHSLToRGBFilterEffect_ClassID, src.optimizationFlags()) {}
std::unique_ptr<GrFragmentProcessor> GrHSLToRGBFilterEffect::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrHSLToRGBFilterEffect(*this));
}

View File

@ -0,0 +1,50 @@
/*
* 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/SkTypes.h"
#include "src/gpu/GrCoordTransform.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& c) const override {
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<GrFragmentProcessor> Make() {
return std::unique_ptr<GrFragmentProcessor>(new GrHSLToRGBFilterEffect());
}
GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "HSLToRGBFilterEffect"; }
private:
GrHSLToRGBFilterEffect()
: INHERITED(kGrHSLToRGBFilterEffect_ClassID,
(OptimizationFlags)(kConstantOutputForConstantInput_OptimizationFlag |
kPreservesOpaqueInput_OptimizationFlag)) {}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -0,0 +1,55 @@
/*
* 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 "include/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<GrRGBToHSLFilterEffect>();
(void)_outer;
fragBuilder->codeAppendf(
"half4 c = %s;\nhalf4 p = c.y < c.z ? half4(c.zy, -1.0, 0.66666666666666663) : "
"half4(c.yz, 0.0, -0.33333333333333331);\nhalf4 q = c.x < p.x ? half4(p.x, c.x, "
"p.yw) : half4(c.x, p.x, p.yz);\n\nhalf pmV = q.x;\nhalf pmC = pmV - min(q.y, "
"q.z);\nhalf pmL = pmV - pmC * 0.5;\nhalf H = abs(q.w + (q.y - q.z) / (pmC * 6.0 + "
"9.9999997473787516e-05));\nhalf S = pmC / ((c.w + 9.9999997473787516e-05) - "
"abs(pmL * 2.0 - c.w));\nhalf L = pmL / (c.w + 9.9999997473787516e-05);\n%s = "
"half4(H, S, L, c.w);\n",
args.fInputColor, args.fOutputColor);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {}
};
GrGLSLFragmentProcessor* GrRGBToHSLFilterEffect::onCreateGLSLInstance() const {
return new GrGLSLRGBToHSLFilterEffect();
}
void GrRGBToHSLFilterEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrRGBToHSLFilterEffect::onIsEqual(const GrFragmentProcessor& other) const {
const GrRGBToHSLFilterEffect& that = other.cast<GrRGBToHSLFilterEffect>();
(void)that;
return true;
}
GrRGBToHSLFilterEffect::GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src)
: INHERITED(kGrRGBToHSLFilterEffect_ClassID, src.optimizationFlags()) {}
std::unique_ptr<GrFragmentProcessor> GrRGBToHSLFilterEffect::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrRGBToHSLFilterEffect(*this));
}

View File

@ -0,0 +1,52 @@
/*
* 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/SkTypes.h"
#include "src/gpu/GrCoordTransform.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrRGBToHSLFilterEffect : public GrFragmentProcessor {
public:
#include "include/private/SkColorData.h"
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override {
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<GrFragmentProcessor> Make() {
return std::unique_ptr<GrFragmentProcessor>(new GrRGBToHSLFilterEffect());
}
GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "RGBToHSLFilterEffect"; }
private:
GrRGBToHSLFilterEffect()
: INHERITED(kGrRGBToHSLFilterEffect_ClassID,
(OptimizationFlags)(kConstantOutputForConstantInput_OptimizationFlag |
kPreservesOpaqueInput_OptimizationFlag)) {}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
typedef GrFragmentProcessor INHERITED;
};
#endif