VapourSynth-llvmexpr
Loading...
Searching...
No Matches
VulkanMemory.cpp
Go to the documentation of this file.
1
19
20#include "VulkanMemory.hpp"
21#include "VulkanContext.hpp"
22
23#include <cstring>
24#include <stdexcept>
25#include <volk.h>
26
27// NOLINTBEGIN(cppcoreguidelines-macro-usage,cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
28
29#define VMA_IMPLEMENTATION
30#define VMA_STATIC_VULKAN_FUNCTIONS 0
31#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
32
33// NOLINTEND(cppcoreguidelines-macro-usage,cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
34
35#include <vk_mem_alloc.h>
36
37namespace vkexpr {
38
40 VmaVulkanFunctions vulkan_functions = {};
41 vulkan_functions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
42 vulkan_functions.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
43
44 VmaAllocatorCreateInfo allocator_info = {};
45 allocator_info.vulkanApiVersion = VK_API_VERSION_1_3;
46 allocator_info.physicalDevice = *context.getPhysicalDevice();
47 allocator_info.device = *context.getDevice();
48 allocator_info.instance = *context.getInstanceRef();
49 allocator_info.pVulkanFunctions = &vulkan_functions;
50
51 if (vmaCreateAllocator(&allocator_info, &allocator) != VK_SUCCESS) {
52 throw std::runtime_error("Failed to create VMA allocator");
53 }
54
55 vk::CommandPoolCreateInfo pool_info(
56 vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
57 context.getQueueFamilyIndex());
58 transfer_pool = vk::raii::CommandPool(context.getDevice(), pool_info);
59
60 vk::CommandBufferAllocateInfo cmd_info(*transfer_pool,
61 vk::CommandBufferLevel::ePrimary, 1);
62 auto cmd_buffers = vk::raii::CommandBuffers(context.getDevice(), cmd_info);
63 transfer_cmd = std::move(cmd_buffers[0]);
64
65 vk::FenceCreateInfo fence_info;
66 transfer_fence = vk::raii::Fence(context.getDevice(), fence_info);
67}
68
70 if (allocator != VK_NULL_HANDLE) {
71 vmaDestroyAllocator(allocator);
72 }
73}
74
76 VkBufferUsageFlags usage) {
77 VkBufferCreateInfo buffer_info = {};
78 buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
79 buffer_info.size = size;
80 buffer_info.usage = usage;
81 buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
82
83 VmaAllocationCreateInfo alloc_info = {};
84 alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
85
86 VkBuffer buffer = VK_NULL_HANDLE;
87 VmaAllocation allocation = VK_NULL_HANDLE;
88 VmaAllocationInfo allocation_info = {};
89
90 if (vmaCreateBuffer(allocator, &buffer_info, &alloc_info, &buffer,
91 &allocation, &allocation_info) != VK_SUCCESS) {
92 throw std::runtime_error("Failed to create GPU buffer");
93 }
94
95 return {buffer, allocation, allocation_info, size};
96}
97
99 bool for_upload) {
100 VkBufferCreateInfo buffer_info = {};
101 buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
102 buffer_info.size = size;
103 buffer_info.usage = for_upload ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT
104 : VK_BUFFER_USAGE_TRANSFER_DST_BIT;
105 buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
106
107 VmaAllocationCreateInfo alloc_info = {};
108 alloc_info.usage = VMA_MEMORY_USAGE_AUTO;
109 alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
110 VMA_ALLOCATION_CREATE_MAPPED_BIT;
111 if (!for_upload) {
112 alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT |
113 VMA_ALLOCATION_CREATE_MAPPED_BIT;
114 }
115
116 VkBuffer buffer = VK_NULL_HANDLE;
117 VmaAllocation allocation = VK_NULL_HANDLE;
118 VmaAllocationInfo allocation_info = {};
119
120 if (vmaCreateBuffer(allocator, &buffer_info, &alloc_info, &buffer,
121 &allocation, &allocation_info) != VK_SUCCESS) {
122 throw std::runtime_error("Failed to create staging buffer");
123 }
124
125 return {buffer, allocation, allocation_info, size};
126}
127
129 if (buffer.isValid()) {
130 vmaDestroyBuffer(allocator, buffer.buffer, buffer.allocation);
131 buffer.buffer = VK_NULL_HANDLE;
132 buffer.allocation = VK_NULL_HANDLE;
133 buffer.size = 0;
134 }
135}
136
137void VulkanMemory::uploadToBuffer(VulkanBuffer& gpu_buffer, const void* data,
138 VkDeviceSize size, VkDeviceSize offset) {
139 auto staging = createStagingBuffer(size, true);
140
141 std::memcpy(staging.getMappedData(), data, size);
142
143 vk::CommandBufferBeginInfo begin_info(
144 vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
145 transfer_cmd.begin(begin_info);
146
147 vk::BufferCopy copy_region(0, offset, size);
148 transfer_cmd.copyBuffer(staging.buffer, gpu_buffer.buffer, copy_region);
149
150 transfer_cmd.end();
151
152 vk::SubmitInfo submit_info;
153 submit_info.setCommandBuffers(*transfer_cmd);
154 context.submit(submit_info, *transfer_fence);
155
156 auto result =
157 context.getDevice().waitForFences(*transfer_fence, VK_TRUE, UINT64_MAX);
158 if (result != vk::Result::eSuccess) {
159 throw std::runtime_error("Failed to wait for upload fence");
160 }
161 context.getDevice().resetFences(*transfer_fence);
162
163 destroyBuffer(staging);
164}
165
167 VkDeviceSize size, VkDeviceSize offset) {
168 auto staging = createStagingBuffer(size, false);
169
170 vk::CommandBufferBeginInfo begin_info(
171 vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
172 transfer_cmd.begin(begin_info);
173
174 vk::BufferCopy copy_region(offset, 0, size);
175 transfer_cmd.copyBuffer(gpu_buffer.buffer, staging.buffer, copy_region);
176
177 transfer_cmd.end();
178
179 vk::SubmitInfo submit_info;
180 submit_info.setCommandBuffers(*transfer_cmd);
181 context.submit(submit_info, *transfer_fence);
182
183 auto result =
184 context.getDevice().waitForFences(*transfer_fence, VK_TRUE, UINT64_MAX);
185 if (result != vk::Result::eSuccess) {
186 throw std::runtime_error("Failed to wait for download fence");
187 }
188 context.getDevice().resetFences(*transfer_fence);
189
190 std::memcpy(data, staging.getMappedData(), size);
191
192 destroyBuffer(staging);
193}
194
196 VkDeviceSize size) {
197 vk::CommandBufferBeginInfo begin_info(
198 vk::CommandBufferUsageFlagBits::eOneTimeSubmit);
199 transfer_cmd.begin(begin_info);
200
201 vk::BufferCopy copy_region(0, 0, size);
202 transfer_cmd.copyBuffer(src.buffer, dst.buffer, copy_region);
203
204 transfer_cmd.end();
205
206 vk::SubmitInfo submit_info;
207 submit_info.setCommandBuffers(*transfer_cmd);
208 context.submit(submit_info, *transfer_fence);
209
210 auto result =
211 context.getDevice().waitForFences(*transfer_fence, VK_TRUE, UINT64_MAX);
212 if (result != vk::Result::eSuccess) {
213 throw std::runtime_error("Failed to wait for copy fence");
214 }
215 context.getDevice().resetFences(*transfer_fence);
216}
217
218void VulkanMemory::flushBuffer(const VulkanBuffer& buffer, VkDeviceSize size,
219 VkDeviceSize offset) const {
220 if (allocator == VK_NULL_HANDLE || buffer.allocation == VK_NULL_HANDLE ||
221 buffer.getMappedData() == nullptr || size == 0) {
222 return;
223 }
224 (void)vmaFlushAllocation(allocator, buffer.allocation, offset, size);
225}
226
228 VkDeviceSize size,
229 VkDeviceSize offset) const {
230 if (allocator == VK_NULL_HANDLE || buffer.allocation == VK_NULL_HANDLE ||
231 buffer.getMappedData() == nullptr || size == 0) {
232 return;
233 }
234 (void)vmaInvalidateAllocation(allocator, buffer.allocation, offset, size);
235}
236
237} // namespace vkexpr
VulkanMemory(VulkanContext &ctx)
VulkanBuffer createStagingBuffer(VkDeviceSize size, bool for_upload=true)
VulkanBuffer createGPUBuffer(VkDeviceSize size, VkBufferUsageFlags usage=VK_BUFFER_USAGE_STORAGE_BUFFER_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT|VK_BUFFER_USAGE_TRANSFER_SRC_BIT)
void destroyBuffer(VulkanBuffer &buffer)
void copyBuffer(VulkanBuffer &src, VulkanBuffer &dst, VkDeviceSize size)
void uploadToBuffer(VulkanBuffer &gpu_buffer, const void *data, VkDeviceSize size, VkDeviceSize offset=0)
void flushBuffer(const VulkanBuffer &buffer, VkDeviceSize size, VkDeviceSize offset=0) const
void downloadFromBuffer(VulkanBuffer &gpu_buffer, void *data, VkDeviceSize size, VkDeviceSize offset=0)
void invalidateBuffer(const VulkanBuffer &buffer, VkDeviceSize size, VkDeviceSize offset=0) const
VmaAllocation allocation
void * getMappedData() const