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