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