• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ge_aurora_noise_shader.h"
16 
17 #include "ge_log.h"
18 #include "ge_visual_effect_impl.h"
19 
20 namespace OHOS {
21 namespace Rosen {
22 namespace {
23 static constexpr char AURORA_GENERATOR_PROG[] = R"(
24     uniform vec2 iResolution;
25     uniform float noise;
26     const float contrast = 4.64; // contrast constant, 464.0 / 100.0
27     const float brightness = -0.17647; // brightness constant, -45.0 / 255.0
28     const float downSampleFactor = 8.0;
29     float SNoise(in vec3 v);
30     vec4 main(vec2 fragCoord)
31     {
32         vec2 tileSize = iResolution.xy / downSampleFactor;
33         vec2 localXY = mod(fragCoord, tileSize);
34         if (floor(fragCoord.x / tileSize.x) > 0.5 || floor(fragCoord.y / tileSize.y) > 0.5) {
35             return vec4(0.0);
36         }
37         vec2 uv = (localXY + 0.5) / tileSize;
38         float aspect = iResolution.x / iResolution.y;
39         vec2 p = vec2((uv.x / 0.75 - 1.0) * aspect, (uv.y * 2.0 - 1.0)); // horizontal stretch and map uv
40         float freqX = 2.0;
41         float freqY = mix(freqX, freqX * 0.5, smoothstep(1.0, 0.0, uv.y));
42         vec2 dom = vec2(p.x * freqX, p.y * freqY);
43         float n = abs(SNoise(vec3(dom, noise * 3.0)));
44         float alpha = clamp(1.0 - (n * contrast + brightness), 0.0, 1.0);
45         return vec4(alpha);
46     }
47 
48     vec3 Mod289(in vec3 x)
49     {
50         return x - floor(x * (1.0 / 289.0)) * 289.0; // 289.0: prime number for permutation
51     }
52 
53     vec4 Mod289(in vec4 x)
54     {
55         return x - floor(x * (1.0 / 289.0)) * 289.0; // 289.0: prime number for permutation
56     }
57 
58     vec4 Permute(in vec4 x)
59     {
60         return Mod289(((x * 34.0) + 1.0) * x); // 34.0: prime number for permutation
61     }
62 
63     vec4 TaylorInvSqrt(in vec4 r)
64     {
65         return 1.79284291400159 - 0.85373472095314 * r; // Taylor series approximation for 1/sqrt(x)
66     }
67 
68     float SNoise(in vec3 v)
69     {
70         const vec2 c = vec2(0.16666666666667, 0.33333333333333); // Constants for noise function, 1/6 and 1/3
71         const vec4 d = vec4(0.0, 0.5, 1.0, 2.0); // Constants for noise function
72         // First corner
73         vec3 i = floor(v + dot(v, c.yyy));
74         vec3 x0 = v - i + dot(i, c.xxx);
75         // Other corners
76         vec3 g = step(x0.yzx, x0.xyz);
77         vec3 l = 1.0 - g;
78         vec3 i1 = min(g.xyz, l.zxy);
79         vec3 i2 = max(g.xyz, l.zxy);
80         vec3 x1 = x0 - i1 + c.xxx;
81         vec3 x2 = x0 - i2 + c.yyy; // 2.0 * c.x = 1/3 = c.y
82         vec3 x3 = x0 - d.yyy; // -1.0 + 3.0 * c.x = -0.5 = -d.y
83         // Permutations
84         i = Mod289(i);
85         vec4 p = Permute(Permute(Permute(
86             i.z + vec4(0.0, i1.z, i2.z, 1.0))
87             + i.y + vec4(0.0, i1.y, i2.y, 1.0))
88             + i.x + vec4(0.0, i1.x, i2.x, 1.0));
89         float n = 0.142857142857; // i.e., 1.0 / 7.0
90         vec3 ns = n * d.wyz - d.xzx;
91         vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // 49.0: mod(p, 7 * 7)
92         vec4 xs = floor(j * ns.z);
93         vec4 ys = floor(j - 7.0 * xs); // mod(j, N) // 7.0: mod(p, 7)
94         vec4 x = xs *ns.x + ns.yyyy;
95         vec4 y = ys *ns.x + ns.yyyy;
96         vec4 h = 1.0 - abs(x) - abs(y);
97         vec4 b0 = vec4(x.xy, y.xy);
98         vec4 b1 = vec4(x.zw, y.zw);
99         vec4 s0 = floor(b0) * 2.0 + 1.0; // 2.0: step size
100         vec4 s1 = floor(b1) * 2.0 + 1.0; // 2.0: step size
101         vec4 sh = -step(h, vec4(0.0));
102         vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy ;
103         vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww ;
104         vec3 p0 = vec3(a0.xy, h.x);
105         vec3 p1 = vec3(a0.zw, h.y);
106         vec3 p2 = vec3(a1.xy, h.z);
107         vec3 p3 = vec3(a1.zw, h.w);
108         // Normalise gradients
109         vec4 norm = TaylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
110         p0 *= norm.x;
111         p1 *= norm.y;
112         p2 *= norm.z;
113         p3 *= norm.w;
114         // Mix final noise value
115         vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); // 0.6: falloff start
116         m = m * m;
117         return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); // scale to [-1,1]
118     }
119 )";
120 
121 static constexpr char AURORA_VERT_BLUR_PROG[] = R"(
122     uniform shader auroraNoiseTexture;
123     uniform vec2 iResolution;
124     const float downSampleFactor = 8.0;
125     const int sampleCount = 20;
126 
127     vec4 SampleWholeTile(vec2 fragCoord, vec2 res)
128     {
129         vec2 tileSize = res / downSampleFactor;
130         vec2 uvInTile = fragCoord / res;
131         vec2 pixel = uvInTile * (tileSize - 1.0);
132         return auroraNoiseTexture.eval(pixel + 0.5);
133     }
134 
135     vec4 main(vec2 fragCoord)
136     {
137         vec2 tileSize = iResolution.xy / downSampleFactor;
138         vec2 localXY = mod(fragCoord, tileSize);
139         if (floor(fragCoord.x / tileSize.x) > 0.5 || floor(fragCoord.y / tileSize.y) > 0.5) {
140             return vec4(0.0);
141         }
142         vec2 uv = (localXY + 0.5) / tileSize;
143         float dist = 1.2 - uv.y; // 1.2: origin height of the vertical blur
144         float blurRadius = mix(0.0, 0.3, smoothstep(0.0, 1.2, dist)); // 0.3: blur radius on top, 1.2: origin
145         vec4 col = vec4(0.0);
146         float totalWeight = 0.0;
147         for (int i = 0; i < sampleCount; ++i) {
148             float s = float(i) / float(sampleCount);
149             vec2 offset = vec2(0.0, s * blurRadius);
150             vec2 sampleUV = uv + offset;
151             sampleUV = clamp(sampleUV, vec2(0.0), vec2(1.0));
152             vec2 sampleCoord = sampleUV * iResolution.xy;
153             float weight = 1.0 - abs(s);
154             col += SampleWholeTile(sampleCoord, iResolution.xy) * weight;
155             totalWeight += weight;
156         }
157         return col / totalWeight;
158     }
159 )";
160 } // anonymous namespace
161 
GEAuroraNoiseShader()162 GEAuroraNoiseShader::GEAuroraNoiseShader() {}
163 
GEAuroraNoiseShader(Drawing::GEAuroraNoiseShaderParams & param)164 GEAuroraNoiseShader::GEAuroraNoiseShader(Drawing::GEAuroraNoiseShaderParams& param)
165 {
166     auroraNoiseParams_ = param;
167 }
168 
CreateAuroraNoiseShader(Drawing::GEAuroraNoiseShaderParams & param)169 std::shared_ptr<GEAuroraNoiseShader> GEAuroraNoiseShader::CreateAuroraNoiseShader(
170     Drawing::GEAuroraNoiseShaderParams& param)
171 {
172     std::shared_ptr<GEAuroraNoiseShader> auroraNoiseShader = std::make_shared<GEAuroraNoiseShader>(param);
173     return auroraNoiseShader;
174 }
175 
MakeDrawingShader(const Drawing::Rect & rect,float progress)176 void GEAuroraNoiseShader::MakeDrawingShader(const Drawing::Rect& rect, float progress)
177 {
178     drShader_ = MakeAuroraNoiseShader(rect);
179 }
180 
Preprocess(Drawing::Canvas & canvas,const Drawing::Rect & rect)181 void GEAuroraNoiseShader::Preprocess(Drawing::Canvas& canvas, const Drawing::Rect& rect)
182 {
183     Drawing::ImageInfo downSampledImg(rect.GetWidth(), rect.GetHeight(),
184         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE);
185     noiseImg_ = MakeAuroraNoiseGeneratorShader(canvas, downSampledImg);
186     Drawing::ImageInfo verticalBlurImgInf(rect.GetWidth(), rect.GetHeight(),
187         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_OPAQUE);
188     verticalBlurImg_ = MakeAuroraNoiseVerticalBlurShader(canvas, verticalBlurImgInf);
189 }
190 
MakeAuroraNoiseGeneratorShader(Drawing::Canvas & canvas,const Drawing::ImageInfo & imageInfo)191 std::shared_ptr<Drawing::Image> GEAuroraNoiseShader::MakeAuroraNoiseGeneratorShader(
192     Drawing::Canvas& canvas, const Drawing::ImageInfo& imageInfo)
193 {
194     float width = imageInfo.GetWidth();
195     float height = imageInfo.GetHeight();
196     builder_ = GetAuroraNoiseBuilder();
197     builder_->SetUniform("iResolution", width, height);
198     builder_->SetUniform("noise", auroraNoiseParams_.noise_);
199     auto auroraNoiseGeneratorShader = builder_->MakeImage(canvas.GetGPUContext().get(), nullptr, imageInfo, false);
200     if (auroraNoiseGeneratorShader == nullptr) {
201         GE_LOGE("GEAuroraNoiseShader auroraNoiseGeneratorShader is nullptr.");
202         return nullptr;
203     }
204     return auroraNoiseGeneratorShader;
205 }
206 
MakeAuroraNoiseVerticalBlurShader(Drawing::Canvas & canvas,const Drawing::ImageInfo & imageInfo)207 std::shared_ptr<Drawing::Image> GEAuroraNoiseShader::MakeAuroraNoiseVerticalBlurShader(
208     Drawing::Canvas& canvas, const Drawing::ImageInfo& imageInfo)
209 {
210     if (noiseImg_ == nullptr) {
211         GE_LOGE("GEAuroraNoiseShader MakeAuroraNoiseVerticalBlurShader noiseImg_ is nullptr.");
212         return nullptr;
213     }
214     float width = imageInfo.GetWidth();
215     float height = imageInfo.GetHeight();
216     verticalBlurBuilder_ = GetAuroraNoiseVerticalBlurBuilder();
217     if (verticalBlurBuilder_ == nullptr) {
218         GE_LOGE("GEAuroraNoiseShader::MakeAuroraNoiseVerticalBlurShader verticalBlurBuilder_ is nullptr.");
219         return nullptr;
220     }
221     Drawing::Matrix matrix;
222     auto auroraNoiseShader = Drawing::ShaderEffect::CreateImageShader(*noiseImg_,
223         Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP,
224         Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
225     verticalBlurBuilder_->SetChild("auroraNoiseTexture", auroraNoiseShader);
226     verticalBlurBuilder_->SetUniform("iResolution", width, height);
227     auto auroraNoiseVerticalBlurShader =
228         verticalBlurBuilder_->MakeImage(canvas.GetGPUContext().get(), nullptr, imageInfo, false);
229     if (auroraNoiseVerticalBlurShader == nullptr) {
230         GE_LOGE("GEAuroraNoiseShader::MakeAuroraNoiseVerticalBlurShader auroraNoiseVerticalBlurShader is nullptr.");
231         return nullptr;
232     }
233     return auroraNoiseVerticalBlurShader;
234 }
235 
GetAuroraNoiseBuilder()236 std::shared_ptr<Drawing::RuntimeShaderBuilder> GEAuroraNoiseShader::GetAuroraNoiseBuilder()
237 {
238     thread_local std::shared_ptr<Drawing::RuntimeEffect> auroraNoiseShaderEffect_ = nullptr;
239     if (auroraNoiseShaderEffect_ == nullptr) {
240         auroraNoiseShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(AURORA_GENERATOR_PROG);
241     }
242 
243     if (auroraNoiseShaderEffect_ == nullptr) {
244         GE_LOGE("GEAuroraNoiseShader::GetAuroraNoiseBuilder auroraNoiseShaderEffect_ is nullptr.");
245         return nullptr;
246     }
247     return std::make_shared<Drawing::RuntimeShaderBuilder>(auroraNoiseShaderEffect_);
248 }
249 
GetAuroraNoiseVerticalBlurBuilder()250 std::shared_ptr<Drawing::RuntimeShaderBuilder> GEAuroraNoiseShader::GetAuroraNoiseVerticalBlurBuilder()
251 {
252     thread_local std::shared_ptr<Drawing::RuntimeEffect> auroraNoiseVerticalBlurShaderEffect_ = nullptr;
253 
254     if (auroraNoiseVerticalBlurShaderEffect_ == nullptr) {
255         auroraNoiseVerticalBlurShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(AURORA_VERT_BLUR_PROG);
256     }
257 
258     if (auroraNoiseVerticalBlurShaderEffect_ == nullptr) {
259         GE_LOGE("GEAuroraNoiseShader::GetAuroraNoiseBuilder auroraNoiseVerticalBlurShaderEffect_ is nullptr.");
260         return nullptr;
261     }
262     return std::make_shared<Drawing::RuntimeShaderBuilder>(auroraNoiseVerticalBlurShaderEffect_);
263 }
264 
GetAuroraNoiseUpSamplingBuilder()265 std::shared_ptr<Drawing::RuntimeShaderBuilder> GEAuroraNoiseShader::GetAuroraNoiseUpSamplingBuilder()
266 {
267     thread_local std::shared_ptr<Drawing::RuntimeEffect> auroraNoiseUpSamplingShaderEffect_ = nullptr;
268     if (auroraNoiseUpSamplingShaderEffect_ == nullptr) {
269         static constexpr char prog[] = R"(
270             uniform shader verticalBlurTexture;
271             uniform vec2 iResolution;
272 
273             const float downSampleFactor = 8.0;
274 
275             vec4 main(vec2 fragCoord)
276             {
277                 vec2 tileSize = iResolution.xy / downSampleFactor;
278                 vec2 uvInTile = fragCoord / iResolution.xy;
279                 vec2 pixel = uvInTile * (tileSize - 1.0);
280                 return verticalBlurTexture.eval(pixel + 0.5);
281             }
282         )";
283         auroraNoiseUpSamplingShaderEffect_ = Drawing::RuntimeEffect::CreateForShader(prog);
284     }
285 
286     if (auroraNoiseUpSamplingShaderEffect_ == nullptr) {
287         GE_LOGE("GEAuroraNoiseShader auroraNoiseUpSamplingShaderEffect_ is nullptr.");
288         return nullptr;
289     }
290     return std::make_shared<Drawing::RuntimeShaderBuilder>(auroraNoiseUpSamplingShaderEffect_);
291 }
292 
MakeAuroraNoiseShader(const Drawing::Rect & rect)293 std::shared_ptr<Drawing::ShaderEffect> GEAuroraNoiseShader::MakeAuroraNoiseShader(const Drawing::Rect& rect)
294 {
295     if (verticalBlurImg_ == nullptr) {
296         GE_LOGE("GEAuroraNoiseShader MakeAuroraNoiseShader verticalBlurImg_ is nullptr.");
297         return nullptr;
298     }
299     auto width = rect.GetWidth();
300     auto height = rect.GetHeight();
301     Drawing::Matrix matrix;
302     auto verticalBlurShader = Drawing::ShaderEffect::CreateImageShader(*verticalBlurImg_, Drawing::TileMode::CLAMP,
303         Drawing::TileMode::CLAMP, Drawing::SamplingOptions(Drawing::FilterMode::LINEAR), matrix);
304     upSamplingBuilder_ = GetAuroraNoiseUpSamplingBuilder();
305     if (upSamplingBuilder_ == nullptr) {
306         GE_LOGE("GEAuroraNoiseShader::MakeAuroraNoiseShader upSamplingBuilder_ is nullptr.");
307         return nullptr;
308     }
309     upSamplingBuilder_->SetChild("verticalBlurTexture", verticalBlurShader);
310     upSamplingBuilder_->SetUniform("iResolution", width, height);
311     auto auroraNoiseUpSamplingShader = upSamplingBuilder_->MakeShader(nullptr, false);
312     if (auroraNoiseUpSamplingShader == nullptr) {
313         GE_LOGE("GEAuroraNoiseShader::MakeAuroraNoiseShader auroraNoiseUpSamplingShader is nullptr.");
314         return nullptr;
315     }
316     return auroraNoiseUpSamplingShader;
317 }
318 
319 } // namespace Rosen
320 } // namespace OHOS