• 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> RSSLRScaleFunction::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, imageColorSpace_);
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 
142     alpha_ = scaleNum_ > SLR_SCALE_THR_LOW ? SLR_ALPHA_HIGH : SLR_ALPHA_LOW;
143     float tao = 1.0f / scaleNum_;
144     kernelSize_ = std::min(std::max(SLR_TAO_MAX_SIZE, static_cast<int>(std::floor(tao))), SLR_WIN_BOUND);
145 
146     RefreshColorSpace(imageColorSpace_ ? colorGamut_ : GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB);
147     isSLRCopy_ = scaleNum_ < SLR_SCALE_THR_HIGH && widthEffect_ && heightEffect_ &&
148         MultiScreenParam::IsSlrScaleEnabled();
149 }
150 
RefreshColorSpace(GraphicColorGamut colorGamut)151 void RSSLRScaleFunction::RefreshColorSpace(GraphicColorGamut colorGamut)
152 {
153     colorGamut_ = colorGamut;
154     Drawing::CMSMatrixType colorMatrixType;
155     switch (colorGamut_) {
156         case GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB:
157             colorMatrixType = Drawing::CMSMatrixType::SRGB;
158             break;
159         case GraphicColorGamut::GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
160             colorMatrixType = Drawing::CMSMatrixType::DCIP3;
161             break;
162         default:
163             RS_LOGE("RSSLRScaleFunction::RefreshColorSpace error colorSpace is %{public}d.", colorGamut_);
164             colorMatrixType = Drawing::CMSMatrixType::SRGB;
165             break;
166     }
167     imageColorSpace_ = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB, colorMatrixType);
168     widthEffect_ = GetSLRShaderEffect(scaleNum_, dstWidth_);
169     heightEffect_ = GetSLRShaderEffect(scaleNum_, dstHeight_);
170 }
171 
CanvasScale(RSPaintFilterCanvas & canvas)172 void RSSLRScaleFunction::CanvasScale(RSPaintFilterCanvas& canvas)
173 {
174     canvas.Translate((mirrorWidth_ - dstWidth_) / 2, (mirrorHeight_ - dstHeight_) / 2);
175     canvas.Save();
176     canvas.Scale(scaleNum_, scaleNum_);
177     scaleMatrix_ = canvas.GetTotalMatrix();
178     canvas.Restore();
179 }
180 
ProcessCacheImage(RSPaintFilterCanvas & canvas,Drawing::Image & cacheImageProcessed)181 void RSSLRScaleFunction::ProcessCacheImage(RSPaintFilterCanvas& canvas, Drawing::Image& cacheImageProcessed)
182 {
183     Drawing::Brush brush;
184     brush.SetAntiAlias(true);
185     canvas.AttachBrush(brush);
186     auto image = ProcessSLRImage(canvas, cacheImageProcessed);
187     if (image == nullptr) {
188         RS_LOGE("RSSLRScaleFunction::ProcessCacheImage image is nullptr");
189         return;
190     }
191     auto sampling = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
192     canvas.DrawImage(*image, 0, 0, sampling);
193     canvas.DetachBrush();
194 }
195 
ProcessOffscreenImage(RSPaintFilterCanvas & canvas,Drawing::Image & offscreenImage)196 void RSSLRScaleFunction::ProcessOffscreenImage(RSPaintFilterCanvas& canvas, Drawing::Image& offscreenImage)
197 {
198     auto image = ProcessSLRImage(canvas, offscreenImage);
199     if (image == nullptr) {
200         RS_LOGE("RSSLRScaleFunction::ProcessOffscreenImage image is nullptr");
201         return;
202     }
203     auto sampling = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
204     canvas.DrawImage(*image, 0, 0, sampling);
205 }
206 
ProcessSLRImage(RSPaintFilterCanvas & canvas,Drawing::Image & cacheImageProcessed)207 std::shared_ptr<Rosen::Drawing::Image> RSSLRScaleFunction::ProcessSLRImage(RSPaintFilterCanvas& canvas,
208     Drawing::Image& cacheImageProcessed)
209 {
210     auto builder = SLRImageShaderBuilder(cacheImageProcessed);
211     if (builder == nullptr) {
212         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage SLRImageShaderBuilder is nullptr");
213         return nullptr;
214     }
215     auto originImageInfo = cacheImageProcessed.GetImageInfo();
216     auto ScreenInfo = Drawing::ImageInfo(std::ceil(dstWidth_),
217         std::ceil(dstHeight_), originImageInfo.GetColorType(),
218         originImageInfo.GetAlphaType(), imageColorSpace_);
219     std::shared_ptr<Drawing::Image> tmpImage(builder->MakeImage(
220         canvas.GetGPUContext().get(), nullptr, ScreenInfo, false));
221     if (tmpImage == nullptr) {
222         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage tmpImage is nullptr");
223         return nullptr;
224     }
225     auto tempImageInfo = tmpImage->GetImageInfo();
226     auto slrImageInfo = Drawing::ImageInfo(std::ceil(dstWidth_),
227         std::ceil(dstHeight_), tempImageInfo.GetColorType(),
228         tempImageInfo.GetAlphaType(), tempImageInfo.GetColorSpace());
229     auto lapLaceBuilder = LaplaceShaderBuilder(*tmpImage);
230     if (lapLaceBuilder == nullptr) {
231         RS_LOGE("RSSLRScaleFunction::ProcessSLRImage lapLaceBuilder is nullptr");
232         return nullptr;
233     }
234     return lapLaceBuilder->MakeImage(
235         canvas.GetGPUContext().get(), nullptr, slrImageInfo, false);
236 }
237 
SLRImageShaderBuilder(const Drawing::Image & image)238 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::SLRImageShaderBuilder(
239     const Drawing::Image& image)
240 {
241     if (!slrShaderBuilder_) {
242         if (!slrFilterShader_) {
243             slrFilterShader_ = RSSLRScaleFunction::MakeSLRShaderEffect();
244         }
245         if (!slrFilterShader_) {
246             RS_LOGE("RSSLRScaleFunction::SLRImageShader slrFilterShader_ is null");
247             return nullptr;
248         }
249         slrShaderBuilder_ = std::make_shared<Drawing::RuntimeShaderBuilder>(slrFilterShader_);
250     }
251     if (!slrShaderBuilder_) {
252         RS_LOGE("RSSLRScaleFunction::SLRImageShader slrShaderBuilder_ is null");
253         return nullptr;
254     }
255     Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
256     auto imageShader = Drawing::ShaderEffect::CreateImageShader(image, Drawing::TileMode::CLAMP,
257         Drawing::TileMode::CLAMP, sampling, Drawing::Matrix());
258     if (!imageShader) {
259         RS_LOGE("RSSLRScaleFunction::SLRImageShader imageShader is null");
260         return nullptr;
261     }
262     slrShaderBuilder_->SetChild("imageShader", imageShader);
263     slrShaderBuilder_->SetChild("widthShader", widthEffect_);
264     slrShaderBuilder_->SetChild("heightShader", heightEffect_);
265 
266     float tao = 1.0f / scaleNum_;
267     int a = std::min(std::max(SLR_TAO_MAX_SIZE, static_cast<int>(std::floor(tao))), SLR_WIN_BOUND);
268 
269     slrShaderBuilder_->SetUniform("slr_a", a, a);
270     slrShaderBuilder_->SetUniform("slr_coeff", scaleNum_, scaleNum_);
271     slrShaderBuilder_->SetUniform("slr_coeff_tao", tao, tao);
272     return slrShaderBuilder_;
273 }
274 
MakeSLRShaderEffect()275 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::MakeSLRShaderEffect()
276 {
277     static const std::string SLRFilterString(R"(
278         uniform shader imageShader;
279         uniform shader widthShader;
280         uniform shader heightShader;
281         uniform vec2 slr_a;
282         uniform vec2 slr_coeff;
283         uniform vec2 slr_coeff_tao;
284         const int MAX_SIZE = 4;
285         const float factor = 0.000030518509476;
286         const float bit_bound = 32767.0;
287 
288         half4 main(float2 fcoord) {
289             float2 eta = fcoord * slr_coeff_tao - vec2(0.5);
290             half2 coord_s = floor(eta) - slr_a + half2(1.5, 1.5);
291             half4 c = vec4(0, 0, 0, 0);
292             for (int i = 0; i < MAX_SIZE; ++i) {
293                 half4 ws = widthShader.eval(half2(half(i) + 0.5, fcoord.x)) * 255;
294                 float w_i = ws.x + ws.y * 256.0 - bit_bound;
295                 w_i *= factor;
296 
297                 half4 t = vec4(0, 0, 0, 0);
298                 for (int j = 0; j < MAX_SIZE; ++j) {
299                     half4 hs = heightShader.eval(half2(half(j) + 0.5, fcoord.y)) * 255;
300                     float w_j = hs.x + hs.y * 256.0 - bit_bound;
301                     w_j *= factor;
302                     half2 coord = coord_s + half2(half(i), half(j));
303                     half4 tc = imageShader.eval(coord);
304                     t += w_j * tc;
305                 }
306                 c += t * w_i;
307             }
308             return c;
309         }
310     )");
311 
312     std::shared_ptr<Drawing::RuntimeEffect> SLRFilterShader =
313         Drawing::RuntimeEffect::CreateForShader(SLRFilterString);
314     if (!SLRFilterShader) {
315         return nullptr;
316     }
317     slrFilterShader_ = std::move(SLRFilterShader);
318     return slrFilterShader_;
319 }
320 
LaplaceShaderBuilder(const Drawing::Image & image)321 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSSLRScaleFunction::LaplaceShaderBuilder(const Drawing::Image& image)
322 {
323     if (!laplaceShaderBuilder_) {
324         if (!laplaceFilterShader_) {
325             laplaceFilterShader_ = RSSLRScaleFunction::MakeLaplaceShaderEffect();
326         }
327         laplaceShaderBuilder_ = std::make_shared<Drawing::RuntimeShaderBuilder>(laplaceFilterShader_);
328     }
329     Drawing::SamplingOptions sampling(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
330     auto imageShader = Drawing::ShaderEffect::CreateImageShader(image, Drawing::TileMode::CLAMP,
331         Drawing::TileMode::CLAMP, sampling, Drawing::Matrix());
332     if (!imageShader) {
333         RS_LOGE("RSSLRScaleFunction::SLRImageShader imageShader is null");
334         return nullptr;
335     }
336     laplaceShaderBuilder_->SetChild("imageShader", imageShader);
337     laplaceShaderBuilder_->SetUniform("alpha", alpha_);
338     return laplaceShaderBuilder_;
339 }
340 
MakeLaplaceShaderEffect()341 std::shared_ptr<Drawing::RuntimeEffect> RSSLRScaleFunction::MakeLaplaceShaderEffect()
342 {
343     static const std::string lapFilterString(R"(
344         uniform shader imageShader;
345         uniform float alpha;
346         vec4 main(vec2 coord) {
347             vec4 c = imageShader.eval(coord);
348             vec4 top = imageShader.eval(coord + half2(0.0, 1.0));
349             vec4 bottom = imageShader.eval(coord - half2(0.0, 1.0));
350             vec4 left = imageShader.eval(coord - half2(1.0, 0.0));
351             vec4 right = imageShader.eval(coord + half2(1.0, 0.0));
352             return clamp(c + alpha * (4.0 * c - top - bottom - left - right), 0.0, 1.0);
353         }
354     )");
355 
356     std::shared_ptr<Drawing::RuntimeEffect> lapFilterShader =
357         Drawing::RuntimeEffect::CreateForShader(lapFilterString);
358     if (!lapFilterShader) {
359         return nullptr;
360     }
361     laplaceFilterShader_ = std::move(lapFilterShader);
362     return laplaceFilterShader_;
363 }
364 
365 } // namespace Rosen
366 } // namespace OHOS