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/RendererVk.h"
15 #include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.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 ASSERT(mDescriptorSetCacheManager.empty());
67 }
68
destroy(RendererVk * renderer)69 void BufferBlock::destroy(RendererVk *renderer)
70 {
71 VkDevice device = renderer->getDevice();
72
73 mDescriptorSetCacheManager.destroyKeys(renderer);
74 if (mMappedMemory)
75 {
76 unmap(device);
77 }
78
79 renderer->onMemoryDealloc(mMemoryAllocationType, mAllocatedBufferSize, mMemoryTypeIndex,
80 mDeviceMemory.getHandle());
81
82 mVirtualBlock.destroy(device);
83 mBuffer.destroy(device);
84 mDeviceMemory.destroy(device);
85 }
86
init(Context * context,Buffer & buffer,uint32_t memoryTypeIndex,vma::VirtualBlockCreateFlags flags,DeviceMemory & deviceMemory,VkMemoryPropertyFlags memoryPropertyFlags,VkDeviceSize size)87 angle::Result BufferBlock::init(Context *context,
88 Buffer &buffer,
89 uint32_t memoryTypeIndex,
90 vma::VirtualBlockCreateFlags flags,
91 DeviceMemory &deviceMemory,
92 VkMemoryPropertyFlags memoryPropertyFlags,
93 VkDeviceSize size)
94 {
95 RendererVk *renderer = context->getRenderer();
96 ASSERT(!mVirtualBlock.valid());
97 ASSERT(!mBuffer.valid());
98 ASSERT(!mDeviceMemory.valid());
99
100 ANGLE_VK_TRY(context, mVirtualBlock.init(renderer->getDevice(), flags, size));
101
102 mBuffer = std::move(buffer);
103 mDeviceMemory = std::move(deviceMemory);
104 mMemoryPropertyFlags = memoryPropertyFlags;
105 mSize = size;
106 mAllocatedBufferSize = size;
107 mMemoryAllocationType = MemoryAllocationType::Buffer;
108 mMemoryTypeIndex = memoryTypeIndex;
109 mMappedMemory = nullptr;
110 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
111
112 return angle::Result::Continue;
113 }
114
initWithoutVirtualBlock(Context * context,Buffer & buffer,MemoryAllocationType memoryAllocationType,uint32_t memoryTypeIndex,DeviceMemory & deviceMemory,VkMemoryPropertyFlags memoryPropertyFlags,VkDeviceSize size,VkDeviceSize allocatedBufferSize)115 void BufferBlock::initWithoutVirtualBlock(Context *context,
116 Buffer &buffer,
117 MemoryAllocationType memoryAllocationType,
118 uint32_t memoryTypeIndex,
119 DeviceMemory &deviceMemory,
120 VkMemoryPropertyFlags memoryPropertyFlags,
121 VkDeviceSize size,
122 VkDeviceSize allocatedBufferSize)
123 {
124 RendererVk *renderer = context->getRenderer();
125 ASSERT(!mVirtualBlock.valid());
126 ASSERT(!mBuffer.valid());
127 ASSERT(!mDeviceMemory.valid());
128
129 mBuffer = std::move(buffer);
130 mDeviceMemory = std::move(deviceMemory);
131 mMemoryPropertyFlags = memoryPropertyFlags;
132 mSize = size;
133 mAllocatedBufferSize = allocatedBufferSize;
134 mMemoryAllocationType = memoryAllocationType;
135 mMemoryTypeIndex = memoryTypeIndex;
136 mMappedMemory = nullptr;
137 mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
138 }
139
map(const VkDevice device)140 VkResult BufferBlock::map(const VkDevice device)
141 {
142 ASSERT(mMappedMemory == nullptr);
143 return mDeviceMemory.map(device, 0, mSize, 0, &mMappedMemory);
144 }
145
unmap(const VkDevice device)146 void BufferBlock::unmap(const VkDevice device)
147 {
148 mDeviceMemory.unmap(device);
149 mMappedMemory = nullptr;
150 }
151
allocate(VkDeviceSize size,VkDeviceSize alignment,VmaVirtualAllocation * allocationOut,VkDeviceSize * offsetOut)152 VkResult BufferBlock::allocate(VkDeviceSize size,
153 VkDeviceSize alignment,
154 VmaVirtualAllocation *allocationOut,
155 VkDeviceSize *offsetOut)
156 {
157 std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
158 mCountRemainsEmpty = 0;
159 return mVirtualBlock.allocate(size, alignment, allocationOut, offsetOut);
160 }
161
free(VmaVirtualAllocation allocation,VkDeviceSize offset)162 void BufferBlock::free(VmaVirtualAllocation allocation, VkDeviceSize offset)
163 {
164 std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
165 mVirtualBlock.free(allocation, offset);
166 }
167
getAndIncrementEmptyCounter()168 int32_t BufferBlock::getAndIncrementEmptyCounter()
169 {
170 return ++mCountRemainsEmpty;
171 }
172
calculateStats(vma::StatInfo * pStatInfo) const173 void BufferBlock::calculateStats(vma::StatInfo *pStatInfo) const
174 {
175 std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
176 mVirtualBlock.calculateStats(pStatInfo);
177 }
178
179 // BufferSuballocation implementation.
map(Context * context)180 VkResult BufferSuballocation::map(Context *context)
181 {
182 return mBufferBlock->map(context->getDevice());
183 }
184
185 // SharedBufferSuballocationGarbage implementation.
destroyIfComplete(RendererVk * renderer)186 bool SharedBufferSuballocationGarbage::destroyIfComplete(RendererVk *renderer)
187 {
188 if (renderer->hasResourceUseFinished(mLifetime))
189 {
190 mBuffer.destroy(renderer->getDevice());
191 mSuballocation.destroy(renderer);
192 return true;
193 }
194 return false;
195 }
196
hasResourceUseSubmitted(RendererVk * renderer) const197 bool SharedBufferSuballocationGarbage::hasResourceUseSubmitted(RendererVk *renderer) const
198 {
199 return renderer->hasResourceUseSubmitted(mLifetime);
200 }
201 } // namespace vk
202 } // namespace rx
203