1 /*
2 * Copyright (c) 2024 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 #include "render/rs_distortion_shader_filter.h"
16
17 #include "common/rs_optional_trace.h"
18 #include "common/rs_common_def.h"
19 #include "platform/common/rs_log.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 // 0.24 means a mapping between the external input and the actual calculated value.
24 static const float DISTORTION_SCALE = 0.24f;
25
RSDistortionFilter(float distortionK)26 RSDistortionFilter::RSDistortionFilter(float distortionK)
27 : RSDrawingFilterOriginal(nullptr), distortionK_(distortionK)
28 {
29 type_ = FilterType::DISTORT;
30
31 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
32 hash_ = SkOpts::hash(&distortionK_, sizeof(distortionK_), hash_);
33 hash_ = SkOpts::hash(&scaleCoord_, sizeof(scaleCoord_), hash_);
34 hash_ = SkOpts::hash(&offsetX_, sizeof(offsetX_), hash_);
35 hash_ = SkOpts::hash(&offsetY_, sizeof(offsetY_), hash_);
36 }
37
38 RSDistortionFilter::~RSDistortionFilter() = default;
39
GetDescription()40 std::string RSDistortionFilter::GetDescription()
41 {
42 return "DistortionEffect k: " + std::to_string(distortionK_) +
43 ", scaleCoord: " + std::to_string(scaleCoord_) + ", offsetX: " + std::to_string(offsetX_) +
44 ", offsetY: " + std::to_string(offsetY_);
45 }
46
IsValid() const47 bool RSDistortionFilter::IsValid() const
48 {
49 if (distortionK_ < -1 || distortionK_ > 1) {
50 return false;
51 }
52 if (ROSEN_EQ(scaleCoord_, 0.0f)) {
53 return false;
54 }
55 // -0.5f means the calculation coefficient of scale
56 if (ROSEN_LNE(distortionK_ * DISTORTION_SCALE, -0.5f / (scaleCoord_ * scaleCoord_))) {
57 return false;
58 }
59 return true;
60 }
61
MakeDistortionShader()62 std::shared_ptr<Drawing::RuntimeShaderBuilder> RSDistortionFilter::MakeDistortionShader()
63 {
64 static std::shared_ptr<Drawing::RuntimeEffect> distortEffect = nullptr;
65 std::string distortString(
66 R"(
67 uniform shader imageInput;
68 uniform float2 iResolution;
69 uniform float distortionK;
70 uniform float scale; // coord: 0_1 -> -scale_scale
71 uniform float2 offset;
72
73 half4 main(float2 xy) {
74 float2 uv = xy / iResolution.xy;
75 uv = 2.0 * scale * uv - float2(scale, scale) - offset;
76 float rr = uv.x * uv.x + uv.y * uv.y;
77 float2 finalUV = uv / (1.0 + distortionK * rr);
78 finalUV = finalUV + float2(scale, scale) + offset;
79 finalUV = finalUV / (2 * scale);
80 half4 c = imageInput.eval(finalUV * iResolution.xy);
81 return half4(c.rgba);
82 }
83 )");
84
85 if (distortEffect == nullptr) {
86 distortEffect = Drawing::RuntimeEffect::CreateForShader(distortString);
87 if (distortEffect == nullptr) {
88 ROSEN_LOGE("RSDistortionFilter::RuntimeShader distortEffect create failed");
89 return nullptr;
90 }
91 }
92 std::shared_ptr<Drawing::RuntimeShaderBuilder> distortBuilder =
93 std::make_shared<Drawing::RuntimeShaderBuilder>(distortEffect);
94 return distortBuilder;
95 }
96
DrawDistortion(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const97 void RSDistortionFilter::DrawDistortion(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
98 const Drawing::Rect& src, const Drawing::Rect& dst) const
99 {
100 auto distortBuilder = MakeDistortionShader();
101 if (!distortBuilder || !IsValid()) {
102 ROSEN_LOGE("RSDistortionFilter::shader error");
103 return;
104 }
105 RS_OPTIONAL_TRACE_NAME("DrawDistortion");
106
107 Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
108 distortBuilder->SetChild("imageInput", Drawing::ShaderEffect::CreateImageShader(*image, Drawing::TileMode::DECAL,
109 Drawing::TileMode::DECAL, linear, Drawing::Matrix()));
110 distortBuilder->SetUniform("iResolution", image->GetWidth(), image->GetHeight());
111 distortBuilder->SetUniform("distortionK", distortionK_ * DISTORTION_SCALE);
112 distortBuilder->SetUniform("scale", scaleCoord_);
113 distortBuilder->SetUniform("offset", offsetX_, offsetY_);
114
115 std::shared_ptr<Drawing::ShaderEffect> distortShader = distortBuilder->MakeShader(nullptr, false);
116 Drawing::Brush brush;
117 brush.SetShaderEffect(distortShader);
118 if (distortionK_ < 0) {
119 canvas.AttachBrush(brush);
120 canvas.DrawRect(dst);
121 canvas.DetachBrush();
122 return;
123 }
124 canvas.DrawBackground(brush);
125 }
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const126 void RSDistortionFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
127 const Drawing::Rect& src, const Drawing::Rect& dst) const
128 {
129 if (!image || image->GetWidth() <= 0 || image->GetHeight() <= 0) {
130 ROSEN_LOGE("RSDistortionFilter::image error");
131 return;
132 }
133 DrawDistortion(canvas, image, src, dst);
134 }
135 } // namespace Rosen
136 } // namespace OHOS