• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "render/rs_hps_blur.h"
17 
18 #include <mutex>
19 
20 #include "common/rs_common_def.h"
21 #include "common/rs_optional_trace.h"
22 #include "draw/surface.h"
23 #include "effect/runtime_shader_builder.h"
24 #include "platform/common/rs_log.h"
25 #include "platform/common/rs_system_properties.h"
26 #include "rs_profiler.h"
27 
28 namespace OHOS {
29 namespace Rosen {
30 
31 static constexpr uint32_t MAX_SURFACE_SIZE = 10000;
32 constexpr float MAX_ALPHA = 255.0f;
33 static std::shared_ptr<Drawing::RuntimeEffect> g_mixEffect;
34 std::mutex g_mixEffectMutex;
35 
GetShaderTransform(const Drawing::Rect & blurRect,float scaleW,float scaleH)36 Drawing::Matrix HpsBlurFilter::GetShaderTransform(const Drawing::Rect& blurRect, float scaleW, float scaleH)
37 {
38     Drawing::Matrix matrix;
39     matrix.SetScale(scaleW, scaleH);
40     Drawing::Matrix translateMatrix;
41     translateMatrix.Translate(blurRect.GetLeft(), blurRect.GetTop());
42     matrix.PostConcat(translateMatrix);
43     return matrix;
44 }
45 
GetMixEffect() const46 std::shared_ptr<Drawing::RuntimeEffect> HpsBlurFilter::GetMixEffect() const
47 {
48     static const std::string mixString(R"(
49         uniform shader blurredInput;
50         uniform float inColorFactor;
51 
52         highp float random(float2 xy) {
53             float t = dot(xy, float2(78.233, 12.9898));
54             return fract(sin(t) * 43758.5453);
55         }
56         half4 main(float2 xy) {
57             highp float noiseGranularity = inColorFactor / 255.0;
58             half4 finalColor = blurredInput.eval(xy);
59             float noise  = mix(-noiseGranularity, noiseGranularity, random(xy));
60             finalColor.rgb += noise;
61             return finalColor;
62         }
63     )");
64 
65     if (g_mixEffect == nullptr) {
66         std::unique_lock<std::mutex> lock(g_mixEffectMutex);
67         if (g_mixEffect == nullptr) {
68             g_mixEffect = Drawing::RuntimeEffect::CreateForShader(mixString);
69             if (g_mixEffect == nullptr) {
70                 return nullptr;
71             }
72         }
73     }
74     return g_mixEffect;
75 }
76 
ApplyMaskColorFilter(Drawing::Canvas & offscreenCanvas,float alpha,const RSColor & maskColor) const77 float HpsBlurFilter::ApplyMaskColorFilter(Drawing::Canvas& offscreenCanvas, float alpha,
78     const RSColor& maskColor) const
79 {
80     float newAlpha = alpha;
81     if (maskColor != RgbPalette::Transparent()) {
82         float maskColorAlpha = static_cast<float>(maskColor.GetAlpha()) / MAX_ALPHA;
83         newAlpha += maskColorAlpha - alpha * maskColorAlpha;
84         Drawing::Brush maskBrush;
85         maskBrush.SetColor(maskColor.AsArgbInt());
86         if (ROSEN_EQ(newAlpha, 0.f)) {
87             maskBrush.SetAlphaF(0.f);
88         } else {
89             maskBrush.SetAlphaF(maskColorAlpha / newAlpha);
90         }
91         ROSEN_LOGD("HpsBlurFilter::ApplyHpsBlur newMaskColor %{public}#x, alpha = %{public}f",
92             maskColor.AsArgbInt(), alpha);
93         offscreenCanvas.DrawBackground(maskBrush);
94     }
95     return newAlpha;
96 }
97 
ApplyHpsBlur(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::HpsBlurParameter & param,float alpha,std::shared_ptr<Drawing::ColorFilter> colorFilter,const RSColor & maskColor) const98 bool HpsBlurFilter::ApplyHpsBlur(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
99     const Drawing::HpsBlurParameter& param, float alpha, std::shared_ptr<Drawing::ColorFilter> colorFilter,
100     const RSColor& maskColor) const
101 {
102     auto surface = canvas.GetSurface();
103     if (surface == nullptr || image == nullptr) {
104         return false;
105     }
106     std::array<int, 2> dimension = canvas.CalcHpsBluredImageDimension(param); // There are 2 variables
107     if (dimension[0] <= 0 || dimension[1] <= 0 || dimension[0] >= static_cast<int>(MAX_SURFACE_SIZE)
108         || dimension[1] >= static_cast<int>(MAX_SURFACE_SIZE)) {
109         ROSEN_LOGD("HpsBlurFilter::ApplyHpsBlur CalcHpsBluredImageDimension error");
110         return false;
111     }
112     std::shared_ptr<Drawing::Surface> offscreenSurface = surface->MakeSurface(dimension[0], dimension[1]);
113     if (offscreenSurface == nullptr) {
114         return false;
115     }
116 
117     std::shared_ptr<Drawing::Canvas> offscreenCanvas = offscreenSurface->GetCanvas();
118     if (offscreenCanvas == nullptr) {
119         return false;
120     }
121     Drawing::Rect dimensionRect = {0, 0, dimension[0], dimension[1]};
122     auto offscreenHpsParam = Drawing::HpsBlurParameter(param.src, dimensionRect, param.sigma,
123         param.saturation, param.brightness);
124     if (!offscreenCanvas->DrawBlurImage(*image, offscreenHpsParam)) {
125         return false;
126     }
127     RS_PROFILER_ADD_HPS_BLUR_METRICS(static_cast<uint32_t>(image->GetWidth() * image->GetHeight()));
128 
129     alpha = ApplyMaskColorFilter(*offscreenCanvas, alpha, maskColor);
130 
131     auto imageCache = offscreenSurface->GetImageSnapshot();
132     if (imageCache == nullptr) {
133         return false;
134     }
135     auto dst = param.dst;
136     Drawing::Brush brush;
137     Drawing::SamplingOptions linear(Drawing::FilterMode::LINEAR, Drawing::MipmapMode::NONE);
138     const auto blurMatrix = GetShaderTransform(dst, dst.GetWidth() / imageCache->GetWidth(),
139         dst.GetHeight() / imageCache->GetHeight());
140     const auto blurShader = Drawing::ShaderEffect::CreateImageShader(*imageCache, Drawing::TileMode::CLAMP,
141         Drawing::TileMode::CLAMP, linear, blurMatrix);
142     if (!SetShaderEffect(brush, blurShader, imageCache)) { return false; }
143     if (colorFilter != nullptr) {
144         Drawing::Filter filter;
145         filter.SetColorFilter(colorFilter);
146         brush.SetFilter(filter);
147     }
148     brush.SetAlphaF(alpha);
149     canvas.AttachBrush(brush);
150     canvas.DrawRect(dst);
151     canvas.DetachBrush();
152     return true;
153 }
154 
SetShaderEffect(Drawing::Brush & brush,std::shared_ptr<Drawing::ShaderEffect> blurShader,std::shared_ptr<Drawing::Image> imageCache) const155 bool HpsBlurFilter::SetShaderEffect(Drawing::Brush& brush, std::shared_ptr<Drawing::ShaderEffect> blurShader,
156     std::shared_ptr<Drawing::Image> imageCache) const
157 {
158     if (blurShader == nullptr || imageCache == nullptr) {
159         return false;
160     }
161     static auto factor = RSSystemProperties::GetHpsBlurNoiseFactor();
162     ROSEN_LOGD("HpsBlurFilter::ApplyHpsBlur HpsBlurNoise %{public}f", factor);
163     static constexpr float epsilon = 0.1f;
164     if (!ROSEN_LE(factor, epsilon)) {
165         auto mixEffect = GetMixEffect();
166         if (mixEffect == nullptr) {
167             return false;
168         }
169         Drawing::RuntimeShaderBuilder mixBuilder(mixEffect);
170         mixBuilder.SetChild("blurredInput", blurShader);
171         ROSEN_LOGD("HpsBlurFilter::HpsBlurNoise factor : %{public}f", factor);
172         mixBuilder.SetUniform("inColorFactor", factor);
173         brush.SetShaderEffect(mixBuilder.MakeShader(nullptr, imageCache->IsOpaque()));
174     } else {
175         brush.SetShaderEffect(blurShader);
176     }
177     return true;
178 }
179 
180 } // namespace Rosen
181 } // namespace OHOS