1 //
2 // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Suballocation.cpp:
7 // Implements class methods for BufferBlock and Suballocation and other related classes
8 //
9
10 // #include "libANGLE/renderer/vulkan/vk_utils.h"
11
12 #include "libANGLE/renderer/vulkan/Suballocation.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
15 #include "libANGLE/renderer/vulkan/vk_renderer.h"
16
17 namespace rx
18 {
19 namespace vk
20 {
21 // BufferBlock implementation.
BufferBlock()22 BufferBlock::BufferBlock()
23 : mMemoryPropertyFlags(0),
24 mSize(0),
25 mAllocatedBufferSize(0),
26 mMemoryAllocationType(MemoryAllocationType::InvalidEnum),
27 mMemoryTypeIndex(kInvalidMemoryTypeIndex),
28 mMappedMemory(nullptr)
29 {}
30
BufferBlock(BufferBlock && other)31 BufferBlock::BufferBlock(BufferBlock &&other)
32 : mVirtualBlock(std::move(other.mVirtualBlock)),
33 mBuffer(std::move(other.mBuffer)),
34 mDeviceMemory(std::move(other.mDeviceMemory)),
35 mMemoryPropertyFlags(other.mMemoryPropertyFlags),
36 mSize(other.mSize),
37 mAllocatedBufferSize(other.mAllocatedBufferSize),
38 mMemoryAllocationType(other.mMemoryAllocationType),
39 mMemoryTypeIndex(other.mMemoryTypeIndex),
40 mMappedMemory(other.mMappedMemory),
41 mSerial(other.mSerial),
42 mCountRemainsEmpty(0)
43 {}
44
operator =(BufferBlock && other)45 BufferBlock &BufferBlock::operator=(BufferBlock &&other)
46 {
47 std::swap(mVirtualBlock, other.mVirtualBlock);
48 std::swap(mBuffer, other.mBuffer);
49 std::swap(mDeviceMemory, other.mDeviceMemory);
50 std::swap(mMemoryPropertyFlags, other.mMemoryPropertyFlags);
51 std::swap(mSize, other.mSize);
52 std::swap(mAllocatedBufferSize, other.mAllocatedBufferSize);
53 std::swap(mMemoryAllocationType, other.mMemoryAllocationType);
54 std::swap(mMemoryTypeIndex, other.mMemoryTypeIndex);
55 std::swap(mMappedMemory, other.mMappedMemory);
56 std::swap(mSerial, other.mSerial);
57 std::swap(mCountRemainsEmpty, other.mCountRemainsEmpty);
58 return *this;
59 }
60
~BufferBlock()61 BufferBlock::~BufferBlock()
62 {
63 ASSERT(!mVirtualBlock.valid());
64 ASSERT(!mBuffer.valid());
65 ASSERT(!mDeviceMemory.valid());
66 }
67
destroy(Renderer * renderer)68 void BufferBlock::destroy(Renderer *renderer)
69 {
70 VkDevice device = renderer->getDevice();
71
72 if (mMappedMemory)
73 {
74 unmap(device);
75 }
76
77 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocatedBufferSize, mMemoryTypeIndex,
78 mDeviceMemory.getHandle());
79
80 mVirtualBlock.destroy(device);
81 mBuffer.destroy(device);
82 mDeviceMemory.destroy(device);
83 }
84
init(ErrorContext * context,Buffer & buffer,uint32_t memoryTypeIndex,vma::VirtualBlockCreateFlags flags,DeviceMemory & deviceMemory,VkMemoryPropertyFlags memoryPropertyFlags,VkDeviceSize size)85 VkResult BufferBlock::init(ErrorContext *context,
86 Buffer &buffer,
87 uint32_t memoryTypeIndex,
88 vma::VirtualBlockCreateFlags flags,
89 DeviceMemory &deviceMemory,
90 VkMemoryPropertyFlags memoryPropertyFlags,
91 VkDeviceSize size)
92 {
93 Renderer *renderer = context->getRenderer();
94 ASSERT(!mVirtualBlock.valid());
95 ASSERT(!mBuffer.valid());
96 ASSERT(!mDeviceMemory.valid());
97
98 VK_RESULT_TRY(mVirtualBlock.init(renderer->getDevice(), flags, size));
99
100 mBuffer = std::move(buffer);
101 mDeviceMemory = std::move(deviceMemory);
102 mMemoryPropertyFlags = memoryPropertyFlags;
103 mSize = size;
104 mAllocatedBufferSize = size;
105 mMemoryAllocationType = MemoryAllocationType::Buffer;
106 mMemoryTypeIndex = memoryTypeIndex;
107 mMappedMemory = nullptr;
108 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
109
110 return VK_SUCCESS;
111 }
112
initWithoutVirtualBlock(ErrorContext * context,Buffer & buffer,MemoryAllocationType memoryAllocationType,uint32_t memoryTypeIndex,DeviceMemory & deviceMemory,VkMemoryPropertyFlags memoryPropertyFlags,VkDeviceSize size,VkDeviceSize allocatedBufferSize)113 void BufferBlock::initWithoutVirtualBlock(ErrorContext *context,
114 Buffer &buffer,
115 MemoryAllocationType memoryAllocationType,
116 uint32_t memoryTypeIndex,
117 DeviceMemory &deviceMemory,
118 VkMemoryPropertyFlags memoryPropertyFlags,
119 VkDeviceSize size,
120 VkDeviceSize allocatedBufferSize)
121 {
122 Renderer *renderer = context->getRenderer();
123 ASSERT(!mVirtualBlock.valid());
124 ASSERT(!mBuffer.valid());
125 ASSERT(!mDeviceMemory.valid());
126
127 mBuffer = std::move(buffer);
128 mDeviceMemory = std::move(deviceMemory);
129 mMemoryPropertyFlags = memoryPropertyFlags;
130 mSize = size;
131 mAllocatedBufferSize = allocatedBufferSize;
132 mMemoryAllocationType = memoryAllocationType;
133 mMemoryTypeIndex = memoryTypeIndex;
134 mMappedMemory = nullptr;
135 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
136 }
137
map(const VkDevice device)138 VkResult BufferBlock::map(const VkDevice device)
139 {
140 ASSERT(mMappedMemory == nullptr);
141 return mDeviceMemory.map(device, 0, mAllocatedBufferSize, 0, &mMappedMemory);
142 }
143
unmap(const VkDevice device)144 void BufferBlock::unmap(const VkDevice device)
145 {
146 mDeviceMemory.unmap(device);
147 mMappedMemory = nullptr;
148 }
149
allocate(VkDeviceSize size,VkDeviceSize alignment,VmaVirtualAllocation * allocationOut,VkDeviceSize * offsetOut)150 VkResult BufferBlock::allocate(VkDeviceSize size,
151 VkDeviceSize alignment,
152 VmaVirtualAllocation *allocationOut,
153 VkDeviceSize *offsetOut)
154 {
155 std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
156 mCountRemainsEmpty = 0;
157 return mVirtualBlock.allocate(size, alignment, allocationOut, offsetOut);
158 }
159
free(VmaVirtualAllocation allocation,VkDeviceSize offset)160 void BufferBlock::free(VmaVirtualAllocation allocation, VkDeviceSize offset)
161 {
162 std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
163 mVirtualBlock.free(allocation, offset);
164 }
165
getAndIncrementEmptyCounter()166 int32_t BufferBlock::getAndIncrementEmptyCounter()
167 {
168 return ++mCountRemainsEmpty;
169 }
170
calculateStats(vma::StatInfo * pStatInfo) const171 void BufferBlock::calculateStats(vma::StatInfo *pStatInfo) const
172 {
173 std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
174 mVirtualBlock.calculateStats(pStatInfo);
175 }
176
177 // BufferSuballocation implementation.
map(ErrorContext * context)178 VkResult BufferSuballocation::map(ErrorContext *context)
179 {
180 return mBufferBlock->map(context->getDevice());
181 }
182
flush(Renderer * renderer)183 void BufferSuballocation::flush(Renderer *renderer)
184 {
185 if (!isCoherent())
186 {
187 const VkDeviceSize nonCoherentAtomSize =
188 renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize;
189
190 VkMappedMemoryRange mappedRange = {};
191 mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
192 mappedRange.memory = mBufferBlock->getDeviceMemory().getHandle();
193 mappedRange.offset = getOffset();
194 mappedRange.size = roundUp<VkDeviceSize>(mSize, nonCoherentAtomSize);
195
196 ASSERT(mappedRange.size <= mBufferBlock->getAllocatedBufferSize());
197 mBufferBlock->getDeviceMemory().flush(renderer->getDevice(), mappedRange);
198 }
199 }
200
invalidate(Renderer * renderer)201 void BufferSuballocation::invalidate(Renderer *renderer)
202 {
203 if (!isCoherent())
204 {
205 const VkDeviceSize nonCoherentAtomSize =
206 renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize;
207
208 VkMappedMemoryRange mappedRange = {};
209 mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
210 mappedRange.memory = mBufferBlock->getDeviceMemory().getHandle();
211 mappedRange.offset = getOffset();
212 mappedRange.size = roundUp<VkDeviceSize>(mSize, nonCoherentAtomSize);
213
214 ASSERT(mappedRange.size <= mBufferBlock->getAllocatedBufferSize());
215 mBufferBlock->getDeviceMemory().invalidate(renderer->getDevice(), mappedRange);
216 }
217 }
218
219 // BufferSuballocationGarbage implementation.
destroyIfComplete(Renderer * renderer)220 bool BufferSuballocationGarbage::destroyIfComplete(Renderer *renderer)
221 {
222 if (renderer->hasResourceUseFinished(mLifetime))
223 {
224 mBuffer.destroy(renderer->getDevice());
225 mSuballocation.destroy(renderer);
226 return true;
227 }
228 return false;
229 }
230
hasResourceUseSubmitted(Renderer * renderer) const231 bool BufferSuballocationGarbage::hasResourceUseSubmitted(Renderer *renderer) const
232 {
233 return renderer->hasResourceUseSubmitted(mLifetime);
234 }
235 } // namespace vk
236 } // namespace rx
237