• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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