-
Notifications
You must be signed in to change notification settings - Fork 437
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Memory (sub)allocation API 2.0 #2316
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
marc0246
added a commit
to marc0246/vulkano
that referenced
this pull request
Sep 7, 2023
This was referenced Sep 7, 2023
hakolao
pushed a commit
to hakolao/vulkano
that referenced
this pull request
Feb 20, 2024
* Excommunicate `PoolAllocator` * Switch to manual deallocation * Move `ResourceMemory` away from the `suballocator` module * Remove `SuballocatorError::BlockSizeExceeded` * Fix examples * Fix atom size * Address safety TODOs * Nice English you got there bro
hakolao
pushed a commit
to hakolao/vulkano
that referenced
this pull request
Feb 20, 2024
hakolao
pushed a commit
to hakolao/vulkano
that referenced
this pull request
Feb 20, 2024
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This fixes most of the horrible design decisions from #1997. After I fix the ones left over, I think there will be no more reason for breaking changes in it pretty much ever. Though I've been wrong before, so I'd appreciate feedback, if there's a way it can be made more generic.
The (many) problems
A relatively highly-requested feature, which is quite obvious when you think about it, is being able to suballocate existing buffers (as opposed to
SubbufferAllocator
which allocates its own buffer(s)). This is currently not possible becauseMemoryAlloc
is tied to (sub)allocations ofDeviceMemory
: it holds a reference to the suballocator it came from and the suballocators in turn only accept aMemoryAlloc
as a region to suballocate (DeviceMemory
being the root of all such hierarchies).It would have been possible to remedy this while keeping the reference to the suballocator in its returned suballocation, however there are other problems with this:
Suballocator
trait to be implemented onArc
s (so that the returned suballocation can hold this reference):Arc
), so if the user wanted to implement an allocator trait it would require double-boxing of the allocator that's put in the allocation, on top of dynamic dispatch. This is less so a consideration for suballocators since there's only so many algorithms and no reason for the user to implement one, but it's a consideration for allocators in general.Sync
(they still are at this point, read "most of the horrible design decisions").'static
.MemoryAllocator
, excludes many possibilities:I guess this and some other reasons that I forgot is why allocation APIs have an explicit
deallocate
method which fixes all of that. One only needs to implement the trait for their type, and the library can blanket impl it for all references and other pointer types and standard library types. Whether the allocator is internally or externall synchronized is also up to the implementor, because the allocations are separate from the allocator. etc. I don't know why none of our allocator traits have this method, but I can only imagine the original reasoning was that this method is unsafe. Alas, I highly doubt this is a good enough justification.Solutions
So now
Suballocator
has an unsafedeallocate
method, and can be used to suballocate absolutely anything: aDeviceMemory
block, or suballocations thereof. These can then be bound to buffers which can also be suballocated into subbuffers, or you can suballocate subbuffers. If you really wanted to you could even suballocate regions of descriptors in descriptor arrays, or whatever else you might encounter in Vulkan, such as an array ofu32
s inside a buffer.MemoryAllocator
also has an unsafedeallocate
method, to allowMemoryAlloc
s to be freed directly to it rather than to a suballocator as described above. The issue is that the specific block theMemoryAlloc
belongs to must be somehow known. The solution, while unsafe, is much more elegant than the boxing and dynamic dispatch that would be the alternative IMO: an opaqueAllocationHandle
that can represent any piece of data used to identify the allocation, most likely a pointer or index.Suballocation
also has such a handle to identify the suballocation within the suballocator. These handles can also safely beSend + Sync
regardless of how the (sub)allocator is synchronized, because again, (sub)allocators and their (sub)allocations are separate from each other. So the (sub)allocator can be synchronized any which way.PoolAllocator
Is bye bye. No one liked it anyway! The only thing it gave us is special-casing everywhere because it has an upper bound on the suballocation size unlike everything else, and then there's the whole headache of how to specify said block size. Or how
GenericMemoryAllocatorCreateInfo::allocation_type
existed solely because of it. That's not to say pool allocation isn't useful, it absolutely is, just that this being a suballocator was frankly never meant to be. The user can create a pool themself with ease, such as can be seen in the implementation ofGenericMemoryAllocator
.Changelog: