Flutter Engine
The Flutter Engine
SkGainmapShader.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 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
9
22
23#include <cmath>
24#include <cstdint>
25
26static constexpr char gGainmapSKSL[] =
27 "uniform shader base;"
28 "uniform shader gainmap;"
29 "uniform half4 logRatioMin;"
30 "uniform half4 logRatioMax;"
31 "uniform half4 gainmapGamma;"
32 "uniform half4 epsilonBase;"
33 "uniform half4 epsilonOther;"
34 "uniform half W;"
35 "uniform int gainmapIsAlpha;"
36 "uniform int gainmapIsRed;"
37 "uniform int singleChannel;"
38 "uniform int noGamma;"
39 "uniform int isApple;"
40 "uniform half appleG;"
41 "uniform half appleH;"
42 ""
43 "half4 main(float2 coord) {"
44 "half4 S = base.eval(coord);"
45 "half4 G = gainmap.eval(coord);"
46 "if (gainmapIsAlpha == 1) {"
47 "G = half4(G.a, G.a, G.a, 1.0);"
48 "}"
49 "if (gainmapIsRed == 1) {"
50 "G = half4(G.r, G.r, G.r, 1.0);"
51 "}"
52 "if (singleChannel == 1) {"
53 "half L;"
54 "if (isApple == 1) {"
55 "L = pow(G.r, appleG);"
56 "L = log(1.0 + (appleH - 1.0) * pow(G.r, appleG));"
57 "} else if (noGamma == 1) {"
58 "L = mix(logRatioMin.r, logRatioMax.r, G.r);"
59 "} else {"
60 "L = mix(logRatioMin.r, logRatioMax.r, pow(G.r, gainmapGamma.r));"
61 "}"
62 "half3 H = (S.rgb + epsilonBase.rgb) * exp(L * W) - epsilonOther.rgb;"
63 "return half4(H.r, H.g, H.b, S.a);"
64 "} else {"
65 "half3 L;"
66 "if (isApple == 1) {"
67 "L = pow(G.rgb, half3(appleG));"
68 "L = log(half3(1.0) + (appleH - 1.0) * L);"
69 "} else if (noGamma == 1) {"
70 "L = mix(logRatioMin.rgb, logRatioMax.rgb, G.rgb);"
71 "} else {"
72 "L = mix(logRatioMin.rgb, logRatioMax.rgb, pow(G.rgb, gainmapGamma.rgb));"
73 "}"
74 "half3 H = (S.rgb + epsilonBase.rgb) * exp(L * W) - epsilonOther.rgb;"
75 "return half4(H.r, H.g, H.b, S.a);"
76 "}"
77 "}";
78
80 static const SkRuntimeEffect* effect =
82 SkASSERT(effect);
83 return sk_ref_sp(effect);
84}
85
86static bool all_channels_equal(const SkColor4f& c) {
87 return c.fR == c.fG && c.fR == c.fB;
88}
89
91 const SkRect& baseRect,
92 const SkSamplingOptions& baseSamplingOptions,
93 const sk_sp<const SkImage>& gainmapImage,
94 const SkRect& gainmapRect,
95 const SkSamplingOptions& gainmapSamplingOptions,
96 const SkGainmapInfo& gainmapInfo,
97 const SkRect& dstRect,
98 float dstHdrRatio,
99 sk_sp<SkColorSpace> dstColorSpace) {
100 sk_sp<SkColorSpace> baseColorSpace =
101 baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB();
102
103 // Determine the color space in which the gainmap math is to be applied.
104 sk_sp<SkColorSpace> gainmapMathColorSpace =
105 gainmapInfo.fGainmapMathColorSpace
107 : baseColorSpace->makeLinearGamma();
108 if (!dstColorSpace) {
109 dstColorSpace = SkColorSpace::MakeSRGB();
110 }
111
112 // Compute the sampling transformation matrices.
113 const SkMatrix baseRectToDstRect = SkMatrix::RectToRect(baseRect, dstRect);
114 const SkMatrix gainmapRectToDstRect = SkMatrix::RectToRect(gainmapRect, dstRect);
115
116 // Compute the weight parameter that will be used to blend between the images.
117 float W = 0.f;
118 if (dstHdrRatio > gainmapInfo.fDisplayRatioSdr) {
119 if (dstHdrRatio < gainmapInfo.fDisplayRatioHdr) {
120 W = (std::log(dstHdrRatio) - std::log(gainmapInfo.fDisplayRatioSdr)) /
121 (std::log(gainmapInfo.fDisplayRatioHdr) -
122 std::log(gainmapInfo.fDisplayRatioSdr));
123 } else {
124 W = 1.f;
125 }
126 }
127
128 const bool baseImageIsHdr = (gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR);
129 if (baseImageIsHdr) {
130 W -= 1.f;
131 }
132
133 // Return the base image directly if the gainmap will not be applied at all.
134 if (W == 0.f) {
135 return baseImage->makeShader(baseSamplingOptions, &baseRectToDstRect);
136 }
137
138 // Create a color filter to transform from the base image's color space to the color space in
139 // which the gainmap is to be applied.
140 auto colorXformSdrToGainmap =
141 SkColorFilterPriv::MakeColorSpaceXform(baseColorSpace, gainmapMathColorSpace);
142
143 // Create a color filter to transform from the color space in which the gainmap is applied to
144 // the destination color space.
145 auto colorXformGainmapToDst =
146 SkColorFilterPriv::MakeColorSpaceXform(gainmapMathColorSpace, dstColorSpace);
147
148 // The base image shader will convert into the color space in which the gainmap is applied.
149 auto baseImageShader = baseImage->makeRawShader(baseSamplingOptions, &baseRectToDstRect)
150 ->makeWithColorFilter(colorXformSdrToGainmap);
151
152 // The gainmap image shader will ignore any color space that the gainmap has.
153 auto gainmapImageShader =
154 gainmapImage->makeRawShader(gainmapSamplingOptions, &gainmapRectToDstRect);
155
156 // Create the shader to apply the gainmap.
157 sk_sp<SkShader> gainmapMathShader;
158 {
160 const SkColor4f logRatioMin({std::log(gainmapInfo.fGainmapRatioMin.fR),
161 std::log(gainmapInfo.fGainmapRatioMin.fG),
162 std::log(gainmapInfo.fGainmapRatioMin.fB),
163 1.f});
164 const SkColor4f logRatioMax({std::log(gainmapInfo.fGainmapRatioMax.fR),
165 std::log(gainmapInfo.fGainmapRatioMax.fG),
166 std::log(gainmapInfo.fGainmapRatioMax.fB),
167 1.f});
168 const int noGamma =
169 gainmapInfo.fGainmapGamma.fR == 1.f &&
170 gainmapInfo.fGainmapGamma.fG == 1.f &&
171 gainmapInfo.fGainmapGamma.fB == 1.f;
172 const uint32_t colorTypeFlags = SkColorTypeChannelFlags(gainmapImage->colorType());
173 const int gainmapIsAlpha = colorTypeFlags == kAlpha_SkColorChannelFlag;
174 const int gainmapIsRed = colorTypeFlags == kRed_SkColorChannelFlag;
175 const int singleChannel = all_channels_equal(gainmapInfo.fGainmapGamma) &&
178 (colorTypeFlags == kGray_SkColorChannelFlag ||
179 colorTypeFlags == kAlpha_SkColorChannelFlag ||
180 colorTypeFlags == kRed_SkColorChannelFlag);
181 const SkColor4f& epsilonBase =
182 baseImageIsHdr ? gainmapInfo.fEpsilonHdr : gainmapInfo.fEpsilonSdr;
183 const SkColor4f& epsilonOther =
184 baseImageIsHdr ? gainmapInfo.fEpsilonSdr : gainmapInfo.fEpsilonHdr;
185
186 const int isApple = gainmapInfo.fType == SkGainmapInfo::Type::kApple;
187 const float appleG = 1.961f;
188 const float appleH = gainmapInfo.fDisplayRatioHdr;
189
190 builder.child("base") = baseImageShader;
191 builder.child("gainmap") = gainmapImageShader;
192 builder.uniform("logRatioMin") = logRatioMin;
193 builder.uniform("logRatioMax") = logRatioMax;
194 builder.uniform("gainmapGamma") = gainmapInfo.fGainmapGamma;
195 builder.uniform("epsilonBase") = epsilonBase;
196 builder.uniform("epsilonOther") = epsilonOther;
197 builder.uniform("noGamma") = noGamma;
198 builder.uniform("singleChannel") = singleChannel;
199 builder.uniform("gainmapIsAlpha") = gainmapIsAlpha;
200 builder.uniform("gainmapIsRed") = gainmapIsRed;
201 builder.uniform("W") = W;
202
203 builder.uniform("isApple") = isApple;
204 builder.uniform("appleG") = appleG;
205 builder.uniform("appleH") = appleH;
206
207 gainmapMathShader = builder.makeShader();
208 SkASSERT(gainmapMathShader);
209 }
210
211 // Return a shader that will apply the gainmap and then convert to the destination color space.
212 return gainmapMathShader->makeWithColorFilter(colorXformGainmapToDst);
213}
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kRed_SkColorChannelFlag
Definition: SkColor.h:239
@ kAlpha_SkColorChannelFlag
Definition: SkColor.h:242
@ kGray_SkColorChannelFlag
Definition: SkColor.h:243
static constexpr char gGainmapSKSL[]
static bool all_channels_equal(const SkColor4f &c)
static sk_sp< SkRuntimeEffect > gainmap_apply_effect()
static uint32_t SkColorTypeChannelFlags(SkColorType ct)
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define W
Definition: aaa.cpp:17
static sk_sp< SkColorFilter > MakeColorSpaceXform(sk_sp< SkColorSpace > src, sk_sp< SkColorSpace > dst)
sk_sp< SkColorSpace > makeLinearGamma() const
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkShader > Make(const sk_sp< const SkImage > &baseImage, const SkRect &baseRect, const SkSamplingOptions &baseSamplingOptions, const sk_sp< const SkImage > &gainmapImage, const SkRect &gainmapRect, const SkSamplingOptions &gainmapSamplingOptions, const SkGainmapInfo &gainmapInfo, const SkRect &dstRect, float dstHdrRatio, sk_sp< SkColorSpace > dstColorSpace)
SkColorSpace * colorSpace() const
Definition: SkImage.cpp:156
sk_sp< SkShader > makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:207
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
SkColorType colorType() const
Definition: SkImage.cpp:152
sk_sp< SkColorSpace > refColorSpace() const
Definition: SkImage.cpp:158
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
static Result MakeForShader(SkString sksl, const Options &)
sk_sp< SkShader > makeWithColorFilter(sk_sp< SkColorFilter >) const
Definition: SkShader.cpp:43
SkColor4f fGainmapRatioMax
Definition: SkGainmapInfo.h:49
SkColor4f fEpsilonSdr
Definition: SkGainmapInfo.h:55
SkColor4f fGainmapGamma
Definition: SkGainmapInfo.h:50
sk_sp< SkColorSpace > fGainmapMathColorSpace
Definition: SkGainmapInfo.h:95
SkColor4f fGainmapRatioMin
Definition: SkGainmapInfo.h:48
BaseImageType fBaseImageType
Definition: SkGainmapInfo.h:75
float fDisplayRatioSdr
Definition: SkGainmapInfo.h:65
SkColor4f fEpsilonHdr
Definition: SkGainmapInfo.h:56
float fDisplayRatioHdr
Definition: SkGainmapInfo.h:66