1 /*
2  * Copyright (c) 2024 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 "render_barrier_list.h"
17 
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdint>
21 
22 #include <render/namespace.h>
23 
24 #include "nodecontext/render_command_list.h"
25 #include "util/linear_allocator.h"
26 #include "util/log.h"
27 
28 using namespace BASE_NS;
29 
30 RENDER_BEGIN_NAMESPACE()
31 namespace {
32 constexpr size_t MEMORY_ALIGNMENT { 16 };
33 
AllocateBarrierListMemory(RenderBarrierList::LinearAllocatorStruct & allocator,const size_t byteSize)34 void* AllocateBarrierListMemory(RenderBarrierList::LinearAllocatorStruct& allocator, const size_t byteSize)
35 {
36     void* rc = allocator.allocators[allocator.currentIndex]->Allocate(byteSize);
37     if (rc) {
38         return rc;
39     } else { // current allocator is out of memory
40         PLUGIN_ASSERT_MSG(allocator.allocators[allocator.currentIndex]->GetByteSize() > 0,
41             "do not create render barrier list with zero size initial allocation");
42 
43         const size_t alignment = allocator.allocators[allocator.currentIndex]->GetAlignment();
44 
45         allocator.allocators.push_back(make_unique<LinearAllocator>(byteSize, alignment));
46         allocator.currentIndex = static_cast<uint32_t>(allocator.allocators.size() - 1);
47 
48         rc = allocator.allocators[allocator.currentIndex]->Allocate(byteSize);
49         PLUGIN_ASSERT_MSG(rc, "render barrier list allocation : out of memory");
50         return rc;
51     }
52 }
53 
AllocateCommandBarriers(RenderBarrierList::LinearAllocatorStruct & allocator,const size_t count)54 CommandBarrier* AllocateCommandBarriers(RenderBarrierList::LinearAllocatorStruct& allocator, const size_t count)
55 {
56     const size_t byteSize = count * sizeof(CommandBarrier);
57     return static_cast<CommandBarrier*>(AllocateBarrierListMemory(allocator, byteSize));
58 }
59 } // namespace
60 
RenderBarrierList(const uint32_t reserveBarrierCountHint)61 RenderBarrierList::RenderBarrierList(const uint32_t reserveBarrierCountHint)
62 {
63     const size_t memAllocationByteSize = sizeof(CommandBarrier) * reserveBarrierCountHint;
64     if (memAllocationByteSize > 0) {
65         linearAllocator_.allocators.push_back(make_unique<LinearAllocator>(memAllocationByteSize, MEMORY_ALIGNMENT));
66     }
67 }
68 
BeginFrame()69 void RenderBarrierList::BeginFrame()
70 {
71     const auto clearAndReserve = [](auto& vec) {
72         const size_t count = vec.size();
73         vec.clear();
74         vec.reserve(count);
75     };
76 
77     clearAndReserve(barrierPointBarriers_);
78     clearAndReserve(barrierPointIndextoIndex_);
79 
80     if (!linearAllocator_.allocators.empty()) {
81         linearAllocator_.currentIndex = 0;
82         if (linearAllocator_.allocators.size() == 1) { // size is good for this frame
83             linearAllocator_.allocators[linearAllocator_.currentIndex]->Reset();
84         } else if (linearAllocator_.allocators.size() > 1) {
85             size_t fullByteSize = 0;
86             size_t alignment = 0;
87             for (auto& ref : linearAllocator_.allocators) {
88                 fullByteSize += ref->GetCurrentByteSize();
89                 alignment = std::max(alignment, (size_t)ref->GetAlignment());
90                 ref.reset();
91             }
92             linearAllocator_.allocators.clear();
93 
94             // create new single allocation for combined previous size and some extra bytes
95             linearAllocator_.allocators.push_back(make_unique<LinearAllocator>(fullByteSize, alignment));
96         }
97     }
98 }
99 
AddBarriersToBarrierPoint(const uint32_t barrierPointIndex,const vector<CommandBarrier> & barriers)100 void RenderBarrierList::AddBarriersToBarrierPoint(
101     const uint32_t barrierPointIndex, const vector<CommandBarrier>& barriers)
102 {
103     if (!barriers.empty()) {
104         BarrierPointBarrierList* structData = static_cast<BarrierPointBarrierList*>(
105             AllocateBarrierListMemory(linearAllocator_, sizeof(BarrierPointBarrierList)));
106         CommandBarrier* commandBarrierData = AllocateCommandBarriers(linearAllocator_, barriers.size());
107         if (structData && commandBarrierData) {
108             const size_t barriersByteSize = barriers.size() * sizeof(CommandBarrier);
109             const bool val = CloneData(commandBarrierData, barriersByteSize, barriers.data(), barriersByteSize);
110             PLUGIN_UNUSED(val);
111             PLUGIN_ASSERT(val);
112             size_t barrierIndex = 0;
113             if (auto iter = barrierPointIndextoIndex_.find(barrierPointIndex);
114                 iter != barrierPointIndextoIndex_.cend()) {
115                 barrierIndex = iter->second;
116             } else { // first barrier to this barrier point index
117                 barrierPointBarriers_.push_back(BarrierPointBarriers {});
118                 barrierIndex = barrierPointBarriers_.size() - 1;
119                 barrierPointIndextoIndex_[barrierPointIndex] = barrierIndex;
120             }
121 
122             const uint32_t barrierCount = static_cast<uint32_t>(barriers.size());
123             BarrierPointBarriers& ref = barrierPointBarriers_[barrierIndex];
124             ref.fullCommandBarrierCount += barrierCount;
125             ref.barrierListCount += 1u;
126 
127             structData->count = barrierCount;
128             structData->commandBarriers = commandBarrierData;
129             if (ref.barrierListCount == 1) { // first barrier point barrier list
130                 ref.firstBarrierList = structData;
131             } else {
132                 // patch next pointer for previous BarrierPointBarrierList
133                 ref.lastBarrierList->nextBarrierPointBarrierList = structData;
134             }
135             ref.lastBarrierList = structData;
136 
137             PLUGIN_ASSERT(ref.firstBarrierList);
138             PLUGIN_ASSERT(ref.lastBarrierList);
139         }
140     }
141 }
142 
HasBarriers(const uint32_t barrierPointIndex) const143 bool RenderBarrierList::HasBarriers(const uint32_t barrierPointIndex) const
144 {
145     return (barrierPointIndextoIndex_.count(barrierPointIndex) == 1);
146 }
147 
GetBarrierPointBarriers(const uint32_t barrierPointIndex) const148 const RenderBarrierList::BarrierPointBarriers* RenderBarrierList::GetBarrierPointBarriers(
149     const uint32_t barrierPointIndex) const
150 {
151     const BarrierPointBarriers* barriers = nullptr;
152 
153     if (const auto iter = barrierPointIndextoIndex_.find(barrierPointIndex); iter != barrierPointIndextoIndex_.cend()) {
154         const size_t index = iter->second;
155         PLUGIN_ASSERT(index < barrierPointBarriers_.size());
156         if (index < barrierPointBarriers_.size()) {
157             barriers = &barrierPointBarriers_[index];
158         }
159     }
160 
161     return barriers;
162 }
163 RENDER_END_NAMESPACE()
164