Browse Source

Implement staging buffer.

master
Draklaw 4 years ago
parent
commit
2c93e5e1b3
  1. 95
      src/Vulkan/Context.cpp
  2. 6
      src/Vulkan/Context.h
  3. 28
      src/VulkanTutorial.cpp

95
src/Vulkan/Context.cpp

@ -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, &region);
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;

6
src/Vulkan/Context.h

@ -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;
};

28
src/VulkanTutorial.cpp

@ -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
);
}

Loading…
Cancel
Save