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