refactor high-contrast filter
Rewrite as one cacheable runtime effect with uniforms paralleling SkHighContrastConfig. This is mostly for style, in the sense of readability but also how I'd recommend writing these effects generally: one program body controlled by uniforms. Callers needing specialization can write their own effect (or use our TBD uniform->constant facility). Test isAlphaUnchanged(), and make it so by not saturating c.a. MaliT880 was producing seriously bad results until I switched to mix(). Change-Id: Ia4cfef25fe26643f6832a5fa0843b28dafc5b284 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/372295 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
63f75fc1b6
commit
4d68c244a7
@ -11,57 +11,58 @@
|
||||
#include "include/private/SkTPin.h"
|
||||
#include "src/core/SkRuntimeEffectPriv.h"
|
||||
|
||||
sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& userConfig) {
|
||||
if (!userConfig.isValid()) {
|
||||
sk_sp<SkColorFilter> SkHighContrastFilter::Make(const SkHighContrastConfig& config) {
|
||||
if (!config.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct Uniforms { float grayscale, invertStyle, contrast; };
|
||||
|
||||
static SkRuntimeEffect* effect = []{
|
||||
SkString code{R"(
|
||||
uniform shader input;
|
||||
uniform half grayscale, invertStyle, contrast;
|
||||
)"};
|
||||
code += kRGB_to_HSL_sksl;
|
||||
code += kHSL_to_RGB_sksl;
|
||||
code += R"(
|
||||
half4 main() {
|
||||
half4 c = sample(input); // linear unpremul RGBA in dst gamut.
|
||||
if (grayscale == 1) {
|
||||
c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;
|
||||
}
|
||||
if (invertStyle == 1/*brightness*/) {
|
||||
c.rgb = 1 - c.rgb;
|
||||
} else if (invertStyle == 2/*lightness*/) {
|
||||
c.rgb = rgb_to_hsl(c.rgb);
|
||||
c.b = 1 - c.b;
|
||||
c.rgb = hsl_to_rgb(c.rgb);
|
||||
}
|
||||
c.rgb = mix(half3(0.5), c.rgb, contrast);
|
||||
return half4(saturate(c.rgb), c.a);
|
||||
}
|
||||
)";
|
||||
|
||||
auto [effect, err] = SkRuntimeEffect::Make(code);
|
||||
if (!err.isEmpty()) {
|
||||
SkDebugf("%s\n%s\n", code.c_str(), err.c_str());
|
||||
}
|
||||
SkASSERT(effect && err.isEmpty());
|
||||
return effect.release();
|
||||
}();
|
||||
|
||||
// A contrast setting of exactly +1 would divide by zero (1+c)/(1-c), so pull in to +1-ε.
|
||||
// I'm not exactly sure why we've historically pinned -1 up to -1+ε, maybe just symmetry?
|
||||
SkHighContrastConfig config = userConfig;
|
||||
config.fContrast = SkTPin(config.fContrast,
|
||||
-1.0f + FLT_EPSILON,
|
||||
+1.0f - FLT_EPSILON);
|
||||
float c = SkTPin(config.fContrast,
|
||||
-1.0f + FLT_EPSILON,
|
||||
+1.0f - FLT_EPSILON);
|
||||
|
||||
struct { float M; } uniforms;
|
||||
SkString code{
|
||||
"uniform shader input;"
|
||||
"uniform half M;"
|
||||
Uniforms uniforms = {
|
||||
config.fGrayscale ? 1.0f : 0.0f,
|
||||
(float)config.fInvertStyle, // 0.0f for none, 1.0f for brightness, 2.0f for lightness
|
||||
(1+c)/(1-c),
|
||||
};
|
||||
|
||||
code += kRGB_to_HSL_sksl;
|
||||
code += kHSL_to_RGB_sksl;
|
||||
|
||||
code += "half4 main() {";
|
||||
if (true) {
|
||||
code += "half4 c = sample(input);"; // c is linear unpremul RGBA in the dst gamut.
|
||||
}
|
||||
if (config.fGrayscale) {
|
||||
code += "c.rgb = dot(half3(0.2126, 0.7152, 0.0722), c.rgb).rrr;";
|
||||
}
|
||||
if (config.fInvertStyle == SkHighContrastConfig::InvertStyle::kInvertBrightness) {
|
||||
code += "c.rgb = 1 - c.rgb;";
|
||||
}
|
||||
if (config.fInvertStyle == SkHighContrastConfig::InvertStyle::kInvertLightness) {
|
||||
code += "c.rgb = rgb_to_hsl(c.rgb);";
|
||||
code += "c.b = 1 - c.b;";
|
||||
code += "c.rgb = hsl_to_rgb(c.rgb);";
|
||||
}
|
||||
if (float c = config.fContrast) {
|
||||
uniforms.M = (1+c)/(1-c);
|
||||
code += "c.rgb = (c.rgb - 0.5)*M + 0.5;";
|
||||
}
|
||||
if (true) {
|
||||
code += "return saturate(c);";
|
||||
}
|
||||
code += "}";
|
||||
|
||||
auto [effect, err] = SkRuntimeEffect::Make(code);
|
||||
if (!err.isEmpty()) {
|
||||
SkDebugf("%s\n%s\n", code.c_str(), err.c_str());
|
||||
}
|
||||
SkASSERT(effect && err.isEmpty());
|
||||
|
||||
sk_sp<SkColorFilter> input = nullptr;
|
||||
skcms_TransferFunction linear = SkNamedTransferFn::kLinear;
|
||||
SkAlphaType unpremul = kUnpremul_SkAlphaType;
|
||||
|
@ -45,10 +45,11 @@ DEF_TEST(HighContrastFilter_FilterImage, reporter) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(HighContrastFilter_SanityCheck, reporter) {
|
||||
DEF_TEST(HighContrastFilter_SmokeTest, reporter) {
|
||||
SkHighContrastConfig config;
|
||||
config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
|
||||
sk_sp<SkColorFilter> filter = SkHighContrastFilter::Make(config);
|
||||
REPORTER_ASSERT(reporter, filter->isAlphaUnchanged());
|
||||
|
||||
SkColor white_inverted = filter->filterColor(SK_ColorWHITE);
|
||||
REPORTER_ASSERT(reporter, white_inverted == SK_ColorBLACK);
|
||||
|
Loading…
Reference in New Issue
Block a user