• 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 "rs_slr_scale.h"
17 
18 #include <cfloat>
19 #include "graphic_feature_param_manager.h"
20 #include "rs_trace.h"
21 #include "pipeline/main_thread/rs_main_thread.h"
22 
23 namespace OHOS {
24 namespace Rosen {
25 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::slrFilterShader_ = nullptr;
26 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::laplaceFilterShader_ = nullptr;
27 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::slrShaderBuilder_ = nullptr;
28 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::laplaceShaderBuilder_ = nullptr;
RSSLRScaleFunction(float dstWidth,float dstHeight,float srcWidth,float srcHeight)29 RSSLRScaleFunction::RSSLRScaleFunction(
30     float dstWidth, float dstHeight, float srcWidth, float srcHeight)
31     : mirrorWidth_(dstWidth), mirrorHeight_(dstHeight), srcWidth_(srcWidth), srcHeight_(srcHeight)
32 {
33     RefreshScreenData();
34 }
35 
CheckOrRefreshScreen(float dstWidth,float dstHeight,float srcWidth,float srcHeight)36 void RSSLRScaleFunction::CheckOrRefreshScreen(
37     float dstWidth, float dstHeight, float srcWidth, float srcHeight)
38 {
39     if (std::fabs(mirrorWidth_ - dstWidth) <= FLT_EPSILON && std::fabs(mirrorHeight_ - dstHeight) <= FLT_EPSILON &&
40         std::fabs(srcWidth_ - srcWidth) <= FLT_EPSILON && std::fabs(srcHeight_ - srcHeight) <= FLT_EPSILON) {
41         return;
42     }
43     mirrorWidth_ = dstWidth;
44     mirrorHeight_ = dstHeight;
45     srcWidth_ = srcWidth;
46     srcHeight_ = srcHeight;
47     RefreshScreenData();
48 }
49 
50 #define PI 3.14159265358979323846
51 #define SLR_WIN_BOUND 2
52 
GetSLRFactor(float x,int a)53 float GetSLRFactor(float x, int a)
54 {
55     if (x - static_cast<float>(a) >= FLT_EPSILON ||
56         x + static_cast<float>(a) < FLT_EPSILON || a == 0) {
57         return 0.0f;
58     }
59     if (std::abs(x) < 1e-16) {
60         return 1.0f;
61     }
62     x *= PI;
63     return a * std::sin(x) * std::sin(x / a) / (x * x);
64 }
65 
66 // BIT_BOUND is Weight resolution
67 const float BIT_BOUND = 32767.0f;
68 const int SLR_MAX_WIN_SIZE = 4;
69 const int SLR_TAO_MAX_SIZE = 2;
70 const float SLR_SCALE_THR_LOW = 0.65f;
71 const float SLR_ALPHA_LOW = 0.2f;
72 const float SLR_ALPHA_HIGH = 0.05f;
73 
GetSLRWeights(float coeff,int width,int dstWidth,int minBound)74 static std::shared_ptr<uint32_t[]> GetSLRWeights(float coeff, int width, int dstWidth, int minBound)
75 {
76     std::shared_ptr<uint32_t[]> result(new uint32_t[dstWidth * SLR_MAX_WIN_SIZE]);
77     float weights[SLR_MAX_WIN_SIZE];
78     for (auto i = 0; i < dstWidth; i++) {
79         float eta_i = (i + 0.5f) / coeff - 0.5f;
80         int k = std::floor(eta_i) - minBound + 1;
81         float sum = 0.f;
82         for (auto j = 0; j < width; ++j) {
83             float f = GetSLRFactor(coeff * (eta_i - (k + j)), minBound);
84             weights[j] = f;
85             sum += f;
86         }
87         if (ROSEN_LE(sum, 0.f)) {
88             return nullptr;
89         }
90         for (auto j = 0; j < width; ++j) {
91             auto f = weights[j];
92             f /= sum;
93             f *= BIT_BOUND;
94             result[i * SLR_MAX_WIN_SIZE + j] = f + BIT_BOUND;
95         }
96         for (auto k = width; k < SLR_MAX_WIN_SIZE; k++) {
97             result[i * SLR_MAX_WIN_SIZE + k] = BIT_BOUND;
98         }
99     }
100     return result;
101 }
102 
GetSLRShaderEffect(float coeff,int dstWidth)103 std::shared_ptr<Drawing::ShaderEffect> GetSLRShaderEffect(float coeff, int dstWidth)
104 {
105     float tao = 1.0f / coeff;
106     int minBound = std::min(std::max(SLR_TAO_MAX_SIZE, static_cast<int>(std::floor(tao))), SLR_WIN_BOUND);
107 
108     int width = SLR_MAX_WIN_SIZE;
109     Drawing::BitmapFormat format = { Drawing::ColorType::COLORTYPE_N32, Drawing::AlphaType::ALPHATYPE_OPAQUE };
110 
111     Drawing::Bitmap bitmap;
112     bitmap.Build(width, dstWidth, format, width * sizeof(uint32_t));
113 
114     auto weightW = GetSLRWeights(coeff, 2 * minBound, dstWidth, minBound);
115     if (weightW == nullptr) {
116         return nullptr;
117     }
118     Drawing::ImageInfo imageInfo(width, dstWidth,
119         Drawing::ColorType::COLORTYPE_N32, Drawing::AlphaType::ALPHATYPE_OPAQUE);
120     bitmap.InstallPixels(imageInfo, weightW.get(), width * sizeof(uint32_t));
121 
122     Drawing::Image imagew;
123     imagew.BuildFromBitmap(bitmap);
124 
125     Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
126     auto shader = Drawing::ShaderEffect::CreateImageShader(imagew, Drawing::TileMode::CLAMP,
127         Drawing::TileMode::CLAMP, sampling, Drawing::Matrix());
128     return shader;
129 }
130 
RefreshScreenData()131 void RSSLRScaleFunction::RefreshScreenData()
132 {
133     if (ROSEN_LE(mirrorWidth_, 0.f) || ROSEN_LE(srcWidth_, 0.f) ||
134         ROSEN_LE(mirrorHeight_, 0.f) || ROSEN_LE(srcHeight_, 0.f)) {
135         isSLRCopy_ = false;
136         return;
137     }
138     scaleNum_ = std::min(mirrorWidth_ / srcWidth_, mirrorHeight_ / srcHeight_);
139     dstWidth_ = scaleNum_ * srcWidth_;
140     dstHeight_ = scaleNum_ * srcHeight_;
141     alpha_ = scaleNum_ > SLR_SCALE_THR_LOW ? SLR_ALPHA_HIGH : SLR_ALPHA_LOW;
142     float tao = 1.0f / scaleNum_;
143     kernelSize_ = std::min(std::max(SLR_TAO_MAX_SIZE, static_cast<int>(std::floor(tao))), SLR_WIN_BOUND);
144 
145     widthEffect_ = GetSLRShaderEffect(scaleNum_, dstWidth_);
146     heightEffect_ = GetSLRShaderEffect(scaleNum_, dstHeight_);
147     auto multiScreenFeatureParam = std::static_pointer_cast<MultiScreenParam>(
148         GraphicFeatureParamManager::GetInstance().GetFeatureParam(FEATURE_CONFIGS[MULTISCREEN]));
149     if (!multiScreenFeatureParam) {
150         RS_LOGE("RSSLRScaleFunction::RefreshScreenData multiScreenFeatureParam is null");
151         return;
152     }
153     isSLRCopy_ = scaleNum_ < SLR_SCALE_THR_HIGH && widthEffect_ && heightEffect_ &&
154         multiScreenFeatureParam->IsSlrScaleEnabled();
155 }
156 
CanvasScale(RSPaintFilterCanvas & canvas)157 void RSSLRScaleFunction::CanvasScale(RSPaintFilterCanvas& canvas)
158 {
159     canvas.Translate((mirrorWidth_ - dstWidth_) / 2, (mirrorHeight_ - dstHeight_) / 2);
160     canvas.Save();
161     canvas.Scale(scaleNum_, scaleNum_);
162     scaleMatrix_ = canvas.GetTotalMatrix();
163     canvas.Restore();
164 }
165 
ProcessCacheImage(RSPaintFilterCanvas & canvas,Drawing::Image & cacheImageProcessed)166 void RSSLRScaleFunction::ProcessCacheImage(RSPaintFilterCanvas& canvas, Drawing::Image& cacheImageProcessed)
167 {
168     Drawing::Brush brush;
169     brush.SetAntiAlias(true);
170     canvas.AttachBrush(brush);
171     auto image = ProcessSLRImage(canvas, cacheImageProcessed);
172     if (image == nullptr) {
173         RS_LOGE("RSSLRScaleFunction::ProcessCacheImage image is nullptr");
174         return;
175     }
176     auto sampling = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
177     canvas.DrawImage(*image, 0, 0, sampling);
178     canvas.DetachBrush();
179 }
180 
ProcessOffscreenImage(RSPaintFilterCanvas & canvas,Drawing::Image & offscreenImage)181 void RSSLRScaleFunction::ProcessOffscreenImage(RSPaintFilterCanvas& canvas, Drawing::Image& offscreenImage)
182 {
183     auto image = ProcessSLRImage(canvas, offscreenImage);
184     if (image == nullptr) {
185         RS_LOGE("RSSLRScaleFunction::ProcessOffscreenImage image is nullptr");
186         return;
187     }
188     auto sampling = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
189     canvas.DrawImage(*image, 0, 0, sampling);
190 }
191 
ProcessSLRImage(RSPaintFilterCanvas & canvas,Drawing::Image & cacheImageProcessed)192 std::shared_ptr<Rosen::Drawing::Image> RSSLRScaleFunction::ProcessSLRImage(RSPaintFilterCanvas& canvas,
193     Drawing::Image& cacheImageProcessed)
194 {
195     auto builder = SLRImageShaderBuilder(cacheImageProcessed);
196     if (builder == nullptr) {
197         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage SLRImageShaderBuilder is nullptr");
198         return nullptr;
199     }
200     auto originImageInfo = cacheImageProcessed.GetImageInfo();
201     auto ScreenInfo = Drawing::ImageInfo(std::ceil(dstWidth_),
202         std::ceil(dstHeight_), originImageInfo.GetColorType(),
203         originImageInfo.GetAlphaType(), originImageInfo.GetColorSpace());
204     std::shared_ptr<Drawing::Image> tmpImage(builder->MakeImage(
205         canvas.GetGPUContext().get(), nullptr, ScreenInfo, false));
206     if (tmpImage == nullptr) {
207         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage tmpImage is nullptr");
208         return nullptr;
209     }
210     auto tempImageInfo = tmpImage->GetImageInfo();
211     auto slrImageInfo = Drawing::ImageInfo(std::ceil(dstWidth_),
212         std::ceil(dstHeight_), tempImageInfo.GetColorType(),
213         tempImageInfo.GetAlphaType(), tempImageInfo.GetColorSpace());
214     auto lapLaceBuilder = LaplaceShaderBuilder(*tmpImage);
215     if (lapLaceBuilder == nullptr) {
216         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage lapLaceBuilder is nullptr");
217         return nullptr;
218     }
219     return lapLaceBuilder->MakeImage(
220         canvas.GetGPUContext().get(), nullptr, slrImageInfo, false);
221 }
222 
SLRImageShaderBuilder(const Drawing::Image & image)223 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::SLRImageShaderBuilder(
224     const Drawing::Image& image)
225 {
226     if (!slrShaderBuilder_) {
227         if (!slrFilterShader_) {
228             slrFilterShader_ = RSSLRScaleFunction::MakeSLRShaderEffect();
229         }
230         if (!slrFilterShader_) {
231             RS_LOGE("RSSLRScaleFunction::SLRImageShader slrFilterShader_ is null");
232             return nullptr;
233         }
234         slrShaderBuilder_ = std::make_shared<Drawing::RuntimeShaderBuilder>(slrFilterShader_);
235     }
236     if (!slrShaderBuilder_) {
237         RS_LOGE("RSSLRScaleFunction::SLRImageShader slrShaderBuilder_ is null");
238         return nullptr;
239     }
240     Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
241     auto imageShader = Drawing::ShaderEffect::CreateImageShader(image, Drawing::TileMode::CLAMP,
242         Drawing::TileMode::CLAMP, sampling, Drawing::Matrix());
243     if (!imageShader) {
244         RS_LOGE("RSSLRScaleFunction::SLRImageShader imageShader is null");
245         return nullptr;
246     }
247     slrShaderBuilder_->SetChild("imageShader", imageShader);
248     slrShaderBuilder_->SetChild("widthShader", widthEffect_);
249     slrShaderBuilder_->SetChild("heightShader", heightEffect_);
250 
251     float tao = 1.0f / scaleNum_;
252     int a = std::min(std::max(SLR_TAO_MAX_SIZE, static_cast<int>(std::floor(tao))), SLR_WIN_BOUND);
253 
254     slrShaderBuilder_->SetUniform("slr_a", a, a);
255     slrShaderBuilder_->SetUniform("slr_coeff", scaleNum_, scaleNum_);
256     slrShaderBuilder_->SetUniform("slr_coeff_tao", tao, tao);
257     return slrShaderBuilder_;
258 }
259 
MakeSLRShaderEffect()260 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::MakeSLRShaderEffect()
261 {
262     static const std::string SLRFilterString(R"(
263         uniform shader imageShader;
264         uniform shader widthShader;
265         uniform shader heightShader;
266         uniform vec2 slr_a;
267         uniform vec2 slr_coeff;
268         uniform vec2 slr_coeff_tao;
269         const int MAX_SIZE = 4;
270         const float factor = 0.000030518509476;
271         const float bit_bound = 32767.0;
272 
273         half4 main(float2 fcoord) {
274             float2 eta = fcoord * slr_coeff_tao - vec2(0.5);
275             half2 coord_s = floor(eta) - slr_a + half2(1.5, 1.5);
276             half4 c = vec4(0, 0, 0, 0);
277             for (int i = 0; i < MAX_SIZE; ++i) {
278                 half4 ws = widthShader.eval(half2(half(i) + 0.5, fcoord.x)) * 255;
279                 float w_i = ws.x + ws.y * 256.0 - bit_bound;
280                 w_i *= factor;
281 
282                 half4 t = vec4(0, 0, 0, 0);
283                 for (int j = 0; j < MAX_SIZE; ++j) {
284                     half4 hs = heightShader.eval(half2(half(j) + 0.5, fcoord.y)) * 255;
285                     float w_j = hs.x + hs.y * 256.0 - bit_bound;
286                     w_j *= factor;
287                     half2 coord = coord_s + half2(half(i), half(j));
288                     half4 tc = imageShader.eval(coord);
289                     t += w_j * tc;
290                 }
291                 c += t * w_i;
292             }
293             return c;
294         }
295     )");
296 
297     std::shared_ptr<Drawing::RuntimeEffect> SLRFilterShader =
298         Drawing::RuntimeEffect::CreateForShader(SLRFilterString);
299     if (!SLRFilterShader) {
300         return nullptr;
301     }
302     slrFilterShader_ = std::move(SLRFilterShader);
303     return slrFilterShader_;
304 }
305 
LaplaceShaderBuilder(const Drawing::Image & image)306 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::LaplaceShaderBuilder(const Drawing::Image& image)
307 {
308     if (!laplaceShaderBuilder_) {
309         if (!laplaceFilterShader_) {
310             laplaceFilterShader_ = RSSLRScaleFunction::MakeLaplaceShaderEffect();
311         }
312         laplaceShaderBuilder_ = std::make_shared<Drawing::RuntimeShaderBuilder>(laplaceFilterShader_);
313     }
314     Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
315     auto imageShader = Drawing::ShaderEffect::CreateImageShader(image, Drawing::TileMode::CLAMP,
316         Drawing::TileMode::CLAMP, sampling, Drawing::Matrix());
317     if (!imageShader) {
318         RS_LOGE("RSSLRScaleFunction::SLRImageShader imageShader is null");
319         return nullptr;
320     }
321     laplaceShaderBuilder_->SetChild("imageShader", imageShader);
322     laplaceShaderBuilder_->SetUniform("alpha", alpha_);
323     return laplaceShaderBuilder_;
324 }
325 
MakeLaplaceShaderEffect()326 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::MakeLaplaceShaderEffect()
327 {
328     static const std::string lapFilterString(R"(
329         uniform shader imageShader;
330         uniform float alpha;
331         vec4 main(vec2 coord) {
332             vec4 c = imageShader.eval(coord);
333             vec4 top = imageShader.eval(coord + half2(0.0, 1.0));
334             vec4 bottom = imageShader.eval(coord - half2(0.0, 1.0));
335             vec4 left = imageShader.eval(coord - half2(1.0, 0.0));
336             vec4 right = imageShader.eval(coord + half2(1.0, 0.0));
337             return c + alpha* (4.0 * c - top - bottom - left - right);
338         }
339     )");
340 
341     std::shared_ptr<Drawing::RuntimeEffect> lapFilterShader =
342         Drawing::RuntimeEffect::CreateForShader(lapFilterString);
343     if (!lapFilterShader) {
344         return nullptr;
345     }
346     laplaceFilterShader_ = std::move(lapFilterShader);
347     return laplaceFilterShader_;
348 }
349 
350 } // namespace Rosen
351 } // namespace OHOS