1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/effects/GrSRGBEffect.h"
9 
10 #include "src/gpu/GrFragmentProcessor.h"
11 #include "src/gpu/GrProcessor.h"
12 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
13 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14 
15 class GrGLSRGBEffect : public GrGLSLFragmentProcessor {
16 public:
emitCode(EmitArgs & args)17     void emitCode(EmitArgs& args) override {
18         const GrSRGBEffect& srgbe = args.fFp.cast<GrSRGBEffect>();
19         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
20 
21         SkString srgbFuncName;
22         const GrShaderVar gSrgbArgs[] = {
23             GrShaderVar("x", kHalf_GrSLType),
24         };
25         switch (srgbe.mode()) {
26             case GrSRGBEffect::Mode::kLinearToSRGB:
27                 fragBuilder->emitFunction(kHalf_GrSLType,
28                                           "linear_to_srgb",
29                                           SK_ARRAY_COUNT(gSrgbArgs),
30                                           gSrgbArgs,
31                                           "return (x <= 0.0031308) ? (x * 12.92) "
32                                           ": (1.055 * pow(x, 0.416666667) - 0.055);",
33                                           &srgbFuncName);
34                 break;
35             case GrSRGBEffect::Mode::kSRGBToLinear:
36                 fragBuilder->emitFunction(kHalf_GrSLType,
37                                           "srgb_to_linear",
38                                           SK_ARRAY_COUNT(gSrgbArgs),
39                                           gSrgbArgs,
40                                           "return (x <= 0.04045) ? (x / 12.92) "
41                                           ": pow((x + 0.055) / 1.055, 2.4);",
42                                           &srgbFuncName);
43                 break;
44         }
45 
46         // Mali Bifrost uses fp16 for mediump. Making the intermediate color variable highp causes
47         // calculations to be performed with sufficient precision.
48         fragBuilder->codeAppendf("float4 color = %s;", args.fInputColor);
49         if (srgbe.alpha() == GrSRGBEffect::Alpha::kPremul) {
50             fragBuilder->codeAppendf("float nonZeroAlpha = max(color.a, 0.0001);");
51             fragBuilder->codeAppendf("color = float4(color.rgb / nonZeroAlpha, color.a);");
52         }
53         fragBuilder->codeAppendf("color = float4(%s(half(color.r)), %s(half(color.g)), "
54                                  "%s(half(color.b)), color.a);",
55                                  srgbFuncName.c_str(),
56                                  srgbFuncName.c_str(),
57                                  srgbFuncName.c_str());
58         if (srgbe.alpha() == GrSRGBEffect::Alpha::kPremul) {
59             fragBuilder->codeAppendf("color = float4(color.rgb, 1) * color.a;");
60         }
61         fragBuilder->codeAppendf("%s = half4(color);", args.fOutputColor);
62     }
63 
GenKey(const GrProcessor & processor,const GrShaderCaps &,GrProcessorKeyBuilder * b)64     static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
65                               GrProcessorKeyBuilder* b) {
66         const GrSRGBEffect& srgbe = processor.cast<GrSRGBEffect>();
67         uint32_t key = static_cast<uint32_t>(srgbe.mode()) |
68                       (static_cast<uint32_t>(srgbe.alpha()) << 1);
69         b->add32(key);
70     }
71 
72 private:
73     typedef GrGLSLFragmentProcessor INHERITED;
74 };
75 
76 ///////////////////////////////////////////////////////////////////////////////
77 
GrSRGBEffect(Mode mode,Alpha alpha)78 GrSRGBEffect::GrSRGBEffect(Mode mode, Alpha alpha)
79     : INHERITED(kGrSRGBEffect_ClassID, kPreservesOpaqueInput_OptimizationFlag |
80                 kConstantOutputForConstantInput_OptimizationFlag)
81     , fMode(mode)
82     , fAlpha(alpha)
83 {
84 }
85 
clone() const86 std::unique_ptr<GrFragmentProcessor> GrSRGBEffect::clone() const { return Make(fMode, fAlpha); }
87 
onIsEqual(const GrFragmentProcessor & s) const88 bool GrSRGBEffect::onIsEqual(const GrFragmentProcessor& s) const {
89     const GrSRGBEffect& other = s.cast<GrSRGBEffect>();
90     return other.fMode == fMode;
91 }
92 
srgb_to_linear(float srgb)93 static inline float srgb_to_linear(float srgb) {
94     return (srgb <= 0.04045f) ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
95 }
linear_to_srgb(float linear)96 static inline float linear_to_srgb(float linear) {
97     return (linear <= 0.0031308) ? linear * 12.92f : 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
98 }
99 
constantOutputForConstantInput(const SkPMColor4f & inColor) const100 SkPMColor4f GrSRGBEffect::constantOutputForConstantInput(const SkPMColor4f& inColor) const {
101     SkColor4f color = inColor.unpremul();
102     switch (fMode) {
103         case Mode::kLinearToSRGB:
104             color = { linear_to_srgb(color.fR), linear_to_srgb(color.fG), linear_to_srgb(color.fB),
105                       color.fA };
106             break;
107         case Mode::kSRGBToLinear:
108             color = { srgb_to_linear(color.fR), srgb_to_linear(color.fG), srgb_to_linear(color.fB),
109                       color.fA };
110             break;
111     }
112     return color.premul();
113 }
114 
115 ///////////////////////////////////////////////////////////////////////////////
116 
117 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect);
118 
119 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)120 std::unique_ptr<GrFragmentProcessor> GrSRGBEffect::TestCreate(GrProcessorTestData* d) {
121     Mode testMode = static_cast<Mode>(d->fRandom->nextRangeU(0, 1));
122     return GrSRGBEffect::Make(testMode, Alpha::kPremul);
123 }
124 #endif
125 
126 ///////////////////////////////////////////////////////////////////////////////
127 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const128 void GrSRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
129                                           GrProcessorKeyBuilder* b) const {
130     GrGLSRGBEffect::GenKey(*this, caps, b);
131 }
132 
onCreateGLSLInstance() const133 GrGLSLFragmentProcessor* GrSRGBEffect::onCreateGLSLInstance() const {
134     return new GrGLSRGBEffect;
135 }
136 
137