• 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 "effect_image_chain.h"
17 
18 #include "effect_utils.h"
19 #include "ge_mesa_blur_shader_filter.h"
20 #include "rs_trace.h"
21 
22 #include "pipeline/rs_paint_filter_canvas.h"
23 #include "platform/common/rs_system_properties.h"
24 #include "render/rs_hps_blur.h"
25 #include "render/rs_pixel_map_util.h"
26 
27 #ifdef RS_ENABLE_VK
28 #include "effect_vulkan_context.h"
29 #endif
30 
31 namespace OHOS::Rosen {
PixelFormatToDrawingColorType(const Media::PixelFormat & pixelFormat)32 Drawing::ColorType ImageUtil::PixelFormatToDrawingColorType(const Media::PixelFormat& pixelFormat)
33 {
34     switch (pixelFormat) {
35         case Media::PixelFormat::RGB_565: {
36             return Drawing::ColorType::COLORTYPE_RGB_565;
37         }
38         case Media::PixelFormat::RGBA_8888: {
39             return Drawing::ColorType::COLORTYPE_RGBA_8888;
40         }
41         case Media::PixelFormat::BGRA_8888: {
42             return Drawing::ColorType::COLORTYPE_BGRA_8888;
43         }
44         case Media::PixelFormat::ALPHA_8: {
45             return Drawing::ColorType::COLORTYPE_ALPHA_8;
46         }
47         case Media::PixelFormat::RGBA_F16: {
48             return Drawing::ColorType::COLORTYPE_RGBA_F16;
49         }
50         case Media::PixelFormat::RGBA_1010102: {
51             return Drawing::ColorType::COLORTYPE_RGBA_1010102;
52         }
53         default: {
54             return Drawing::ColorType::COLORTYPE_UNKNOWN;
55         }
56     }
57 }
58 
AlphaTypeToDrawingAlphaType(const Media::AlphaType & alphaType)59 Drawing::AlphaType ImageUtil::AlphaTypeToDrawingAlphaType(const Media::AlphaType& alphaType)
60 {
61     switch (alphaType) {
62         case Media::AlphaType::IMAGE_ALPHA_TYPE_OPAQUE: {
63             return Drawing::AlphaType::ALPHATYPE_OPAQUE;
64         }
65         case Media::AlphaType::IMAGE_ALPHA_TYPE_PREMUL: {
66             return Drawing::AlphaType::ALPHATYPE_PREMUL;
67         }
68         case Media::AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL: {
69             return Drawing::AlphaType::ALPHATYPE_UNPREMUL;
70         }
71         default: {
72             return Drawing::AlphaType::ALPHATYPE_UNKNOWN;
73         }
74     }
75 }
76 
Prepare(const std::shared_ptr<Media::PixelMap> & srcPixelMap,bool forceCPU)77 DrawingError EffectImageChain::Prepare(const std::shared_ptr<Media::PixelMap>& srcPixelMap, bool forceCPU)
78 {
79     std::lock_guard<std::mutex> lock(apiMutex_);
80     if (!CheckPixelMap(srcPixelMap)) {
81         return DrawingError::ERR_ILLEGAL_INPUT;
82     }
83     srcPixelMap_ = srcPixelMap;
84 
85     if (InitWithoutCanvas(srcPixelMap_) != DrawingError::ERR_OK) {
86         EFFECT_LOG_E("EffectImageChain::Prepare: Failed to init.");
87         return DrawingError::ERR_IMAGE_NULL;
88     }
89 
90     forceCPU_ = forceCPU;
91     surface_ = CreateSurface(forceCPU_);
92     if (surface_ == nullptr) {
93         EFFECT_LOG_E("EffectImageChain::Prepare: Failed to create surface %{public}d.", forceCPU_);
94         return DrawingError::ERR_SURFACE;
95     }
96     canvas_ = surface_->GetCanvas();
97 
98     prepared_ = true;
99     return DrawingError::ERR_OK;
100 }
101 
ApplyDrawingFilter(const std::shared_ptr<Drawing::ImageFilter> & filter)102 DrawingError EffectImageChain::ApplyDrawingFilter(const std::shared_ptr<Drawing::ImageFilter>& filter)
103 {
104     if (filter == nullptr) {
105         EFFECT_LOG_E("EffectImageChain::ApplyDrawingFilter: The filter is null.");
106         return DrawingError::ERR_ILLEGAL_INPUT;
107     }
108 
109     std::lock_guard<std::mutex> lock(apiMutex_);
110     filters_ = (filters_ == nullptr) ? filter : Drawing::ImageFilter::CreateComposeImageFilter(filter, filters_);
111     return DrawingError::ERR_OK;
112 }
113 
ApplyBlur(float radius,const Drawing::TileMode & tileMode)114 DrawingError EffectImageChain::ApplyBlur(float radius, const Drawing::TileMode& tileMode)
115 {
116     if (radius < 0.0f) { // invalid radius
117         return DrawingError::ERR_ILLEGAL_INPUT;
118     }
119 
120     std::lock_guard<std::mutex> lock(apiMutex_);
121     if (!prepared_) { // blur need prepare first
122         EFFECT_LOG_E("EffectImageChain::ApplyBlur: Not ready, need prepare first.");
123         return DrawingError::ERR_NOT_PREPARED;
124     }
125 
126     if (forceCPU_) {
127         auto filter = Drawing::ImageFilter::CreateBlurImageFilter(radius, radius, tileMode, nullptr);
128         filters_ = (filters_ == nullptr) ? filter : Drawing::ImageFilter::CreateComposeImageFilter(filter, filters_);
129         return DrawingError::ERR_OK;
130     }
131 
132     if (filters_ != nullptr) {
133         DrawOnFilter(); // need draw first to ensure cascading
134         image_ = surface_->GetImageSnapshot();
135         filters_ = nullptr; // clear filters_ to avoid apply again
136     }
137 
138     auto isHpsApplied = (RSSystemProperties::GetHpsBlurEnabled() && tileMode == Drawing::TileMode::CLAMP &&
139         (ApplyHpsBlur(radius) == DrawingError::ERR_OK));
140     if (isHpsApplied) { // apply hps blur success
141         return DrawingError::ERR_OK;
142     }
143 
144     return ApplyMesaBlur(radius, tileMode);
145 }
146 
ApplyMesaBlur(float radius,const Drawing::TileMode & tileMode)147 DrawingError EffectImageChain::ApplyMesaBlur(float radius, const Drawing::TileMode& tileMode)
148 {
149     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "EffectImageChain::ApplyMesaBlur");
150     Drawing::GEMESABlurShaderFilterParams params { radius, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, static_cast<int>(tileMode),
151         0.f, 0.f };
152     auto mesaBlurFilter = std::make_shared<GEMESABlurShaderFilter>(params);
153     image_ = mesaBlurFilter->ProcessImage(*canvas_, image_,
154         Drawing::Rect(0, 0, srcPixelMap_->GetWidth(), srcPixelMap_->GetHeight()),
155         Drawing::Rect(0, 0, srcPixelMap_->GetWidth(), srcPixelMap_->GetHeight()));
156     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
157     return DrawingError::ERR_OK;
158 }
159 
ApplyHpsBlur(float radius)160 DrawingError EffectImageChain::ApplyHpsBlur(float radius)
161 {
162     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "EffectImageChain::ApplyHpsBlur");
163     auto ret = DrawingError::ERR_OK;
164     do {
165         if (std::ceil(radius) == 0) { // exception when applying hps blur on 0, need handle separately
166             break;
167         }
168 
169         RSPaintFilterCanvas canvas(surface_.get());
170         Drawing::AutoCanvasRestore autoRestore(canvas, true);
171         auto hpsParam = Drawing::HpsBlurParameter(Drawing::Rect(0, 0, image_->GetWidth(), image_->GetHeight()),
172             Drawing::Rect(0, 0, image_->GetWidth(), image_->GetHeight()), radius, 1.f, 1.f);
173         if (!HpsBlurFilter::GetHpsBlurFilter().ApplyHpsBlur(canvas, image_, hpsParam, 1.f)) {
174             EFFECT_LOG_E("EffectImageChain::ApplyHpsBlur: Failed to apply hps blur");
175             ret = DrawingError::ERR_FAST_BLUR;
176             break;
177         }
178         image_ = surface_->GetImageSnapshot();
179     } while (false);
180 
181     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
182     return ret;
183 }
184 
DrawOnFilter()185 void EffectImageChain::DrawOnFilter()
186 {
187     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "EffectImageChain::DrawOnFilter");
188     // Step1: Setup Paint
189     Drawing::Paint paint;
190     paint.SetStyle(Drawing::Paint::PaintStyle::PAINT_FILL);
191     paint.SetAntiAlias(true);
192     paint.SetBlendMode(Drawing::BlendMode::SRC);
193     if (filters_ != nullptr) {
194         Drawing::Filter filter;
195         filter.SetImageFilter(filters_);
196         paint.SetFilter(filter);
197     }
198 
199     // Step2: Draw image
200     canvas_->Save();
201     canvas_->ResetMatrix();
202     canvas_->AttachPaint(paint);
203     canvas_->DrawImage(*image_, 0, 0, Drawing::SamplingOptions());
204     canvas_->DetachPaint();
205     canvas_->Restore();
206     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
207 }
208 
Draw()209 DrawingError EffectImageChain::Draw()
210 {
211     std::lock_guard<std::mutex> lock(apiMutex_);
212     ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "EffectImageChain::Draw");
213     auto ret = DrawingError::ERR_OK;
214     do {
215         if (!prepared_) {
216             EFFECT_LOG_E("EffectImageChain::Draw: Not ready, need prepare first.");
217             ret = DrawingError::ERR_NOT_PREPARED;
218             break;
219         }
220 
221         DrawOnFilter();
222 
223         bool needRead = (!forceCPU_ && dstPixelMap_);
224         if (needRead && !canvas_->ReadPixels(imageInfo_, reinterpret_cast<void*>(dstPixelMap_->GetWritablePixels()),
225             static_cast<uint32_t>(dstPixelMap_->GetRowStride()), 0, 0)) {
226             EFFECT_LOG_E("EffectImageChain::Draw: Failed to readPixels to target Pixmap.");
227             ret = DrawingError::ERR_PIXEL_READ;
228             break;
229         }
230     } while (false);
231 
232     ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
233     return ret;
234 }
235 
CheckPixelMap(const std::shared_ptr<Media::PixelMap> & pixelMap)236 bool EffectImageChain::CheckPixelMap(const std::shared_ptr<Media::PixelMap>& pixelMap)
237 {
238     if (pixelMap == nullptr) {
239         EFFECT_LOG_E("EffectImageChain::CheckPixelMap: The srcPixelMap is nullptr.");
240         return false;
241     }
242 
243     if (pixelMap->GetWidth() <= 0 || pixelMap->GetHeight() <= 0) {
244         EFFECT_LOG_E("EffectImageChain::CheckPixelMap: The width or height is invalid.");
245         return false;
246     }
247 
248     if (pixelMap->GetPixelFormat() == Media::PixelFormat::UNKNOWN) {
249         EFFECT_LOG_E("EffectImageChain::CheckPixelMap: The pixel format is invalid.");
250         return false;
251     }
252 
253     if (pixelMap->GetAlphaType() == Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN) {
254         EFFECT_LOG_E("EffectImageChain::CheckPixelMap: The alpha type is invalid.");
255         return false;
256     }
257 
258     return true;
259 }
260 
InitWithoutCanvas(const std::shared_ptr<Media::PixelMap> & srcPixelMap)261 DrawingError EffectImageChain::InitWithoutCanvas(const std::shared_ptr<Media::PixelMap>& srcPixelMap)
262 {
263     imageInfo_ = Drawing::ImageInfo { srcPixelMap_->GetWidth(), srcPixelMap_->GetHeight(),
264         ImageUtil::PixelFormatToDrawingColorType(srcPixelMap_->GetPixelFormat()),
265         ImageUtil::AlphaTypeToDrawingAlphaType(srcPixelMap_->GetAlphaType()),
266         RSPixelMapUtil::GetPixelmapColorSpace(srcPixelMap_) };
267 
268     Drawing::Bitmap bitmap;
269     bitmap.InstallPixels(imageInfo_, reinterpret_cast<void*>(srcPixelMap_->GetWritablePixels()),
270         static_cast<uint32_t>(srcPixelMap_->GetRowStride()));
271     image_ = std::make_shared<Drawing::Image>();
272     image_->BuildFromBitmap(bitmap);
273 
274     Media::InitializationOptions opts;
275     opts.size = { srcPixelMap_->GetWidth(), srcPixelMap_->GetHeight() };
276     opts.pixelFormat = srcPixelMap_->GetPixelFormat();
277     opts.alphaType = srcPixelMap_->GetAlphaType();
278     opts.editable = true;
279     opts.useDMA = true;
280     auto dstPixelMap = Media::PixelMap::Create(opts);
281     if (dstPixelMap == nullptr) {
282         image_ = nullptr;
283         EFFECT_LOG_E("EffectImageChain::InitWithoutCanvas: Failed to create the dstPixelMap.");
284         return DrawingError::ERR_IMAGE_NULL;
285     }
286     dstPixelMap_ = std::shared_ptr<Media::PixelMap>(dstPixelMap.release());
287 
288     EFFECT_LOG_I("Init w %{public}d, h %{public}d, f %{public}d, alpha %{public}d, useDMA 1",
289         opts.size.width, opts.size.height, srcPixelMap_->GetPixelFormat(), srcPixelMap_->GetAlphaType());
290     return DrawingError::ERR_OK;
291 }
292 
GetPixelMap()293 std::shared_ptr<Media::PixelMap> EffectImageChain::GetPixelMap()
294 {
295     std::lock_guard<std::mutex> lock(apiMutex_);
296     return dstPixelMap_;
297 }
298 
CreateSurface(bool forceCPU)299 std::shared_ptr<Drawing::Surface> EffectImageChain::CreateSurface(bool forceCPU)
300 {
301     if (forceCPU) { // dstPixelMap_ must not null by called
302         auto address = const_cast<uint32_t*>(dstPixelMap_->GetPixel32(0, 0));
303         return Drawing::Surface::MakeRasterDirect(imageInfo_, address, dstPixelMap_->GetRowStride());
304     }
305 
306 #ifdef RS_ENABLE_GPU
307     std::shared_ptr<Drawing::GPUContext> context = nullptr;
308     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
309         renderContext_ = std::make_shared<RenderContext>();
310         renderContext_->InitializeEglContext();
311         renderContext_->SetUpGpuContext();
312         context = renderContext_->GetSharedDrGPUContext();
313     }
314 
315 #ifdef RS_ENABLE_VK
316     if (RSSystemProperties::IsUseVulkan()) {
317         context = EffectVulkanContext::GetSingleton().CreateDrawingContext();
318     }
319 #endif
320 
321     if (context == nullptr) {
322         EFFECT_LOG_E("EffectImageChain::CreateGPUSurface: create gpuContext failed.");
323         return nullptr;
324     }
325     return Drawing::Surface::MakeRenderTarget(context.get(), false, imageInfo_);
326 #else
327     EFFECT_LOG_W("EffectImageChain::CreateGPUSurface: GPU rendering is not supported.");
328     return nullptr;
329 #endif
330 }
331 } // namespace OHOS::Rosen