• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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