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 "recording/draw_cmd_list.h"
17
18 #include <cstddef>
19 #include <memory>
20 #include <unordered_set>
21
22 #include "recording/draw_cmd.h"
23 #include "recording/recording_canvas.h"
24 #include "utils/log.h"
25 #include "utils/performanceCaculate.h"
26
27 namespace OHOS {
28 namespace Rosen {
29 namespace Drawing {
30 namespace {
31 constexpr uint32_t DRAWCMDLIST_OPSIZE_COUNT_LIMIT = 50000;
32 }
33
CreateFromData(const CmdListData & data,bool isCopy)34 std::shared_ptr<DrawCmdList> DrawCmdList::CreateFromData(const CmdListData& data, bool isCopy)
35 {
36 auto cmdList = std::make_shared<DrawCmdList>(DrawCmdList::UnmarshalMode::DEFERRED);
37 if (isCopy) {
38 cmdList->opAllocator_.BuildFromDataWithCopy(data.first, data.second);
39 } else {
40 cmdList->opAllocator_.BuildFromData(data.first, data.second);
41 }
42
43 int32_t* width = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(0, sizeof(int32_t)));
44 int32_t* height = static_cast<int32_t*>(cmdList->opAllocator_.OffsetToAddr(sizeof(int32_t), sizeof(int32_t)));
45 if (width && height) {
46 cmdList->width_ = *width;
47 cmdList->height_ = *height;
48 } else {
49 cmdList->width_ = 0;
50 cmdList->height_ = 0;
51 }
52 return cmdList;
53 }
54
DrawCmdList(DrawCmdList::UnmarshalMode mode)55 DrawCmdList::DrawCmdList(DrawCmdList::UnmarshalMode mode) : width_(0), height_(0), mode_(mode) {}
56
DrawCmdList(int32_t width,int32_t height,DrawCmdList::UnmarshalMode mode)57 DrawCmdList::DrawCmdList(int32_t width, int32_t height, DrawCmdList::UnmarshalMode mode)
58 : width_(width), height_(height), mode_(mode)
59 {
60 opAllocator_.Add(&width_, sizeof(int32_t));
61 opAllocator_.Add(&height_, sizeof(int32_t));
62 }
63
~DrawCmdList()64 DrawCmdList::~DrawCmdList()
65 {
66 if (drawOpItems_.size() == 0 && isNeedUnmarshalOnDestruct_) {
67 UnmarshallingDrawOps();
68 }
69 ClearOp();
70 }
71
AddDrawOp(std::shared_ptr<DrawOpItem> && drawOpItem)72 bool DrawCmdList::AddDrawOp(std::shared_ptr<DrawOpItem>&& drawOpItem)
73 {
74 if (mode_ != DrawCmdList::UnmarshalMode::DEFERRED) {
75 return false;
76 }
77 std::lock_guard<std::recursive_mutex> lock(mutex_);
78 drawOpItems_.emplace_back(drawOpItem);
79 return true;
80 }
81
ClearOp()82 void DrawCmdList::ClearOp()
83 {
84 {
85 std::lock_guard<std::recursive_mutex> lock(mutex_);
86 opAllocator_.ClearData();
87 opAllocator_.Add(&width_, sizeof(int32_t));
88 opAllocator_.Add(&height_, sizeof(int32_t));
89 imageAllocator_.ClearData();
90 bitmapAllocator_.ClearData();
91 imageMap_.clear();
92 imageHandleVec_.clear();
93 drawOpItems_.clear();
94 lastOpGenSize_ = 0;
95 lastOpItemOffset_ = std::nullopt;
96 opCnt_ = 0;
97 }
98 {
99 std::lock_guard<std::mutex> lock(recordCmdMutex_);
100 recordCmdVec_.clear();
101 }
102 {
103 std::lock_guard<std::mutex> lock(imageObjectMutex_);
104 imageObjectVec_.clear();
105 }
106 {
107 std::lock_guard<std::mutex> lock(imageBaseObjMutex_);
108 imageBaseObjVec_.clear();
109 }
110 }
111
GetWidth() const112 int32_t DrawCmdList::GetWidth() const
113 {
114 return width_;
115 }
116
GetHeight() const117 int32_t DrawCmdList::GetHeight() const
118 {
119 return height_;
120 }
121
SetWidth(int32_t width)122 void DrawCmdList::SetWidth(int32_t width)
123 {
124 width_ = width;
125 }
126
SetHeight(int32_t height)127 void DrawCmdList::SetHeight(int32_t height)
128 {
129 height_ = height;
130 }
131
GetNoNeedUICaptured() const132 bool DrawCmdList::GetNoNeedUICaptured() const
133 {
134 return noNeedUICaptured_;
135 }
136
SetNoNeedUICaptured(bool noNeedUICaptured)137 void DrawCmdList::SetNoNeedUICaptured(bool noNeedUICaptured)
138 {
139 noNeedUICaptured_ = noNeedUICaptured;
140 }
141
IsEmpty() const142 bool DrawCmdList::IsEmpty() const
143 {
144 if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
145 return drawOpItems_.empty();
146 }
147 size_t offset = 2 * sizeof(int32_t); // 2 is width and height.Offset of first OpItem is behind the w and h
148 if (opAllocator_.GetSize() <= offset && drawOpItems_.size() == 0) {
149 return true;
150 }
151 return false;
152 }
153
GetOpItemSize() const154 size_t DrawCmdList::GetOpItemSize() const
155 {
156 return mode_ == DrawCmdList::UnmarshalMode::DEFERRED ? drawOpItems_.size() : opCnt_;
157 }
158
GetOpsWithDesc() const159 std::string DrawCmdList::GetOpsWithDesc() const
160 {
161 std::string desc;
162 for (auto& item : drawOpItems_) {
163 if (item == nullptr) {
164 continue;
165 }
166 desc += item->GetOpDesc();
167 desc += "\n";
168 }
169 LOGD("DrawCmdList::GetOpsWithDesc %{public}s, opitem sz: %{public}zu", desc.c_str(), drawOpItems_.size());
170 return desc;
171 }
172
Dump(std::string & out)173 void DrawCmdList::Dump(std::string& out)
174 {
175 bool found = false;
176 std::lock_guard<std::recursive_mutex> lock(mutex_);
177 std::vector<std::shared_ptr<DrawOpItem>> dumpDrawOpItems;
178 size_t lastOpGenSize = lastOpGenSize_;
179 if (drawOpItems_.empty() && !IsEmpty()) {
180 UnmarshallingDrawOpsSimple(dumpDrawOpItems, lastOpGenSize);
181 } else {
182 dumpDrawOpItems = drawOpItems_;
183 }
184
185 for (auto& item : dumpDrawOpItems) {
186 if (item == nullptr) {
187 continue;
188 }
189 found = true;
190 item->Dump(out);
191 out += ' ';
192 }
193 if (found) {
194 out.pop_back();
195 }
196 }
197
MarshallingDrawOps()198 void DrawCmdList::MarshallingDrawOps()
199 {
200 if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
201 return;
202 }
203 std::lock_guard<std::recursive_mutex> lock(mutex_);
204 if (replacedOpListForVector_.empty()) {
205 for (auto& op : drawOpItems_) {
206 if (op) {
207 op->Marshalling(*this);
208 }
209 }
210 return;
211 }
212 for (auto& [index, op] : replacedOpListForVector_) {
213 op.swap(drawOpItems_[index]);
214 }
215 std::vector<uint32_t> opIndexForCache(replacedOpListForVector_.size());
216 uint32_t opReplaceIndex = 0;
217 for (auto index = 0u; index < drawOpItems_.size(); ++index) {
218 if (drawOpItems_[index]) {
219 drawOpItems_[index]->Marshalling(*this);
220 }
221 if (index == static_cast<size_t>(replacedOpListForVector_[opReplaceIndex].first)) {
222 opIndexForCache[opReplaceIndex] = lastOpItemOffset_.value();
223 ++opReplaceIndex;
224 }
225 }
226 for (auto index = 0u; index < replacedOpListForVector_.size(); ++index) {
227 if (replacedOpListForVector_[index].second) {
228 replacedOpListForVector_[index].second->Marshalling(*this);
229 }
230 replacedOpListForBuffer_.emplace_back(opIndexForCache[index], lastOpItemOffset_.value());
231 }
232 }
233
ProfilerMarshallingDrawOps(Drawing::DrawCmdList * cmdlist)234 void DrawCmdList::ProfilerMarshallingDrawOps(Drawing::DrawCmdList *cmdlist)
235 {
236 if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
237 return;
238 }
239 if (!cmdlist) {
240 return;
241 }
242
243 std::lock_guard<std::recursive_mutex> lock(mutex_);
244 for (auto& op : drawOpItems_) {
245 if (!op) {
246 continue;
247 }
248 if (op->GetType() == DrawOpItem::IMAGE_WITH_PARM_OPITEM) {
249 continue;
250 }
251 if (op->GetType() == DrawOpItem::IMAGE_OPITEM) {
252 continue;
253 }
254 if (op->GetType() == DrawOpItem::IMAGE_RECT_OPITEM) {
255 continue;
256 }
257 op->Marshalling(*cmdlist);
258 }
259 }
260
CaculatePerformanceOpType()261 void DrawCmdList::CaculatePerformanceOpType()
262 {
263 size_t offset = offset_;
264 const int caculatePerformaceCount = 500; // 被测单接口用例至少出现500次以上
265 std::map<uint32_t, uint32_t> opTypeCountMap;
266 uint32_t count = 0;
267 do {
268 count++;
269 void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
270 auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
271 if (curOpItemPtr == nullptr) {
272 break;
273 }
274 uint32_t type = curOpItemPtr->GetType();
275 if (opTypeCountMap.find(type) != opTypeCountMap.end()) {
276 if (++opTypeCountMap[type] > caculatePerformaceCount) {
277 performanceCaculateOpType_ = type;
278 DRAWING_PERFORMANCE_START_CACULATE;
279 return;
280 }
281 } else {
282 opTypeCountMap[type] = 1; // 记录出现的第1次
283 }
284 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
285 break;
286 }
287 offset = curOpItemPtr->GetNextOpItemOffset();
288 } while (offset != 0 && count <= MAX_OPITEMSIZE);
289 }
290
UnmarshallingDrawOps(uint32_t * opItemCount)291 void DrawCmdList::UnmarshallingDrawOps(uint32_t* opItemCount)
292 {
293 if (PerformanceCaculate::GetDrawingTestRecordingEnabled()) {
294 CaculatePerformanceOpType();
295 }
296 if (performanceCaculateOpType_ != 0) {
297 LOGI("Drawing Performance UnmarshallingDrawOps begin %{public}lld", PerformanceCaculate::GetUpTime());
298 }
299
300 if (opAllocator_.GetSize() <= offset_ || width_ <= 0 || height_ <= 0) {
301 return;
302 }
303
304 UnmarshallingPlayer player = { *this };
305 drawOpItems_.clear();
306 lastOpGenSize_ = 0;
307 uint32_t opReplaceIndex = 0;
308 size_t offset = offset_;
309 uint32_t count = 0;
310 do {
311 count++;
312 if (opItemCount && ++(*opItemCount) > MAX_OPITEMSIZE) {
313 LOGE("DrawCmdList::UnmarshallingOps failed, opItem count exceed limit");
314 break;
315 }
316 void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
317 auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
318 if (curOpItemPtr == nullptr) {
319 LOGE("DrawCmdList::UnmarshallingOps failed, opItem is nullptr");
320 break;
321 }
322 uint32_t type = curOpItemPtr->GetType();
323 auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset, isReplayMode);
324 if (!op) {
325 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
326 break;
327 }
328 offset = curOpItemPtr->GetNextOpItemOffset();
329 continue;
330 }
331 if (opReplaceIndex < replacedOpListForBuffer_.size() &&
332 replacedOpListForBuffer_[opReplaceIndex].first == offset) {
333 auto* replacePtr = opAllocator_.OffsetToAddr(
334 replacedOpListForBuffer_[opReplaceIndex].second, sizeof(OpItem));
335 if (replacePtr == nullptr) {
336 LOGE("DrawCmdList::Unmarshalling replace Ops failed, replace op is nullptr");
337 break;
338 }
339 auto* replaceOpItemPtr = static_cast<OpItem*>(replacePtr);
340 size_t avaliableSize = opAllocator_.GetSize() - replacedOpListForBuffer_[opReplaceIndex].second;
341 auto replaceOp = player.Unmarshalling(replaceOpItemPtr->GetType(), replacePtr, avaliableSize, isReplayMode);
342 if (replaceOp) {
343 drawOpItems_.emplace_back(replaceOp);
344 replacedOpListForVector_.emplace_back((drawOpItems_.size() - 1), op);
345 } else {
346 drawOpItems_.emplace_back(op);
347 }
348 opReplaceIndex++;
349 } else {
350 drawOpItems_.emplace_back(op);
351 }
352 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
353 break;
354 }
355 offset = curOpItemPtr->GetNextOpItemOffset();
356 if (!replacedOpListForBuffer_.empty() && offset >= replacedOpListForBuffer_[0].second) {
357 LOGD("DrawCmdList::UnmarshallingOps seek end by cache textOps");
358 break;
359 }
360 } while (offset != 0 && count <= MAX_OPITEMSIZE);
361 lastOpGenSize_ = opAllocator_.GetSize();
362
363 opAllocator_.ClearData();
364 imageAllocator_.ClearData();
365 bitmapAllocator_.ClearData();
366 opAllocator_.Add(&width_, sizeof(int32_t));
367 opAllocator_.Add(&height_, sizeof(int32_t));
368
369 if (performanceCaculateOpType_ != 0) {
370 LOGI("Drawing Performance UnmarshallingDrawOps end %{public}lld", PerformanceCaculate::GetUpTime());
371 }
372 }
373
Playback(Canvas & canvas,const Rect * rect)374 void DrawCmdList::Playback(Canvas& canvas, const Rect* rect)
375 {
376 if (canvas.GetUICapture() && noNeedUICaptured_) {
377 return;
378 }
379
380 if (width_ <= 0 || height_ <= 0) {
381 return;
382 }
383 if (performanceCaculateOpType_ != 0) {
384 LOGI("Drawing Performance Playback begin %{public}lld", PerformanceCaculate::GetUpTime());
385 }
386 if (canvas.GetDrawingType() == DrawingType::RECORDING) {
387 PlaybackToDrawCmdList(static_cast<RecordingCanvas&>(canvas).GetDrawCmdList());
388 return;
389 }
390 std::lock_guard<std::recursive_mutex> lock(mutex_);
391 #ifdef ROSEN_OHOS
392 // invalidate cache if high contrast flag changed
393 if (isCached_ && canvas.isHighContrastEnabled() != cachedHighContrast_) {
394 ClearCache();
395 }
396 // Generate or clear cache if cache state changed
397 if (canvas.GetCacheType() == Drawing::CacheType::ENABLED && !isCached_) {
398 GenerateCache(&canvas, rect);
399 } else if (canvas.GetCacheType() == Drawing::CacheType::DISABLED && isCached_) {
400 ClearCache();
401 }
402 #endif
403 Rect tmpRect;
404 if (rect != nullptr) {
405 tmpRect = *rect;
406 }
407 if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
408 PlaybackByBuffer(canvas, &tmpRect);
409 } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
410 PlaybackByVector(canvas, &tmpRect);
411 }
412 if (performanceCaculateOpType_ != 0) {
413 DRAWING_PERFORMANCE_STOP_CACULATE;
414 performanceCaculateOpType_ = 0;
415 LOGI("Drawing Performance Playback end %{public}lld", PerformanceCaculate::GetUpTime());
416 }
417 }
418
GenerateCache(Canvas * canvas,const Rect * rect)419 void DrawCmdList::GenerateCache(Canvas* canvas, const Rect* rect)
420 {
421 #ifdef ROSEN_OHOS
422 if (isCached_) {
423 LOGD("DrawCmdList::GenerateCache Invoke multiple times");
424 return;
425 }
426
427 std::lock_guard<std::recursive_mutex> lock(mutex_);
428 if (mode_ == DrawCmdList::UnmarshalMode::IMMEDIATE) {
429 GenerateCacheByBuffer(canvas, rect);
430 } else if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
431 GenerateCacheByVector(canvas, rect);
432 }
433 #endif
434 }
435
GetIsCache() const436 bool DrawCmdList::GetIsCache() const
437 {
438 return isCached_;
439 }
440
SetIsCache(bool isCached)441 void DrawCmdList::SetIsCache(bool isCached)
442 {
443 isCached_ = isCached;
444 }
445
GetCachedHighContrast() const446 bool DrawCmdList::GetCachedHighContrast() const
447 {
448 return cachedHighContrast_;
449 }
450
SetCachedHighContrast(bool cachedHighContrast)451 void DrawCmdList::SetCachedHighContrast(bool cachedHighContrast)
452 {
453 cachedHighContrast_ = cachedHighContrast;
454 }
455
GetReplacedOpList()456 std::vector<std::pair<size_t, size_t>> DrawCmdList::GetReplacedOpList()
457 {
458 return replacedOpListForBuffer_;
459 }
460
SetReplacedOpList(std::vector<std::pair<size_t,size_t>> replacedOpList)461 void DrawCmdList::SetReplacedOpList(std::vector<std::pair<size_t, size_t>> replacedOpList)
462 {
463 replacedOpListForBuffer_ = replacedOpList;
464 }
465
GetHybridRenderType() const466 DrawCmdList::HybridRenderType DrawCmdList::GetHybridRenderType() const
467 {
468 return hybridRenderType_;
469 }
470
SetHybridRenderType(DrawCmdList::HybridRenderType hybridRenderType)471 void DrawCmdList::SetHybridRenderType(DrawCmdList::HybridRenderType hybridRenderType)
472 {
473 hybridRenderType_ = hybridRenderType;
474 }
475
UpdateNodeIdToPicture(NodeId nodeId)476 void DrawCmdList::UpdateNodeIdToPicture(NodeId nodeId)
477 {
478 if (drawOpItems_.size() == 0) {
479 return;
480 }
481 for (size_t i = 0; i < drawOpItems_.size(); ++i) {
482 auto opItem = drawOpItems_[i];
483 if (!opItem) {
484 continue;
485 }
486 opItem->SetNodeId(nodeId);
487 }
488 }
489
ClearCache()490 void DrawCmdList::ClearCache()
491 {
492 #ifdef ROSEN_OHOS
493 // restore the original op
494 for (auto& [index, op] : replacedOpListForVector_) {
495 op.swap(drawOpItems_[index]);
496 }
497 replacedOpListForVector_.clear();
498 replacedOpListForBuffer_.clear();
499 isCached_ = false;
500 #endif
501 }
502
GenerateCacheByVector(Canvas * canvas,const Rect * rect)503 void DrawCmdList::GenerateCacheByVector(Canvas* canvas, const Rect* rect)
504 {
505 #ifdef ROSEN_OHOS
506 if (drawOpItems_.size() == 0) {
507 return;
508 }
509 uint32_t opSize = drawOpItems_.size();
510 for (auto index = 0u; index < opSize; ++index) {
511 std::shared_ptr<DrawOpItem> op = drawOpItems_[index];
512 if (!op || op->GetType() != DrawOpItem::TEXT_BLOB_OPITEM) {
513 continue;
514 }
515 DrawTextBlobOpItem* textBlobOp = static_cast<DrawTextBlobOpItem*>(op.get());
516 auto replaceCache = textBlobOp->GenerateCachedOpItem(canvas);
517 if (replaceCache) {
518 replacedOpListForVector_.emplace_back(index, op);
519 drawOpItems_[index] = replaceCache;
520 }
521 }
522 isCached_ = true;
523 cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
524 #endif
525 }
526
GenerateCacheByBuffer(Canvas * canvas,const Rect * rect)527 void DrawCmdList::GenerateCacheByBuffer(Canvas* canvas, const Rect* rect)
528 {
529 #ifdef ROSEN_OHOS
530 if (opAllocator_.GetSize() <= offset_) {
531 return;
532 }
533
534 size_t offset = offset_;
535 GenerateCachedOpItemPlayer player = { *this, canvas, rect };
536 uint32_t maxOffset = opAllocator_.GetSize();
537 uint32_t count = 0;
538 do {
539 count++;
540 void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
541 auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
542 if (curOpItemPtr == nullptr) {
543 LOGE("DrawCmdList::GenerateCacheByBuffer failed, opItem is nullptr");
544 break;
545 }
546 size_t avaliableSize = opAllocator_.GetSize() - offset;
547 bool replaceSuccess = player.GenerateCachedOpItem(curOpItemPtr->GetType(), itemPtr, avaliableSize);
548 if (replaceSuccess) {
549 replacedOpListForBuffer_.push_back({offset, lastOpItemOffset_.value()});
550 itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
551 curOpItemPtr = static_cast<OpItem*>(itemPtr);
552 if (curOpItemPtr == nullptr) {
553 LOGE("DrawCmdList::GenerateCache failed, opItem is nullptr");
554 break;
555 }
556 }
557 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
558 break;
559 }
560 offset = curOpItemPtr->GetNextOpItemOffset();
561 } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
562 isCached_ = true;
563 cachedHighContrast_ = canvas && canvas->isHighContrastEnabled();
564 #endif
565 }
566
PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)567 void DrawCmdList::PlaybackToDrawCmdList(std::shared_ptr<DrawCmdList> drawCmdList)
568 {
569 if (!drawCmdList) {
570 return;
571 }
572 std::lock_guard<std::recursive_mutex> lock(mutex_);
573 if (mode_ == DrawCmdList::UnmarshalMode::DEFERRED) {
574 std::lock_guard<std::recursive_mutex> lock(drawCmdList->mutex_);
575 drawCmdList->drawOpItems_.insert(drawCmdList->drawOpItems_.end(), drawOpItems_.begin(), drawOpItems_.end());
576 return;
577 }
578
579 void* addr = opAllocator_.OffsetToAddr(offset_, 0);
580 if (addr == nullptr) {
581 return;
582 }
583
584 {
585 std::lock_guard<std::mutex> lock(drawCmdList->recordCmdMutex_);
586 drawCmdList->recordCmdVec_.swap(recordCmdVec_);
587 }
588 #ifdef SUPPORT_OHOS_PIXMAP
589 {
590 std::lock_guard<std::mutex> lock(drawCmdList->imageObjectMutex_);
591 drawCmdList->imageObjectVec_.swap(imageObjectVec_);
592 }
593 #endif
594 {
595 std::lock_guard<std::mutex> lock(drawCmdList->imageBaseObjMutex_);
596 drawCmdList->imageBaseObjVec_.swap(imageBaseObjVec_);
597 }
598 size_t size = opAllocator_.GetSize() - offset_;
599 auto imageData = GetAllImageData();
600 auto bitmapData = GetAllBitmapData();
601 drawCmdList->opAllocator_.Add(addr, size);
602 if (imageData.first != nullptr && imageData.second != 0) {
603 drawCmdList->AddImageData(imageData.first, imageData.second);
604 }
605
606 if (bitmapData.first != nullptr && bitmapData.second != 0) {
607 drawCmdList->AddBitmapData(bitmapData.first, bitmapData.second);
608 }
609 }
610
PlaybackByVector(Canvas & canvas,const Rect * rect)611 void DrawCmdList::PlaybackByVector(Canvas& canvas, const Rect* rect)
612 {
613 if (drawOpItems_.empty()) {
614 return;
615 }
616 uint32_t opCount = 0;
617 for (auto op : drawOpItems_) {
618 if (isCanvasDrawingOpLimitEnabled_ && opCount > DRAWCMDLIST_OPSIZE_COUNT_LIMIT) {
619 LOGE("DrawCmdList::PlaybackByVector Out of DrawOp limit, DrawOpCount: %{public}d", opCount);
620 break;
621 }
622 if (op) {
623 op->Playback(&canvas, rect);
624 ++opCount;
625 }
626 }
627 canvas.DetachPaint();
628 }
629
UnmarshallingDrawOpsSimple(std::vector<std::shared_ptr<DrawOpItem>> & drawOpItems,size_t & lastOpGenSize)630 bool DrawCmdList::UnmarshallingDrawOpsSimple(
631 std::vector<std::shared_ptr<DrawOpItem>>& drawOpItems, size_t& lastOpGenSize)
632 {
633 if (opAllocator_.GetSize() <= offset_) {
634 return false;
635 }
636 size_t offset = offset_;
637 if (lastOpGenSize != opAllocator_.GetSize()) {
638 uint32_t count = 0;
639 UnmarshallingPlayer player = { *this };
640 drawOpItems.clear();
641 do {
642 count++;
643 void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
644 auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
645 if (curOpItemPtr == nullptr) {
646 break;
647 }
648 uint32_t type = curOpItemPtr->GetType();
649 if (auto op = player.Unmarshalling(type, itemPtr, opAllocator_.GetSize() - offset, isReplayMode)) {
650 drawOpItems_.emplace_back(op);
651 }
652 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
653 break;
654 }
655 offset = curOpItemPtr->GetNextOpItemOffset();
656 } while (offset != 0 && count <= MAX_OPITEMSIZE);
657 lastOpGenSize = opAllocator_.GetSize();
658 }
659 return true;
660 }
661
PlaybackByBuffer(Canvas & canvas,const Rect * rect)662 void DrawCmdList::PlaybackByBuffer(Canvas& canvas, const Rect* rect)
663 {
664 if (!UnmarshallingDrawOpsSimple(drawOpItems_, lastOpGenSize_)) {
665 return;
666 }
667 uint32_t opCount = 0;
668 for (auto op : drawOpItems_) {
669 if (isCanvasDrawingOpLimitEnabled_ && opCount > DRAWCMDLIST_OPSIZE_COUNT_LIMIT) {
670 LOGE("DrawCmdList::PlaybackByBuffer Out of DrawOp limit, DrawOpCount: %{public}d", opCount);
671 break;
672 }
673 if (op) {
674 op->Playback(&canvas, rect);
675 ++opCount;
676 }
677 }
678 canvas.DetachPaint();
679 }
680
GetBounds(Rect & rect)681 void DrawCmdList::GetBounds(Rect& rect)
682 {
683 std::lock_guard<std::recursive_mutex> lock(mutex_);
684 for (const auto& op : drawOpItems_) {
685 if (op == nullptr) {
686 continue;
687 }
688 switch (op->GetType()) {
689 case DrawOpItem::HYBRID_RENDER_PIXELMAP_SIZE_OPITEM: {
690 HybridRenderPixelMapSizeOpItem *sizeOp = static_cast<HybridRenderPixelMapSizeOpItem*>(op.get());
691 rect.Join(Rect(0, 0, sizeOp->GetWidth(), sizeOp->GetHeight()));
692 break;
693 }
694 default:
695 break;
696 }
697 }
698 }
699
IsHybridRenderEnabled(uint32_t maxPixelMapWidth,uint32_t maxPixelMapHeight)700 bool DrawCmdList::IsHybridRenderEnabled(uint32_t maxPixelMapWidth, uint32_t maxPixelMapHeight)
701 {
702 std::lock_guard<std::recursive_mutex> lock(mutex_);
703 // canvasdrawingnode does not support switching from enable to disable
704 if (hybridRenderType_ == HybridRenderType::CANVAS) {
705 return true;
706 }
707 if (!UnmarshallingDrawOpsSimple(drawOpItems_, lastOpGenSize_)) {
708 return false;
709 }
710 // check size
711 Drawing::Rect bounds;
712 int32_t width = GetWidth();
713 int32_t height = GetHeight();
714 GetBounds(bounds);
715 width = std::max(width, DrawingFloatSaturate2Int(ceilf(bounds.GetWidth())));
716 height = std::max(height, DrawingFloatSaturate2Int(ceilf(bounds.GetHeight())));
717 if (width < 0 || height < 0 ||
718 static_cast<uint32_t>(width) > maxPixelMapWidth || static_cast<uint32_t>(height) > maxPixelMapHeight) {
719 return false;
720 }
721 return true;
722 }
723
ProfilerTextBlob(void * handle,uint32_t count,std::shared_ptr<Drawing::DrawCmdList> refDrawCmdList)724 void DrawCmdList::ProfilerTextBlob(void* handle, uint32_t count, std::shared_ptr<Drawing::DrawCmdList> refDrawCmdList)
725 {
726 if (!handle) {
727 return;
728 }
729 DrawTextBlobOpItem::ConstructorHandle* constructorHandle =
730 static_cast<DrawTextBlobOpItem::ConstructorHandle*>(handle);
731 if (refDrawCmdList) {
732 if (count > 0 && count - 1 < refDrawCmdList->drawOpItems_.size()) {
733 auto drawOpItem = refDrawCmdList->drawOpItems_[count - 1];
734 if (drawOpItem && drawOpItem->GetType() == DrawOpItem::TEXT_BLOB_OPITEM) {
735 auto drawTextOpItem = static_cast<DrawTextBlobOpItem*>(drawOpItem.get());
736 constructorHandle->globalUniqueId = drawTextOpItem->GetTypefaceId();
737 }
738 }
739 } else if (constructorHandle->globalUniqueId) {
740 constexpr int bitNumber = 30 + 32;
741 uint64_t replayMask = (uint64_t)1 << bitNumber;
742 constructorHandle->globalUniqueId |= replayMask;
743 }
744 }
745
PatchTypefaceIds(std::shared_ptr<Drawing::DrawCmdList> refDrawCmdList)746 void DrawCmdList::PatchTypefaceIds(std::shared_ptr<Drawing::DrawCmdList> refDrawCmdList)
747 {
748 size_t offset = offset_;
749 size_t maxOffset = opAllocator_.GetSize();
750 uint32_t count = 0;
751 do {
752 count++;
753 void* itemPtr = opAllocator_.OffsetToAddr(offset, sizeof(OpItem));
754 auto* curOpItemPtr = static_cast<OpItem*>(itemPtr);
755 if (curOpItemPtr == nullptr) {
756 break;
757 }
758 uint32_t type = curOpItemPtr->GetType();
759 if (type == DrawOpItem::TEXT_BLOB_OPITEM) {
760 DrawTextBlobOpItem::ConstructorHandle* handle =
761 static_cast<DrawTextBlobOpItem::ConstructorHandle*>(curOpItemPtr);
762 ProfilerTextBlob(handle, count, refDrawCmdList);
763 }
764 if (curOpItemPtr->GetNextOpItemOffset() < offset + sizeof(OpItem)) {
765 break;
766 }
767 offset = curOpItemPtr->GetNextOpItemOffset();
768 } while (offset != 0 && offset < maxOffset && count <= MAX_OPITEMSIZE);
769 }
770
Purge()771 void DrawCmdList::Purge()
772 {
773 std::lock_guard<std::recursive_mutex> lock(mutex_);
774 for (auto op : drawOpItems_) {
775 if (!op) {
776 continue;
777 }
778 auto type = op->GetType();
779 if (type == DrawOpItem::PIXELMAP_RECT_OPITEM ||
780 type == DrawOpItem::PIXELMAP_WITH_PARM_OPITEM ||
781 type == DrawOpItem::PIXELMAP_NINE_OPITEM ||
782 type == DrawOpItem::PIXELMAP_LATTICE_OPITEM) {
783 op->Purge();
784 }
785 }
786 }
787
SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)788 void DrawCmdList::SetIsNeedUnmarshalOnDestruct(bool isNeedUnmarshalOnDestruct)
789 {
790 isNeedUnmarshalOnDestruct_ = isNeedUnmarshalOnDestruct;
791 }
792
GetSize()793 size_t DrawCmdList::GetSize()
794 {
795 size_t totoalSize = sizeof(*this);
796
797 {
798 std::lock_guard<std::recursive_mutex> lock(mutex_);
799 totoalSize += opAllocator_.GetSize() + imageAllocator_.GetSize() + bitmapAllocator_.GetSize();
800 for (auto op : drawOpItems_) {
801 if (op) {
802 totoalSize += op->GetOpSize();
803 }
804 }
805 }
806 return totoalSize;
807 }
808
SetCanvasDrawingOpLimitEnable(bool isEnable)809 void DrawCmdList::SetCanvasDrawingOpLimitEnable(bool isEnable)
810 {
811 isCanvasDrawingOpLimitEnabled_ = isEnable;
812 }
813
GetDrawOpItems() const814 const std::vector<std::shared_ptr<DrawOpItem>> DrawCmdList::GetDrawOpItems() const
815 {
816 std::vector<std::shared_ptr<DrawOpItem>> drawOpItems(drawOpItems_);
817 return drawOpItems;
818 }
819
GetCmdlistDrawRegion()820 RectF DrawCmdList::GetCmdlistDrawRegion()
821 {
822 Rect cmdlistDrawRegion;
823 {
824 std::lock_guard<std::recursive_mutex> lock(mutex_);
825 for (const auto& op : drawOpItems_) {
826 if (!op) {
827 continue;
828 }
829 const auto& type = op->GetType();
830 switch (type) {
831 // dst opItem
832 case DrawOpItem::PATH_OPITEM:
833 case DrawOpItem::TEXT_BLOB_OPITEM:
834 case DrawOpItem::RECT_OPITEM:
835 cmdlistDrawRegion.Join(op->GetOpItemCmdlistDrawRegion());
836 break;
837 // not dst opItem, but will appear in dst scene
838 case DrawOpItem::CLIP_RECT_OPITEM:
839 case DrawOpItem::CLIP_ROUND_RECT_OPITEM:
840 case DrawOpItem::CONCAT_MATRIX_OPITEM:
841 case DrawOpItem::SCALE_OPITEM:
842 case DrawOpItem::SAVE_OPITEM:
843 case DrawOpItem::RESTORE_OPITEM:
844 case DrawOpItem::PIXELMAP_RECT_OPITEM:
845 break;
846 default:
847 return Rect(0, 0, 0, 0);
848 }
849 }
850 }
851 return cmdlistDrawRegion;
852 }
853 } // namespace Drawing
854 } // namespace Rosen
855 } // namespace OHOS
856