• 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 
16 #include <chrono>
17 
18 #include "ge_log.h"
19 #include "ge_radial_gradient_shader_mask.h"
20 #include "utils/ge_trace.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 namespace Drawing {
25 
26 namespace {
27 constexpr static uint8_t SIZE_ARRAY = 12;  // 12 max length
28 // max radius should equals height of image, 2.0 is a scale from diameter to radius.
29 constexpr static float RADIUS_SCALE = 2.0f;
30 } // namespace
31 
GERadialGradientShaderMask(GERadialGradientShaderMaskParams param)32 GERadialGradientShaderMask::GERadialGradientShaderMask(GERadialGradientShaderMaskParams param) : param_(param) {}
33 
GenerateDrawingShader(float width,float height) const34 std::shared_ptr<ShaderEffect> GERadialGradientShaderMask::GenerateDrawingShader(float width, float height) const
35 {
36     GE_TRACE_NAME_FMT("GERadialGradientShaderMask::GenerateDrawingShader, Type: %s, Width: %g, Height: %g",
37         Drawing::GE_MASK_RADIAL_GRADIENT, width, height);
38     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder = nullptr;
39     builder = GetRadialGradientShaderMaskBuilder();
40     if (!builder) {
41         LOGE("GERadialGradientShaderMask::GenerateDrawingShaderHas builder error");
42         return nullptr;
43     }
44     auto radialGradientMaskEffectShader = GenerateShaderEffect(width, height, builder);
45 
46     return radialGradientMaskEffectShader;
47 }
48 
GetRadialGradientShaderMaskBuilder() const49 std::shared_ptr<Drawing::RuntimeShaderBuilder> GERadialGradientShaderMask::GetRadialGradientShaderMaskBuilder() const
50 {
51     thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> radialGradientShaderMaskBuilder = nullptr;
52     if (radialGradientShaderMaskBuilder) {
53         return radialGradientShaderMaskBuilder;
54     }
55 
56     static constexpr char prog[] = R"(
57         const int sizeArray = 12;
58         uniform half2 iResolution;
59         uniform half2 centerPos;
60         uniform half radiusX;
61         uniform half radiusY;
62         uniform half colors[sizeArray];
63         uniform half positions[sizeArray];
64 
65         float radialGradientMask(vec2 uv, vec2 centerPosition)
66         {
67             float sdfValue = length(uv - centerPosition) / radiusY;
68             sdfValue = clamp(sdfValue, 0.0, 1.0);
69 
70             half color = 0.0;
71             color = (sdfValue >= positions[0] && sdfValue < positions[1])
72                 ? mix(colors[0], colors[1], smoothstep(positions[0], positions[1], sdfValue)) : color;
73             color = (sdfValue >= positions[1] && sdfValue < positions[2])
74                 ? mix(colors[1], colors[2], smoothstep(positions[1], positions[2], sdfValue)) : color;
75             color = (sdfValue >= positions[2] && sdfValue < positions[3])
76                 ? mix(colors[2], colors[3], smoothstep(positions[2], positions[3], sdfValue)) : color;
77             color = (sdfValue >= positions[3] && sdfValue < positions[4])
78                 ? mix(colors[3], colors[4], smoothstep(positions[3], positions[4], sdfValue)) : color;
79             color = (sdfValue >= positions[4] && sdfValue < positions[5])
80                 ? mix(colors[4], colors[5], smoothstep(positions[4], positions[5], sdfValue)) : color;
81             color = (sdfValue >= positions[5] && sdfValue < positions[6])
82                 ? mix(colors[5], colors[6], smoothstep(positions[5], positions[6], sdfValue)) : color;
83             color = (sdfValue >= positions[6] && sdfValue < positions[7])
84                 ? mix(colors[6], colors[7], smoothstep(positions[6], positions[7], sdfValue)) : color;
85             color = (sdfValue >= positions[7] && sdfValue < positions[8])
86                 ? mix(colors[7], colors[8], smoothstep(positions[7], positions[8], sdfValue)) : color;
87             color = (sdfValue >= positions[8] && sdfValue < positions[9])
88                 ? mix(colors[8], colors[9], smoothstep(positions[8], positions[9], sdfValue)) : color;
89             color = (sdfValue >= positions[9] && sdfValue < positions[10])
90                 ? mix(colors[9], colors[10], smoothstep(positions[9], positions[10], sdfValue)) : color;
91             color = (sdfValue >= positions[10] && sdfValue < positions[11])
92                 ? mix(colors[10], colors[11], smoothstep(positions[10], positions[11], sdfValue)) : color;
93             return color;
94         }
95 
96         half4 main(vec2 fragCoord)
97         {
98             vec2 uv = fragCoord.xy / iResolution.xy;
99             float screenRatio = iResolution.x / iResolution.y;
100             vec2 centeredUVs = uv * 2.0 - 1.0;
101             centeredUVs.x *= screenRatio * (radiusY / radiusX);
102             vec2 centerPosition = centerPos * 2 - 1.0 ;
103             centerPosition.x *= screenRatio * (radiusY / radiusX);
104 
105             half finalColor = radialGradientMask(centeredUVs, centerPosition);
106             return half4(finalColor);
107         }
108     )";
109 
110     auto radialGradientShaderMaskEffect = Drawing::RuntimeEffect::CreateForShader(prog);
111     if (!radialGradientShaderMaskEffect) {
112         LOGE("GERadialGradientShaderMask::GetRadialGradientShaderMaskBuilder effect error");
113         return nullptr;
114     }
115 
116     radialGradientShaderMaskBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(radialGradientShaderMaskEffect);
117     return radialGradientShaderMaskBuilder;
118 }
119 
GenerateDrawingShaderHasNormal(float width,float height) const120 std::shared_ptr<ShaderEffect> GERadialGradientShaderMask::GenerateDrawingShaderHasNormal(float width,
121     float height) const
122 {
123     GE_TRACE_NAME_FMT("GERadialGradientShaderMask::GenerateDrawingShaderHasNormal, Type: %s, Width: %g, Height: %g",
124         Drawing::GE_MASK_RADIAL_GRADIENT, width, height);
125     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder = nullptr;
126     builder = GetRadialGradientNormalMaskBuilder();
127     if (!builder) {
128         LOGE("GERadialGradientShaderMask::GenerateDrawingShaderHasNormal builder error");
129         return nullptr;
130     }
131     auto radialGradientMaskEffectShader = GenerateShaderEffect(width, height, builder);
132 
133     return radialGradientMaskEffectShader;
134 }
135 
GetRadialGradientNormalMaskBuilder() const136 std::shared_ptr<Drawing::RuntimeShaderBuilder> GERadialGradientShaderMask::GetRadialGradientNormalMaskBuilder() const
137 {
138     thread_local std::shared_ptr<Drawing::RuntimeShaderBuilder> radialGradientMaskNormalBuilder = nullptr;
139     if (radialGradientMaskNormalBuilder) {
140         return radialGradientMaskNormalBuilder;
141     }
142 
143     static constexpr char prog[] = R"(
144         const int sizeArray = 12;
145         uniform half2 iResolution;
146         uniform half2 centerPos;
147         uniform half radiusX;
148         uniform half radiusY;
149         uniform half colors[sizeArray];
150         uniform half positions[sizeArray];
151 
152         float colorGradient(float colorA, float colorB, float startPos, float endPos, float threshold)
153         {
154             if (startPos <= threshold && threshold < endPos) {
155                 return mix(colorA, colorB, smoothstep(startPos, endPos, threshold));
156             }
157             return 0.0;
158         }
159 
160         vec4 radialGradientMask(vec2 uv, vec2 centerPosition)
161         {
162             vec2 vector = uv - centerPosition;
163             float distance = length(vector);
164             float sdfValue = distance / radiusY;
165             sdfValue = clamp(sdfValue, 0.0, 1.0);
166 
167             half color = 0.0;
168             color = (sdfValue >= positions[0] && sdfValue < positions[1])
169                 ? mix(colors[0], colors[1], smoothstep(positions[0], positions[1], sdfValue)) : color;
170             color = (sdfValue >= positions[1] && sdfValue < positions[2])
171                 ? mix(colors[1], colors[2], smoothstep(positions[1], positions[2], sdfValue)) : color;
172             color = (sdfValue >= positions[2] && sdfValue < positions[3])
173                 ? mix(colors[2], colors[3], smoothstep(positions[2], positions[3], sdfValue)) : color;
174             color = (sdfValue >= positions[3] && sdfValue < positions[4])
175                 ? mix(colors[3], colors[4], smoothstep(positions[3], positions[4], sdfValue)) : color;
176             color = (sdfValue >= positions[4] && sdfValue < positions[5])
177                 ? mix(colors[4], colors[5], smoothstep(positions[4], positions[5], sdfValue)) : color;
178             color = (sdfValue >= positions[5] && sdfValue < positions[6])
179                 ? mix(colors[5], colors[6], smoothstep(positions[5], positions[6], sdfValue)) : color;
180             color = (sdfValue >= positions[6] && sdfValue < positions[7])
181                 ? mix(colors[6], colors[7], smoothstep(positions[6], positions[7], sdfValue)) : color;
182             color = (sdfValue >= positions[7] && sdfValue < positions[8])
183                 ? mix(colors[7], colors[8], smoothstep(positions[7], positions[8], sdfValue)) : color;
184             color = (sdfValue >= positions[8] && sdfValue < positions[9])
185                 ? mix(colors[8], colors[9], smoothstep(positions[8], positions[9], sdfValue)) : color;
186             color = (sdfValue >= positions[9] && sdfValue < positions[10])
187                 ? mix(colors[9], colors[10], smoothstep(positions[9], positions[10], sdfValue)) : color;
188             color = (sdfValue >= positions[10] && sdfValue < positions[11])
189                 ? mix(colors[10], colors[11], smoothstep(positions[10], positions[11], sdfValue)) : color;
190 
191             vec2 directionVector = vector / distance * color * 0.5 + 0.5;
192             return vec4(directionVector, 1.0, color);
193         }
194 
195         half4 main(vec2 fragCoord)
196         {
197             vec2 uv = fragCoord.xy / iResolution.xy;
198             float screenRatio = iResolution.x / iResolution.y;
199             vec2 centeredUVs = uv * 2.0 - 1.0;
200             centeredUVs.x *= screenRatio * (radiusY / radiusX);
201             vec2 centerPosition = centerPos * 2 - 1.0 ;
202             centerPosition.x *= screenRatio * (radiusY / radiusX);
203 
204             half4 finalColor = radialGradientMask(centeredUVs, centerPosition);
205             return half4(finalColor);
206         }
207     )";
208 
209     auto radialGradientShaderMaskNormalEffect = Drawing::RuntimeEffect::CreateForShader(prog);
210     if (!radialGradientShaderMaskNormalEffect) {
211         LOGE("GERadialGradientShaderMask::GetRadialGradientNormalMaskBuilder effect error");
212         return nullptr;
213     }
214 
215     radialGradientMaskNormalBuilder = std::make_shared<Drawing::RuntimeShaderBuilder>(
216         radialGradientShaderMaskNormalEffect);
217     return radialGradientMaskNormalBuilder;
218 }
219 
GenerateShaderEffect(float width,float height,std::shared_ptr<Drawing::RuntimeShaderBuilder> builder) const220 std::shared_ptr<ShaderEffect> GERadialGradientShaderMask::GenerateShaderEffect(float width, float height,
221     std::shared_ptr<Drawing::RuntimeShaderBuilder> builder) const
222 {
223     if (!builder) {
224         LOGE("GERadialGradientShaderMask::GenerateShaderEffect builder error");
225         return nullptr;
226     }
227 
228     size_t colorSize = param_.colors_.size();
229     size_t positionSize = param_.positions_.size();
230     // 0.01f is the min value
231     if (colorSize <= 0 || colorSize > SIZE_ARRAY || colorSize != positionSize || width < 0.01f || height < 0.01f) {
232         return nullptr;
233     }
234     // if radius <= 0, no need to draw. 0.001f is the min value
235     if (param_.radiusX_ < 0.001f || param_.radiusY_ < 0.001f) {
236         return nullptr;
237     }
238 
239     float color[SIZE_ARRAY] = {0.0f}; // 0.0 default
240     float position[SIZE_ARRAY] = {1.0f}; // 1.0 default
241     for (size_t i = 0; i < SIZE_ARRAY; i++) {
242         if (i < colorSize) {
243             color[i] = std::clamp(param_.colors_[i], 0.0f, 1.0f); // 0.0 1.0 min and max value
244             position[i] = std::clamp(param_.positions_[i], 0.0f, 1.0f); // 0.0 1.0 min and max value
245         }
246     }
247 
248     bool success = true;
249     for (size_t i = 1; i < colorSize; i++) {
250         success = success && (position[i] >= position[i - 1]);
251     }
252     if (!success) {
253         return nullptr;
254     }
255 
256     if (position[0] < 0.001f) { // 0.001 represents the fraction bias
257         position[0] -= 0.001f;
258     }
259 
260     builder->SetUniform("iResolution", width, height);
261     builder->SetUniform("centerPos", param_.center_.first, param_.center_.second);
262     builder->SetUniform("radiusX", param_.radiusX_ * RADIUS_SCALE);
263     builder->SetUniform("radiusY", param_.radiusY_ * RADIUS_SCALE);
264     builder->SetUniform("colors", color, SIZE_ARRAY);
265     builder->SetUniform("positions", position, SIZE_ARRAY);
266     auto radialGradientMaskEffectShader = builder->MakeShader(nullptr, false);
267     if (!radialGradientMaskEffectShader) {
268         LOGE("GERadialGradientShaderMask::GenerateDrawingShaderHas effect error");
269     }
270     return radialGradientMaskEffectShader;
271 }
272 
273 } // namespace Drawing
274 } // namespace Rosen
275 } // namespace OHOS