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