• 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 "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