1 /*
2 * Copyright (c) 2021-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 "ui/rs_canvas_node.h"
17
18 #include <algorithm>
19 #include <string>
20
21 #include "common/rs_obj_abs_geometry.h"
22 #include "command/rs_canvas_node_command.h"
23 #include "command/rs_node_command.h"
24 #include "platform/common/rs_log.h"
25 #include "common/rs_obj_geometry.h"
26 #include "common/rs_optional_trace.h"
27 #include "pipeline/rs_draw_cmd_list.h"
28 #include "pipeline/rs_node_map.h"
29 #include "transaction/rs_transaction_proxy.h"
30 #include "ui/rs_ui_context.h"
31 #ifdef RS_ENABLE_VK
32 #include "modifier_render_thread/rs_modifiers_draw.h"
33 #include "modifier_render_thread/rs_modifiers_draw_thread.h"
34 #include "media_errors.h"
35 #endif
36
37 namespace OHOS {
38 namespace Rosen {
Create(bool isRenderServiceNode,bool isTextureExportNode,std::shared_ptr<RSUIContext> rsUIContext)39 RSCanvasNode::SharedPtr RSCanvasNode::Create(
40 bool isRenderServiceNode, bool isTextureExportNode, std::shared_ptr<RSUIContext> rsUIContext)
41 {
42 SharedPtr node(new RSCanvasNode(isRenderServiceNode, isTextureExportNode, rsUIContext));
43 if (rsUIContext != nullptr) {
44 rsUIContext->GetMutableNodeMap().RegisterNode(node);
45 } else {
46 RSNodeMap::MutableInstance().RegisterNode(node);
47 }
48
49 std::unique_ptr<RSCommand> command = std::make_unique<RSCanvasNodeCreate>(node->GetId(), isTextureExportNode);
50 node->AddCommand(command, node->IsRenderServiceNode());
51 node->SetUIContextToken();
52 return node;
53 }
54
RSCanvasNode(bool isRenderServiceNode,bool isTextureExportNode,std::shared_ptr<RSUIContext> rsUIContext)55 RSCanvasNode::RSCanvasNode(bool isRenderServiceNode, bool isTextureExportNode, std::shared_ptr<RSUIContext> rsUIContext)
56 : RSNode(isRenderServiceNode, isTextureExportNode, rsUIContext) {}
57
RSCanvasNode(bool isRenderServiceNode,NodeId id,bool isTextureExportNode,std::shared_ptr<RSUIContext> rsUIContext)58 RSCanvasNode::RSCanvasNode(bool isRenderServiceNode, NodeId id, bool isTextureExportNode,
59 std::shared_ptr<RSUIContext> rsUIContext)
60 : RSNode(isRenderServiceNode, id, isTextureExportNode, rsUIContext) {}
61
~RSCanvasNode()62 RSCanvasNode::~RSCanvasNode()
63 {
64 #ifdef RS_ENABLE_VK
65 if (IsHybridRenderCanvas()) {
66 RSModifiersDraw::RemoveSurfaceByNodeId(GetId(), true);
67 }
68 #endif
69 }
70
SetHDRPresent(bool hdrPresent)71 void RSCanvasNode::SetHDRPresent(bool hdrPresent)
72 {
73 std::unique_ptr<RSCommand> command = std::make_unique<RSCanvasNodeSetHDRPresent>(GetId(), hdrPresent);
74 if (AddCommand(command, true)) {
75 ROSEN_LOGD("RSCanvasNode::SetHDRPresent HDRClient set hdr true");
76 }
77 }
78
SetColorGamut(uint32_t colorGamut)79 void RSCanvasNode::SetColorGamut(uint32_t colorGamut)
80 {
81 std::unique_ptr<RSCommand> command = std::make_unique<RSCanvasNodeSetColorGamut>(GetId(), colorGamut);
82 AddCommand(command, true);
83 }
84
BeginRecording(int width,int height)85 ExtendRecordingCanvas* RSCanvasNode::BeginRecording(int width, int height)
86 {
87 if (recordingCanvas_) {
88 delete recordingCanvas_;
89 recordingCanvas_ = nullptr;
90 RS_LOGE("RSCanvasNode::BeginRecording last beginRecording without finishRecording");
91 }
92
93 recordingCanvas_ = new ExtendRecordingCanvas(width, height);
94 recordingCanvas_->SetIsCustomTextType(isCustomTextType_);
95 recordingCanvas_->SetIsCustomTypeface(isCustomTypeface_);
96 if (auto recording = recordingCanvas_->GetDrawCmdList()) {
97 recording->SetIsNeedUnmarshalOnDestruct(!IsRenderServiceNode());
98 }
99 if (!recordingUpdated_) {
100 return recordingCanvas_;
101 }
102 recordingUpdated_ = false;
103 std::unique_ptr<RSCommand> command = std::make_unique<RSCanvasNodeClearRecording>(GetId());
104 AddCommand(command, IsRenderServiceNode());
105 return recordingCanvas_;
106 }
107
IsRecording() const108 bool RSCanvasNode::IsRecording() const
109 {
110 return recordingCanvas_ != nullptr;
111 }
112
RegisterNodeMap()113 void RSCanvasNode::RegisterNodeMap()
114 {
115 auto rsContext = GetRSUIContext();
116 if (rsContext == nullptr) {
117 return;
118 }
119 auto& nodeMap = rsContext->GetMutableNodeMap();
120 nodeMap.RegisterNode(shared_from_this());
121 }
122
CreateRenderNodeForTextureExportSwitch()123 void RSCanvasNode::CreateRenderNodeForTextureExportSwitch()
124 {
125 if (IsRenderServiceNode()) {
126 hasCreateRenderNodeInRS_ = true;
127 } else {
128 hasCreateRenderNodeInRT_ = true;
129 }
130 std::unique_ptr<RSCommand> command = std::make_unique<RSCanvasNodeCreate>(GetId(), isTextureExportNode_);
131 AddCommand(command, IsRenderServiceNode());
132 }
133
FinishRecording()134 void RSCanvasNode::FinishRecording()
135 {
136 if (!IsRecording()) {
137 return;
138 }
139 auto recording = recordingCanvas_->GetDrawCmdList();
140 delete recordingCanvas_;
141 recordingCanvas_ = nullptr;
142 if (recording && recording->IsEmpty()) {
143 return;
144 }
145 if (recording != nullptr && RSSystemProperties::GetDrawTextAsBitmap()) {
146 // replace drawOpItem with cached one (generated by CPU)
147 recording->GenerateCache();
148 }
149
150 auto modifierType = static_cast<uint16_t>(
151 drawContentLast_ ? ModifierNG::RSModifierType::FOREGROUND_STYLE : ModifierNG::RSModifierType::CONTENT_STYLE);
152 std::unique_ptr<RSCommand> command =
153 std::make_unique<RSCanvasNodeUpdateRecording>(GetId(), recording, modifierType);
154 AddCommand(command, IsRenderServiceNode());
155 recordingUpdated_ = true;
156 }
157
DrawOnNode(RSModifierType type,DrawFunc func)158 void RSCanvasNode::DrawOnNode(RSModifierType type, DrawFunc func)
159 {
160 auto recordingCanvas = std::make_shared<ExtendRecordingCanvas>(GetPaintWidth(), GetPaintHeight());
161 recordingCanvas->SetIsCustomTextType(isCustomTextType_);
162 recordingCanvas->SetIsCustomTypeface(isCustomTypeface_);
163 func(recordingCanvas);
164
165 auto recording = recordingCanvas->GetDrawCmdList();
166 if (recording) {
167 recording->SetIsNeedUnmarshalOnDestruct(!IsRenderServiceNode());
168 }
169 if (recording && recording->IsEmpty()) {
170 return;
171 }
172 RSNode::SetDrawNode();
173 if (recording != nullptr && RSSystemProperties::GetDrawTextAsBitmap()) {
174 // replace drawOpItem with cached one (generated by CPU)
175 recording->GenerateCache();
176 }
177 auto modifierType = static_cast<uint16_t>(ModifierTypeConvertor::ToModifierNGType(type));
178 std::unique_ptr<RSCommand> command =
179 std::make_unique<RSCanvasNodeUpdateRecording>(GetId(), recording, modifierType);
180 if (AddCommand(command, IsRenderServiceNode())) {
181 recordingUpdated_ = true;
182 }
183 }
184
GetPaintWidth() const185 float RSCanvasNode::GetPaintWidth() const
186 {
187 auto frame = GetStagingProperties().GetFrame();
188 return frame.z_ <= 0.f ? GetStagingProperties().GetBounds().z_ : frame.z_;
189 }
190
GetPaintHeight() const191 float RSCanvasNode::GetPaintHeight() const
192 {
193 auto frame = GetStagingProperties().GetFrame();
194 return frame.w_ <= 0.f ? GetStagingProperties().GetBounds().w_ : frame.w_;
195 }
196
SetFreeze(bool isFreeze)197 void RSCanvasNode::SetFreeze(bool isFreeze)
198 {
199 if (!IsUniRenderEnabled()) {
200 ROSEN_LOGE("SetFreeze is not supported in separate render");
201 return;
202 }
203 RS_OPTIONAL_TRACE_NAME_FMT("RSCanvasNode::SetFreeze id:%llu", GetId());
204 RSNode::SetDrawNode();
205 std::unique_ptr<RSCommand> command = std::make_unique<RSSetFreeze>(GetId(), isFreeze);
206 AddCommand(command, true);
207 }
208
OnBoundsSizeChanged() const209 void RSCanvasNode::OnBoundsSizeChanged() const
210 {
211 auto bounds = GetStagingProperties().GetBounds();
212 std::lock_guard<std::mutex> lock(mutex_);
213 if (boundsChangedCallback_) {
214 boundsChangedCallback_(bounds);
215 }
216 }
217
SetBoundsChangedCallback(BoundsChangedCallback callback)218 void RSCanvasNode::SetBoundsChangedCallback(BoundsChangedCallback callback)
219 {
220 std::lock_guard<std::mutex> lock(mutex_);
221 boundsChangedCallback_ = callback;
222 }
223
GetBitmap(Drawing::Bitmap & bitmap,std::shared_ptr<Drawing::DrawCmdList> drawCmdList)224 bool RSCanvasNode::GetBitmap(Drawing::Bitmap& bitmap, std::shared_ptr<Drawing::DrawCmdList> drawCmdList)
225 {
226 if (!IsHybridRenderCanvas()) {
227 return false;
228 }
229 bool ret = false;
230 #ifdef RS_ENABLE_VK
231 RSModifiersDrawThread::Instance().PostSyncTask([this, &bitmap, &ret]() {
232 auto pixelMap = RSModifiersDraw::GetPixelMapByNodeId(GetId(), false);
233 if (pixelMap == nullptr) {
234 RS_LOGE("RSCanvasNode::GetBitmap pixelMap is nullptr");
235 return;
236 }
237 Drawing::ImageInfo info(
238 pixelMap->GetWidth(), pixelMap->GetHeight(), Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL);
239 if (!bitmap.InstallPixels(info, pixelMap->GetWritablePixels(), pixelMap->GetRowBytes())) {
240 RS_LOGE("RSCanvasNode::GetBitmap get bitmap fail");
241 return;
242 }
243 ret = true;
244 });
245 #endif
246 return ret;
247 }
248
GetPixelmap(std::shared_ptr<Media::PixelMap> pixelMap,std::shared_ptr<Drawing::DrawCmdList> drawCmdList,const Drawing::Rect * rect)249 bool RSCanvasNode::GetPixelmap(std::shared_ptr<Media::PixelMap> pixelMap,
250 std::shared_ptr<Drawing::DrawCmdList> drawCmdList, const Drawing::Rect* rect)
251 {
252 if (!IsHybridRenderCanvas()) {
253 return false;
254 }
255 if (pixelMap == nullptr || rect == nullptr) {
256 RS_LOGE("RSCanvasNode::GetPixelmap pixelMap or rect is nullptr");
257 return false;
258 }
259 bool ret = false;
260 #ifdef RS_ENABLE_VK
261 RSModifiersDrawThread::Instance().PostSyncTask([this, pixelMap, rect, &ret]() {
262 auto srcPixelMap = RSModifiersDraw::GetPixelMapByNodeId(GetId(), false);
263 if (srcPixelMap == nullptr) {
264 RS_LOGE("RSCanvasNode::GetPixelmap get source pixelMap fail");
265 return;
266 }
267 Media::Rect srcRect = { rect->GetLeft(), rect->GetTop(), rect->GetWidth(), rect->GetHeight() };
268 auto ret =
269 srcPixelMap->ReadPixels(Media::RWPixelsOptions { static_cast<uint8_t*>(pixelMap->GetWritablePixels()),
270 pixelMap->GetByteCount(), 0, pixelMap->GetRowStride(), srcRect, Media::PixelFormat::RGBA_8888 });
271 if (ret != Media::SUCCESS) {
272 RS_LOGE("RSCanvasNode::GetPixelmap get pixelMap fail");
273 return;
274 }
275 ret = true;
276 });
277 #endif
278 return ret;
279 }
280
ResetSurface(int width,int height)281 bool RSCanvasNode::ResetSurface(int width, int height)
282 {
283 if (!IsHybridRenderCanvas()) {
284 return false;
285 }
286 #ifdef RS_ENABLE_VK
287 return RSModifiersDraw::ResetSurfaceByNodeId(width, height, GetId(), true, true);
288 #endif
289 return false;
290 }
291
292 // [Attention] Only used in PC window resize scene now
SetLinkedRootNodeId(NodeId rootNodeId)293 void RSCanvasNode::SetLinkedRootNodeId(NodeId rootNodeId)
294 {
295 ROSEN_LOGI("RSCanvasNode::SetLinkedRootNodeId nodeId: %{public}" PRIu64 ", rootNode: %{public}" PRIu64 "",
296 GetId(), rootNodeId);
297 std::unique_ptr<RSCommand> command =
298 std::make_unique<RSCanvasNodeSetLinkedRootNodeId>(GetId(), rootNodeId);
299 AddCommand(command, true);
300 linkedRootNodeId_ = rootNodeId;
301 }
302
303 // [Attention] Only used in PC window resize scene now
GetLinkedRootNodeId()304 NodeId RSCanvasNode::GetLinkedRootNodeId()
305 {
306 return linkedRootNodeId_;
307 }
308
Marshalling(Parcel & parcel) const309 bool RSCanvasNode::Marshalling(Parcel& parcel) const
310 {
311 bool success =
312 parcel.WriteUint64(GetId()) && parcel.WriteBool(IsRenderServiceNode()) && parcel.WriteUint64(linkedRootNodeId_);
313 if (!success) {
314 ROSEN_LOGE("RSCanvasNode::Marshalling, read parcel failed");
315 }
316 return success;
317 }
318
Unmarshalling(Parcel & parcel)319 RSCanvasNode::SharedPtr RSCanvasNode::Unmarshalling(Parcel& parcel)
320 {
321 uint64_t id = UINT64_MAX;
322 NodeId linkedRootNodeId = INVALID_NODEID;
323 bool isRenderServiceNode = false;
324 if (!(parcel.ReadUint64(id) && parcel.ReadBool(isRenderServiceNode) && parcel.ReadUint64(linkedRootNodeId))) {
325 ROSEN_LOGE("RSCanvasNode::Unmarshalling, read param failed");
326 return nullptr;
327 }
328
329 if (auto prevNode = RSNodeMap::Instance().GetNode(id)) {
330 RS_LOGW("RSCanvasNode::Unmarshalling, the node id is already in the map");
331 // if the node id is already in the map, we should not create a new node
332 return prevNode->ReinterpretCastTo<RSCanvasNode>();
333 }
334
335 SharedPtr canvasNode(new RSCanvasNode(isRenderServiceNode, id));
336 RSNodeMap::MutableInstance().RegisterNode(canvasNode);
337
338 // for nodes constructed by unmarshalling, we should not destroy the corresponding render node on destruction
339 canvasNode->skipDestroyCommandInDestructor_ = true;
340 canvasNode->linkedRootNodeId_ = linkedRootNodeId;
341
342 return canvasNode;
343 }
344
345 } // namespace Rosen
346 } // namespace OHOS
347