Implement staging buffer.
This commit is contained in:
@@ -121,6 +121,7 @@ void Context::initialize(const ContextSettings& settings) {
|
||||
create_surface(settings);
|
||||
choose_physical_device(settings);
|
||||
create_device(settings);
|
||||
create_internal_objects();
|
||||
}
|
||||
|
||||
void Context::shutdown() {
|
||||
@@ -132,6 +133,9 @@ void Context::shutdown() {
|
||||
for(auto& callback: m_context_destruction_callbacks)
|
||||
callback();
|
||||
|
||||
destroy_fence(m_transfer_fence);
|
||||
destroy_command_pool(m_transfer_command_pool);
|
||||
|
||||
destroy_device(m_device);
|
||||
destroy_surface(m_surface);
|
||||
destroy_debug_messenger(m_debug_messenger);
|
||||
@@ -334,6 +338,68 @@ std::tuple<VkBuffer, VkDeviceMemory> Context::create_buffer(VkDeviceSize size, V
|
||||
return { buffer, memory };
|
||||
}
|
||||
|
||||
void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size) {
|
||||
VkCommandBufferAllocateInfo alloc_info {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = m_transfer_command_pool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
VkCommandBuffer command_buffer;
|
||||
vkAllocateCommandBuffers(m_device, &alloc_info, &command_buffer);
|
||||
auto const command_buffer_guard = make_guard([this, command_buffer]() {
|
||||
vkFreeCommandBuffers(m_device, m_transfer_command_pool, 1, &command_buffer);
|
||||
});
|
||||
|
||||
VkCommandBufferBeginInfo begin_info {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
vkBeginCommandBuffer(command_buffer, &begin_info);
|
||||
|
||||
VkBufferCopy region {
|
||||
.srcOffset = 0,
|
||||
.dstOffset = 0,
|
||||
.size = size,
|
||||
};
|
||||
vkCmdCopyBuffer(command_buffer, src, dst, 1, ®ion);
|
||||
|
||||
VkBufferMemoryBarrier buffer_barrier {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||
.srcQueueFamilyIndex = queue_family(VK_QUEUE_TRANSFER_BIT),
|
||||
.dstQueueFamilyIndex = dst_queue_family,
|
||||
.buffer = dst,
|
||||
.offset = 0,
|
||||
.size = size,
|
||||
};
|
||||
vkCmdPipelineBarrier(
|
||||
command_buffer,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
0,
|
||||
0, nullptr,
|
||||
1, &buffer_barrier,
|
||||
0, nullptr
|
||||
);
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
VkSubmitInfo submit_info {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &command_buffer,
|
||||
};
|
||||
vkQueueSubmit(
|
||||
queue(m_transfer_queue_index),
|
||||
1, &submit_info,
|
||||
m_transfer_fence
|
||||
);
|
||||
vkWaitForFences(m_device, 1, &m_transfer_fence, VK_TRUE, UINT64_MAX);
|
||||
}
|
||||
|
||||
|
||||
void Context::destroy_instance(VkInstance& instance) {
|
||||
if(instance == nullptr)
|
||||
@@ -599,7 +665,8 @@ std::optional<VkPhysicalDeviceProperties> Context::select_physical_device(
|
||||
VkPhysicalDeviceProperties device_properties;
|
||||
vkGetPhysicalDeviceProperties(physical_device, &device_properties);
|
||||
|
||||
m_queue_families.assign(settings.queues().size(), INVALID_QUEUE_FAMILY);
|
||||
m_transfer_queue_index = settings.queues().size();
|
||||
m_queue_families.assign(settings.queues().size() + 1, INVALID_QUEUE_FAMILY);
|
||||
m_presentation_queue_family = INVALID_QUEUE_FAMILY;
|
||||
|
||||
auto const queue_families = this->queue_families(physical_device);
|
||||
@@ -628,6 +695,10 @@ std::optional<VkPhysicalDeviceProperties> Context::select_physical_device(
|
||||
m_queue_families[index] = queue_family_index;
|
||||
}
|
||||
|
||||
if(m_queue_families[m_transfer_queue_index] == INVALID_QUEUE_FAMILY
|
||||
&& queue_family.queueFlags == VK_QUEUE_TRANSFER_BIT)
|
||||
m_queue_families[m_transfer_queue_index] = queue_family_index;
|
||||
|
||||
queue_family_index += 1;
|
||||
}
|
||||
|
||||
@@ -734,6 +805,28 @@ void Context::create_device(const ContextSettings& settings) {
|
||||
vkGetDeviceQueue(m_device, m_presentation_queue_family, 0, &m_presentation_queue);
|
||||
}
|
||||
|
||||
void Context::create_internal_objects() {
|
||||
VkCommandPoolCreateInfo pool_info {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = 0,
|
||||
.queueFamilyIndex = queue_family(m_transfer_queue_index),
|
||||
};
|
||||
if(vkCreateCommandPool(
|
||||
m_device,
|
||||
&pool_info,
|
||||
nullptr,
|
||||
&m_transfer_command_pool
|
||||
) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create command pool");
|
||||
}
|
||||
|
||||
VkFenceCreateInfo fence_info {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
};
|
||||
if(vkCreateFence(m_device, &fence_info, nullptr, &m_transfer_fence) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create fence");
|
||||
}
|
||||
|
||||
void Context::initialize_extension_functions() {
|
||||
uint32_t errors_count = 0;
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
VkDeviceMemory allocate_memory(VkDeviceSize size, uint32_t type_filter, VkMemoryPropertyFlags properties);
|
||||
|
||||
std::tuple<VkBuffer, VkDeviceMemory> create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_properties);
|
||||
void copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size);
|
||||
|
||||
|
||||
void destroy_instance(VkInstance& instance);
|
||||
@@ -142,6 +143,7 @@ private:
|
||||
const ContextSettings& settings
|
||||
);
|
||||
void create_device(const ContextSettings& settings);
|
||||
void create_internal_objects();
|
||||
|
||||
void initialize_extension_functions();
|
||||
|
||||
@@ -172,6 +174,10 @@ private:
|
||||
VkSurfaceFormatKHR m_surface_format;
|
||||
VkPresentModeKHR m_present_mode;
|
||||
|
||||
uint32_t m_transfer_queue_index = UINT32_MAX;
|
||||
VkCommandPool m_transfer_command_pool = VK_NULL_HANDLE;
|
||||
VkFence m_transfer_fence = VK_NULL_HANDLE;
|
||||
|
||||
std::vector<ContextDestructionCallback> m_context_destruction_callbacks;
|
||||
};
|
||||
|
||||
|
||||
@@ -438,17 +438,30 @@ void VulkanTutorial::create_vertex_buffer() {
|
||||
|
||||
VkDeviceSize buffer_size = sizeof(vertices[0]) * vertices.size();
|
||||
|
||||
std::tie(m_vertex_buffer, m_vertex_buffer_memory) = m_context.create_buffer(
|
||||
VkBuffer tmp_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory tmp_buffer_memory = VK_NULL_HANDLE;
|
||||
std::tie(tmp_buffer, tmp_buffer_memory) = m_context.create_buffer(
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
);
|
||||
auto const tmp_buffer_guard = make_guard([&] {
|
||||
m_context.free_memory(tmp_buffer_memory);
|
||||
m_context.destroy_buffer(tmp_buffer);
|
||||
});
|
||||
|
||||
std::tie(m_vertex_buffer, m_vertex_buffer_memory) = m_context.create_buffer(
|
||||
buffer_size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
||||
);
|
||||
|
||||
void* buffer = nullptr;
|
||||
vkMapMemory(
|
||||
m_context.device(),
|
||||
m_vertex_buffer_memory,
|
||||
tmp_buffer_memory,
|
||||
0,
|
||||
buffer_size,
|
||||
0,
|
||||
@@ -459,7 +472,14 @@ void VulkanTutorial::create_vertex_buffer() {
|
||||
|
||||
vkUnmapMemory(
|
||||
m_context.device(),
|
||||
m_vertex_buffer_memory
|
||||
tmp_buffer_memory
|
||||
);
|
||||
|
||||
m_context.copy_buffer(
|
||||
m_vertex_buffer,
|
||||
tmp_buffer,
|
||||
m_context.queue_family(GRAPHIC_QUEUE),
|
||||
buffer_size
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user