1 /*
2 * Copyright (c) 2023 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 "pipeline/rs_canvas_drawing_render_node.h"
17
18 #include "include/core/SkCanvas.h"
19 #include "src/image/SkImage_Base.h"
20 #ifdef NEW_SKIA
21 #include "include/gpu/GrBackendSurface.h"
22 #endif
23
24 #include "common/rs_common_def.h"
25 #include "common/rs_obj_abs_geometry.h"
26 #include "pipeline/rs_paint_filter_canvas.h"
27 #include "platform/common/rs_log.h"
28 #include "property/rs_properties_painter.h"
29 #include "visitor/rs_node_visitor.h"
30
31 namespace OHOS {
32 namespace Rosen {
RSCanvasDrawingRenderNode(NodeId id,std::weak_ptr<RSContext> context)33 RSCanvasDrawingRenderNode::RSCanvasDrawingRenderNode(NodeId id, std::weak_ptr<RSContext> context)
34 : RSCanvasRenderNode(id, context)
35 {}
36
~RSCanvasDrawingRenderNode()37 RSCanvasDrawingRenderNode::~RSCanvasDrawingRenderNode()
38 {
39 #ifndef USE_ROSEN_DRAWING
40 if (preThreadInfo_.second && skSurface_) {
41 preThreadInfo_.second(std::move(skSurface_));
42 }
43 #else
44 if (preThreadInfo_.second && surface_) {
45 preThreadInfo_.second(std::move(surface_));
46 }
47 #endif
48 }
49
ProcessRenderContents(RSPaintFilterCanvas & canvas)50 void RSCanvasDrawingRenderNode::ProcessRenderContents(RSPaintFilterCanvas& canvas)
51 {
52 #ifndef USE_ROSEN_DRAWING
53 int width = 0;
54 int height = 0;
55 if (!GetSizeFromDrawCmdModifiers(width, height)) {
56 return;
57 }
58
59 if (IsNeedResetSurface(width, height)) {
60 if (preThreadInfo_.second && skSurface_) {
61 preThreadInfo_.second(std::move(skSurface_));
62 }
63 if (!ResetSurface(width, height, canvas)) {
64 return;
65 }
66 preThreadInfo_ = curThreadInfo_;
67 } else if (preThreadInfo_.first != curThreadInfo_.first) {
68 auto preMatrix = canvas_->getTotalMatrix();
69 auto preSurface = skSurface_;
70 if (!ResetSurface(width, height, canvas)) {
71 return;
72 }
73 #if (defined NEW_SKIA) && (defined RS_ENABLE_GL)
74 auto image = preSurface->makeImageSnapshot();
75 if (!image) {
76 return;
77 }
78 GrSurfaceOrigin origin = kBottomLeft_GrSurfaceOrigin;
79 auto sharedBackendTexture = image->getBackendTexture(false, &origin);
80 if (!sharedBackendTexture.isValid()) {
81 RS_LOGE("RSCanvasDrawingRenderNode::ProcessRenderContents sharedBackendTexture is nullptr");
82 return;
83 }
84 auto sharedTexture = SkImage::MakeFromTexture(
85 canvas.recordingContext(), sharedBackendTexture, origin, image->colorType(), image->alphaType(), nullptr);
86 if (sharedTexture == nullptr) {
87 RS_LOGE("RSCanvasDrawingRenderNode::ProcessRenderContents sharedTexture is nullptr");
88 return;
89 }
90 canvas_->drawImage(sharedTexture, 0.f, 0.f);
91 #else
92 if (auto image = preSurface->makeImageSnapshot()) {
93 canvas_->drawImage(image, 0.f, 0.f);
94 }
95 #endif
96 if (preThreadInfo_.second && preSurface) {
97 preThreadInfo_.second(std::move(preSurface));
98 }
99 preThreadInfo_ = curThreadInfo_;
100 canvas_->setMatrix(preMatrix);
101 }
102
103 RSModifierContext context = { GetMutableRenderProperties(), canvas_.get() };
104 ApplyDrawCmdModifier(context, RSModifierType::CONTENT_STYLE);
105 ApplyDrawCmdModifier(context, RSModifierType::OVERLAY_STYLE);
106
107 SkMatrix mat;
108 if (RSPropertiesPainter::GetGravityMatrix(
109 GetRenderProperties().GetFrameGravity(), GetRenderProperties().GetFrameRect(), width, height, mat)) {
110 canvas.concat(mat);
111 }
112 auto image = skSurface_->makeImageSnapshot();
113 {
114 std::lock_guard<std::mutex> lock(mutex_);
115 skSurface_->readPixels(skBitmap_, 0, 0);
116 }
117 #ifdef NEW_SKIA
118 auto samplingOptions = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
119 canvas.drawImage(image, 0.f, 0.f, samplingOptions, nullptr);
120 #else
121 canvas.drawImage(image, 0.f, 0.f, nullptr);
122 #endif
123 #endif
124 }
125
126 #ifndef USE_ROSEN_DRAWING
ResetSurface(int width,int height,RSPaintFilterCanvas & canvas)127 bool RSCanvasDrawingRenderNode::ResetSurface(int width, int height, RSPaintFilterCanvas& canvas)
128 {
129 SkImageInfo info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
130
131 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
132 #ifdef NEW_SKIA
133 auto grContext = canvas.recordingContext();
134 #else
135 auto grContext = canvas.getGrContext();
136 #endif
137 if (grContext == nullptr) {
138 RS_LOGE("RSCanvasDrawingRenderNode::ProcessRenderContents: GrContext is nullptr");
139 return false;
140 }
141 skSurface_ = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info);
142 if (!skSurface_ && width > 0 && height > 0) {
143 skSurface_ = SkSurface::MakeRaster(info);
144 }
145 #else
146 skSurface_ = SkSurface::MakeRaster(info);
147 #endif
148 if (!skSurface_) {
149 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface SkSurface is nullptr");
150 return false;
151 }
152 canvas_ = std::make_unique<RSPaintFilterCanvas>(skSurface_.get());
153 return skSurface_ != nullptr;
154 }
155 #else
ResetSurface(int width,int height,RSPaintFilterCanvas & canvas)156 bool RSCanvasDrawingRenderNode::ResetSurface(int width, int height, RSPaintFilterCanvas& canvas)
157 {
158 Drawing::BitmapFormat info = Drawing::BitmapFormat{ Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
159 auto bitmap = std::make_shared<Drawing::Bitmap>();
160 bitmap->Build(width, height, info);
161
162 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
163 auto gpuContext = canvas.GetGPUContext();
164 if (gpuContext == nullptr) {
165 RS_LOGE("RSCanvasDrawingRenderNode::ProcessRenderContents: GpuContext is nullptr");
166 return false;
167 }
168 auto image = std::make_shared<Drawing::Image>();
169 if (!image->BuildFromBitmap(*gpuContext, *bitmap)) {
170 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface Drawing::Image is nullptr");
171 return false;
172 }
173 auto surface = std::make_shared<Drawing::Surface>();
174 if (!surface->Bind(*image)) {
175 if (!surface->Bind(*bitmap)) {
176 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface Drawing::Surface is nullptr");
177 return false;
178 }
179 bitmap_ = bitmap;
180 }
181 #else
182 auto surface = std::make_shared<Drawing::Surface>();
183 if (!surface->Bind(*bitmap)) {
184 RS_LOGE("RSCanvasDrawingRenderNode::ResetSurface Drawing::Surface is nullptr");
185 return false;
186 }
187 bitmap_ = bitmap;
188 #endif
189 surface_ = surface;
190 canvas_ = std::make_unique<RSPaintFilterCanvas>(surface_.get());
191 return true;
192 }
193 #endif
194
ApplyDrawCmdModifier(RSModifierContext & context,RSModifierType type) const195 void RSCanvasDrawingRenderNode::ApplyDrawCmdModifier(RSModifierContext& context, RSModifierType type) const
196 {
197 auto it = drawCmdModifiers_.find(type);
198 if (it == drawCmdModifiers_.end() || it->second.empty()) {
199 return;
200 }
201 for (const auto& modifier : it->second) {
202 auto prop = modifier->GetProperty();
203 #ifndef USE_ROSEN_DRAWING
204 auto cmd = std::static_pointer_cast<RSRenderProperty<DrawCmdListPtr>>(prop)->Get();
205 cmd->Playback(*context.canvas_);
206 cmd->ClearOp();
207 #else
208 auto cmd = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(prop)->Get();
209 cmd->Playback(*context.canvas_);
210 #endif
211 }
212 }
213
214 #ifndef USE_ROSEN_DRAWING
GetBitmap()215 SkBitmap RSCanvasDrawingRenderNode::GetBitmap()
216 {
217 SkBitmap bitmap;
218 if (skSurface_ == nullptr) {
219 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: SkSurface is nullptr");
220 return bitmap;
221 }
222 sk_sp<SkImage> image = skSurface_->makeImageSnapshot();
223 if (image == nullptr) {
224 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: SkImage is nullptr");
225 return bitmap;
226 }
227 if (!image->asLegacyBitmap(&bitmap)) {
228 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: asLegacyBitmap failed");
229 }
230 return bitmap;
231 }
232
GetPixelmap(const std::shared_ptr<Media::PixelMap> pixelmap,const SkRect * rect)233 bool RSCanvasDrawingRenderNode::GetPixelmap(const std::shared_ptr<Media::PixelMap> pixelmap, const SkRect* rect)
234 {
235 if (!pixelmap) {
236 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: pixelmap is nullptr");
237 return false;
238 }
239
240 if (skBitmap_.empty()) {
241 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: skBitmap_ is empty");
242 return false;
243 }
244
245 SkImageInfo info =
246 SkImageInfo::Make(pixelmap->GetWidth(), pixelmap->GetHeight(), kRGBA_8888_SkColorType, kPremul_SkAlphaType);
247 std::lock_guard<std::mutex> lock(mutex_);
248 if (!skBitmap_.readPixels(info, pixelmap->GetWritablePixels(), pixelmap->GetRowBytes(), rect->x(), rect->y())) {
249 RS_LOGE("RSCanvasDrawingRenderNode::GetPixelmap: readPixels failed");
250 return false;
251 }
252 return true;
253 }
254
255 #else
GetBitmap(Drawing::Bitmap & bitmap)256 bool RSCanvasDrawingRenderNode::GetBitmap(Drawing::Bitmap& bitmap)
257 {
258 if (surface_ == nullptr) {
259 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: Drawing::Surface is nullptr");
260 return false;
261 }
262 std::shared_ptr<Drawing::Image> image = surface_->GetImageSnapshot();
263 if (image == nullptr) {
264 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: Drawing::Image is nullptr");
265 return false;
266 }
267 RS_LOGE("RSCanvasDrawingRenderNode::GetBitmap: Drawing asLegacyBitmap failed");
268 return false;
269 }
270 #endif
271
GetSizeFromDrawCmdModifiers(int & width,int & height)272 bool RSCanvasDrawingRenderNode::GetSizeFromDrawCmdModifiers(int& width, int& height)
273 {
274 auto it = drawCmdModifiers_.find(RSModifierType::CONTENT_STYLE);
275 if (it == drawCmdModifiers_.end() || it->second.empty()) {
276 return false;
277 }
278 for (const auto& modifier : it->second) {
279 auto prop = modifier->GetProperty();
280 #ifndef USE_ROSEN_DRAWING
281 if (auto cmd = std::static_pointer_cast<RSRenderProperty<DrawCmdListPtr>>(prop)->Get()) {
282 #else
283 if (auto cmd = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(prop)->Get()) {
284 #endif
285 width = std::max(width, cmd->GetWidth());
286 height = std::max(height, cmd->GetHeight());
287 }
288 }
289 if (width <= 0 || height <= 0) {
290 RS_LOGE("RSCanvasDrawingRenderNode::GetSizeFromDrawCmdModifiers: The width or height of the canvas is less "
291 "than or equal to 0");
292 return false;
293 }
294 return true;
295 }
296
297 bool RSCanvasDrawingRenderNode::IsNeedResetSurface(const int& width, const int& height) const
298 {
299 #ifndef USE_ROSEN_DRAWING
300 if (!skSurface_) {
301 #else
302 if (!surface_ || !surface_->GetCanvas()) {
303 #endif
304 return true;
305 } else {
306 // There is no need to reapply the buffer during the animation, only if the size of the DrawCmdList set by ArkUI
307 // changes. When the component sets the margin and padding properties, ArkUI does not set the DrawCmdList size,
308 // in which case the size of the SkSurface should be the same as the size of Render Properties Bounds. In other
309 // cases, ArkUI sets the DrawCmdList to the same size as the Render Properties Bounds.
310 #ifndef USE_ROSEN_DRAWING
311 return (skSurface_->width() != width || skSurface_->height() != height) &&
312 (static_cast<int>(GetRenderProperties().GetBoundsWidth()) != skSurface_->width() ||
313 static_cast<int>(GetRenderProperties().GetBoundsHeight()) != skSurface_->height());
314 #else
315 auto canvas = surface_->GetCanvas();
316 return (canvas->GetWidth() != width || canvas->GetHeight() != height) &&
317 (static_cast<int>(GetRenderProperties().GetBoundsWidth()) != canvas->GetWidth() ||
318 static_cast<int>(GetRenderProperties().GetBoundsHeight()) != canvas->GetHeight());
319 #endif
320 }
321 }
322 } // namespace Rosen
323 } // namespace OHOS