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