Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 ""
40 "half4 main(float2 coord) {"
41 "half4 S = base.eval(coord);"
42 "half4 G = gainmap.eval(coord);"
43 "if (gainmapIsAlpha == 1) {"
44 "G = half4(G.a, G.a, G.a, 1.0);"
45 "}"
46 "if (gainmapIsRed == 1) {"
47 "G = half4(G.r, G.r, G.r, 1.0);"
48 "}"
49 "if (singleChannel == 1) {"
50 "half L;"
51 "if (noGamma == 1) {"
52 "L = mix(logRatioMin.r, logRatioMax.r, G.r);"
53 "} else {"
54 "L = mix(logRatioMin.r, logRatioMax.r, pow(G.r, gainmapGamma.r));"
55 "}"
56 "half3 H = (S.rgb + epsilonBase.rgb) * exp(L * W) - epsilonOther.rgb;"
57 "return half4(H.r, H.g, H.b, S.a);"
58 "} else {"
59 "half3 L;"
60 "if (noGamma == 1) {"
61 "L = mix(logRatioMin.rgb, logRatioMax.rgb, G.rgb);"
62 "} else {"
63 "L = mix(logRatioMin.rgb, logRatioMax.rgb, pow(G.rgb, gainmapGamma.rgb));"
64 "}"
65 "half3 H = (S.rgb + epsilonBase.rgb) * exp(L * W) - epsilonOther.rgb;"
66 "return half4(H.r, H.g, H.b, S.a);"
67 "}"
68 "}";
69
71 static const SkRuntimeEffect* effect =
73 SkASSERT(effect);
74 return sk_ref_sp(effect);
75}
76
77static bool all_channels_equal(const SkColor4f& c) {
78 return c.fR == c.fG && c.fR == c.fB;
79}
80
82 const SkRect& baseRect,
83 const SkSamplingOptions& baseSamplingOptions,
84 const sk_sp<const SkImage>& gainmapImage,
85 const SkRect& gainmapRect,
86 const SkSamplingOptions& gainmapSamplingOptions,
87 const SkGainmapInfo& gainmapInfo,
88 const SkRect& dstRect,
89 float dstHdrRatio,
90 sk_sp<SkColorSpace> dstColorSpace) {
91 sk_sp<SkColorSpace> baseColorSpace =
92 baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB();
93
94 // Determine the color space in which the gainmap math is to be applied.
95 sk_sp<SkColorSpace> gainmapMathColorSpace =
96 gainmapInfo.fGainmapMathColorSpace
98 : baseColorSpace->makeLinearGamma();
99 if (!dstColorSpace) {
100 dstColorSpace = SkColorSpace::MakeSRGB();
101 }
102
103 // Compute the sampling transformation matrices.
104 const SkMatrix baseRectToDstRect = SkMatrix::RectToRect(baseRect, dstRect);
105 const SkMatrix gainmapRectToDstRect = SkMatrix::RectToRect(gainmapRect, dstRect);
106
107 // Compute the weight parameter that will be used to blend between the images.
108 float W = 0.f;
109 if (dstHdrRatio > gainmapInfo.fDisplayRatioSdr) {
110 if (dstHdrRatio < gainmapInfo.fDisplayRatioHdr) {
111 W = (std::log(dstHdrRatio) - std::log(gainmapInfo.fDisplayRatioSdr)) /
112 (std::log(gainmapInfo.fDisplayRatioHdr) -
113 std::log(gainmapInfo.fDisplayRatioSdr));
114 } else {
115 W = 1.f;
116 }
117 }
118
119 const bool baseImageIsHdr = (gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR);
120 if (baseImageIsHdr) {
121 W -= 1.f;
122 }
123
124 // Return the base image directly if the gainmap will not be applied at all.
125 if (W == 0.f) {
126 return baseImage->makeShader(baseSamplingOptions, &baseRectToDstRect);
127 }
128
129 // Create a color filter to transform from the base image's color space to the color space in
130 // which the gainmap is to be applied.
131 auto colorXformSdrToGainmap =
132 SkColorFilterPriv::MakeColorSpaceXform(baseColorSpace, gainmapMathColorSpace);
133
134 // Create a color filter to transform from the color space in which the gainmap is applied to
135 // the destination color space.
136 auto colorXformGainmapToDst =
137 SkColorFilterPriv::MakeColorSpaceXform(gainmapMathColorSpace, dstColorSpace);
138
139 // The base image shader will convert into the color space in which the gainmap is applied.
140 auto baseImageShader = baseImage->makeRawShader(baseSamplingOptions, &baseRectToDstRect)
141 ->makeWithColorFilter(colorXformSdrToGainmap);
142
143 // The gainmap image shader will ignore any color space that the gainmap has.
144 auto gainmapImageShader =
145 gainmapImage->makeRawShader(gainmapSamplingOptions, &gainmapRectToDstRect);
146
147 // Create the shader to apply the gainmap.
148 sk_sp<SkShader> gainmapMathShader;
149 {
151 const SkColor4f logRatioMin({std::log(gainmapInfo.fGainmapRatioMin.fR),
152 std::log(gainmapInfo.fGainmapRatioMin.fG),
153 std::log(gainmapInfo.fGainmapRatioMin.fB),
154 1.f});
155 const SkColor4f logRatioMax({std::log(gainmapInfo.fGainmapRatioMax.fR),
156 std::log(gainmapInfo.fGainmapRatioMax.fG),
157 std::log(gainmapInfo.fGainmapRatioMax.fB),
158 1.f});
159 const int noGamma =
160 gainmapInfo.fGainmapGamma.fR == 1.f &&
161 gainmapInfo.fGainmapGamma.fG == 1.f &&
162 gainmapInfo.fGainmapGamma.fB == 1.f;
163 const uint32_t colorTypeFlags = SkColorTypeChannelFlags(gainmapImage->colorType());
164 const int gainmapIsAlpha = colorTypeFlags == kAlpha_SkColorChannelFlag;
165 const int gainmapIsRed = colorTypeFlags == kRed_SkColorChannelFlag;
166 const int singleChannel = all_channels_equal(gainmapInfo.fGainmapGamma) &&
169 (colorTypeFlags == kGray_SkColorChannelFlag ||
170 colorTypeFlags == kAlpha_SkColorChannelFlag ||
171 colorTypeFlags == kRed_SkColorChannelFlag);
172 const SkColor4f& epsilonBase =
173 baseImageIsHdr ? gainmapInfo.fEpsilonHdr : gainmapInfo.fEpsilonSdr;
174 const SkColor4f& epsilonOther =
175 baseImageIsHdr ? gainmapInfo.fEpsilonSdr : gainmapInfo.fEpsilonHdr;
176 builder.child("base") = baseImageShader;
177 builder.child("gainmap") = gainmapImageShader;
178 builder.uniform("logRatioMin") = logRatioMin;
179 builder.uniform("logRatioMax") = logRatioMax;
180 builder.uniform("gainmapGamma") = gainmapInfo.fGainmapGamma;
181 builder.uniform("epsilonBase") = epsilonBase;
182 builder.uniform("epsilonOther") = epsilonOther;
183 builder.uniform("noGamma") = noGamma;
184 builder.uniform("singleChannel") = singleChannel;
185 builder.uniform("gainmapIsAlpha") = gainmapIsAlpha;
186 builder.uniform("gainmapIsRed") = gainmapIsRed;
187 builder.uniform("W") = W;
188 gainmapMathShader = builder.makeShader();
189 SkASSERT(gainmapMathShader);
190 }
191
192 // Return a shader that will apply the gainmap and then convert to the destination color space.
193 return gainmapMathShader->makeWithColorFilter(colorXformGainmapToDst);
194}
#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)
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition SkMatrix.h:157
static Result MakeForShader(SkString sksl, const Options &)
SkColor4f fGainmapRatioMax
SkColor4f fEpsilonSdr
SkColor4f fGainmapGamma
sk_sp< SkColorSpace > fGainmapMathColorSpace
SkColor4f fGainmapRatioMin
BaseImageType fBaseImageType
float fDisplayRatioSdr
SkColor4f fEpsilonHdr
float fDisplayRatioHdr