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 "GrSRGBEffect.h" 9 10 #include "GrFragmentProcessor.h" 11 #include "GrProcessor.h" 12 #include "glsl/GrGLSLFragmentProcessor.h" 13 #include "glsl/GrGLSLFragmentShaderBuilder.h" 14 15 class GrGLSRGBEffect : public GrGLSLFragmentProcessor { 16 public: 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("half nonZeroAlpha = max(color.a, 0.00001);"); 51 fragBuilder->codeAppendf("color = half4(color.rgb / nonZeroAlpha, color.a);"); 52 } 53 fragBuilder->codeAppendf("color = half4(%s(color.r), %s(color.g), %s(color.b), color.a);", 54 srgbFuncName.c_str(), 55 srgbFuncName.c_str(), 56 srgbFuncName.c_str()); 57 if (srgbe.alpha() == GrSRGBEffect::Alpha::kPremul) { 58 fragBuilder->codeAppendf("color = half4(color.rgb, 1) * color.a;"); 59 } 60 fragBuilder->codeAppendf("%s = color;", args.fOutputColor); 61 } 62 63 static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&, 64 GrProcessorKeyBuilder* b) { 65 const GrSRGBEffect& srgbe = processor.cast<GrSRGBEffect>(); 66 uint32_t key = static_cast<uint32_t>(srgbe.mode()) | 67 (static_cast<uint32_t>(srgbe.alpha()) << 1); 68 b->add32(key); 69 } 70 71 private: 72 typedef GrGLSLFragmentProcessor INHERITED; 73 }; 74 75 /////////////////////////////////////////////////////////////////////////////// 76 77 GrSRGBEffect::GrSRGBEffect(Mode mode, Alpha alpha) 78 : INHERITED(kGrSRGBEffect_ClassID, kPreservesOpaqueInput_OptimizationFlag | 79 kConstantOutputForConstantInput_OptimizationFlag) 80 , fMode(mode) 81 , fAlpha(alpha) 82 { 83 } 84 85 std::unique_ptr<GrFragmentProcessor> GrSRGBEffect::clone() const { return Make(fMode, fAlpha); } 86 87 bool GrSRGBEffect::onIsEqual(const GrFragmentProcessor& s) const { 88 const GrSRGBEffect& other = s.cast<GrSRGBEffect>(); 89 return other.fMode == fMode; 90 } 91 92 static inline float srgb_to_linear(float srgb) { 93 return (srgb <= 0.04045f) ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f); 94 } 95 static inline float linear_to_srgb(float linear) { 96 return (linear <= 0.0031308) ? linear * 12.92f : 1.055f * powf(linear, 1.f / 2.4f) - 0.055f; 97 } 98 99 SkPMColor4f GrSRGBEffect::constantOutputForConstantInput(const SkPMColor4f& inColor) const { 100 SkColor4f color = inColor.unpremul(); 101 switch (fMode) { 102 case Mode::kLinearToSRGB: 103 color = { linear_to_srgb(color.fR), linear_to_srgb(color.fG), linear_to_srgb(color.fB), 104 color.fA }; 105 break; 106 case Mode::kSRGBToLinear: 107 color = { srgb_to_linear(color.fR), srgb_to_linear(color.fG), srgb_to_linear(color.fB), 108 color.fA }; 109 break; 110 } 111 return color.premul(); 112 } 113 114 /////////////////////////////////////////////////////////////////////////////// 115 116 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSRGBEffect); 117 118 #if GR_TEST_UTILS 119 std::unique_ptr<GrFragmentProcessor> GrSRGBEffect::TestCreate(GrProcessorTestData* d) { 120 Mode testMode = static_cast<Mode>(d->fRandom->nextRangeU(0, 1)); 121 return GrSRGBEffect::Make(testMode, Alpha::kPremul); 122 } 123 #endif 124 125 /////////////////////////////////////////////////////////////////////////////// 126 127 void GrSRGBEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 128 GrProcessorKeyBuilder* b) const { 129 GrGLSRGBEffect::GenKey(*this, caps, b); 130 } 131 132 GrGLSLFragmentProcessor* GrSRGBEffect::onCreateGLSLInstance() const { 133 return new GrGLSRGBEffect; 134 } 135 136