Added multiple command-buffers and syncronization commands to allow the system to render multiple frames at once.

This commit is contained in:
Rebekah 2024-07-15 13:23:44 -04:00
parent 7e429da9ae
commit cec2cb3ec9
Signed by: oneechanhax
GPG Key ID: 0074BF373B812798

View File

@ -89,13 +89,15 @@ class VulkanExampleApplication {
std::unique_ptr<vk::raii::RenderPass> vk_render_pass;
std::unique_ptr<vk::raii::Pipeline> vk_pipeline;
std::unique_ptr<vk::raii::CommandPool> vk_command_pool;
std::unique_ptr<vk::raii::CommandBuffers> vk_command_buffers;
std::unique_ptr<vk::raii::DescriptorSetLayout> vk_descriptor_set_layout;
std::unique_ptr<vk::raii::DescriptorPool> vk_descriptor_pool;
std::unique_ptr<vk::raii::DescriptorSets> vk_descriptor_sets;
std::unique_ptr<vk::raii::Fence> vk_fence_in_flight;
std::unique_ptr<vk::raii::Semaphore> vk_semephore_image_available;
std::unique_ptr<vk::raii::Semaphore> vk_semephore_render_finished;
uint current_frame_index = 0;
std::vector<vk::raii::CommandBuffer> vk_command_buffers;
std::vector<vk::raii::Fence> vk_fences_in_flight;
std::vector<vk::raii::Semaphore> vk_semephores_image_available;
std::vector<vk::raii::Semaphore> vk_semephores_render_finished;
struct VulkanDeviceQueriedInfo {
std::unique_ptr<vk::raii::SurfaceKHR> screen_surface;
@ -643,9 +645,9 @@ public:
const vk::CommandBufferAllocateInfo command_buffer_alloc_info {
.commandPool = **this->vk_command_pool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1
.commandBufferCount = MAX_FRAMES_IN_FLIGHT
};
this->vk_command_buffers = std::make_unique<vk::raii::CommandBuffers>(*this->vk_gpu, command_buffer_alloc_info);
this->vk_command_buffers = vk::raii::CommandBuffers(*this->vk_gpu, command_buffer_alloc_info);
}
{
// vertex
@ -671,9 +673,11 @@ public:
this->CopyBuffer(*index_buffer_staging.first, *this->vk_buffer_index.first, index_buffer_size);
}
{ // syncronizing vars
this->vk_semephore_image_available = std::make_unique<vk::raii::Semaphore>(*this->vk_gpu, vk::SemaphoreCreateInfo {});
this->vk_semephore_render_finished = std::make_unique<vk::raii::Semaphore>(*this->vk_gpu, vk::SemaphoreCreateInfo {});
this->vk_fence_in_flight = std::make_unique<vk::raii::Fence>(*this->vk_gpu, vk::FenceCreateInfo { .flags = vk::FenceCreateFlagBits::eSignaled });
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
this->vk_semephores_image_available.push_back(vk::raii::Semaphore(*this->vk_gpu, vk::SemaphoreCreateInfo {}));
this->vk_semephores_render_finished.push_back(vk::raii::Semaphore(*this->vk_gpu, vk::SemaphoreCreateInfo {}));
this->vk_fences_in_flight.push_back(vk::raii::Fence(*this->vk_gpu, vk::FenceCreateInfo { .flags = vk::FenceCreateFlagBits::eSignaled }));
}
}
} catch (const vk::SystemError& e) {
std::cout << "Received Vulkan-Specific Error during process init: " << e.what() << std::endl
@ -778,41 +782,40 @@ public:
std::cout << "Completed tests with: " << std::to_string(amount_of_frames_needed) << " frames!" << std::endl;
}
void DrawFrame() const {
const std::array<vk::Fence, 1> wait_fences = { *this->vk_fence_in_flight };
void DrawFrame() {
const std::array<vk::Fence, 1> wait_fences = { *this->vk_fences_in_flight[this->current_frame_index] };
const vk::Result fence_result = this->vk_gpu->waitForFences(wait_fences, vk::True, std::numeric_limits<std::uint64_t>::max());
if (fence_result != vk::Result::eSuccess)
throw std::runtime_error("failed to wait for frame fence!");
this->vk_gpu->resetFences(wait_fences);
const auto next_image = this->vk_swapchain->acquireNextImage(std::numeric_limits<std::uint64_t>::max(), *this->vk_semephore_image_available);
const auto next_image = this->vk_swapchain->acquireNextImage(std::numeric_limits<std::uint64_t>::max(), *this->vk_semephores_image_available[this->current_frame_index]);
if (next_image.first != vk::Result::eSuccess) {
if (next_image.first == vk::Result::eNotReady) // i think its best to just return...
return;
if (next_image.first != vk::Result::eSuboptimalKHR)
throw std::runtime_error("failed to aquire next image!: " + std::to_string((int)next_image.first)); // vk::Result::eTimeout and everything else throws!
}
this->vk_command_buffers->front().reset();
const auto& command_buffer = this->vk_command_buffers[this->current_frame_index];
command_buffer.reset();
this->RecordCommandBuffer(this->vk_command_buffers->front(), next_image.second);
this->RecordCommandBuffer(command_buffer, next_image.second);
const std::array<vk::Semaphore, 1> wait_semaphores = { *this->vk_semephore_image_available };
const std::array<vk::Semaphore, 1> wait_semaphores = { *this->vk_semephores_image_available[this->current_frame_index] };
constexpr auto wait_stages = vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput);
const std::array<vk::Semaphore, 1> signal_semaphores = { *this->vk_semephore_render_finished };
const std::vector<vk::CommandBuffer> command_buffers(this->vk_command_buffers->begin(), this->vk_command_buffers->end());
const std::array<vk::Semaphore, 1> signal_semaphores = { *this->vk_semephores_render_finished[this->current_frame_index] };
const vk::SubmitInfo submit_info {
.waitSemaphoreCount = wait_semaphores.size(),
.pWaitSemaphores = wait_semaphores.data(),
.pWaitDstStageMask = &wait_stages,
.commandBufferCount = static_cast<std::uint32_t>(command_buffers.size()),
.pCommandBuffers = command_buffers.data(),
.commandBufferCount = 1,
.pCommandBuffers = &*command_buffer,
.signalSemaphoreCount = signal_semaphores.size(),
.pSignalSemaphores = signal_semaphores.data()
};
const std::array<vk::SubmitInfo, 1> submit_queue = { submit_info };
this->vk_queue_graphics->submit(submit_queue, **this->vk_fence_in_flight);
this->vk_queue_graphics->submit(submit_queue, *this->vk_fences_in_flight[this->current_frame_index]);
const std::array<vk::SwapchainKHR, 1> swapchains = { *this->vk_swapchain };
const vk::PresentInfoKHR present_info {
@ -826,6 +829,8 @@ public:
const vk::Result present_result = this->vk_queue_present->presentKHR(present_info);
if (present_result != vk::Result::eSuccess)
throw std::runtime_error("failed to present image!");
this->current_frame_index = (this->current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
}
void RecordCommandBuffer(const vk::raii::CommandBuffer& command_buffer, std::uint32_t image_index) const {
@ -890,7 +895,7 @@ private:
.pfnUserCallback = &VulkanDebugCallback
};
#endif
static constexpr int MAX_FRAMES_IN_FLIGHT = 2;
static constexpr std::array<const char*, 1> required_vulkan_device_extensions = { vk::KHRSwapchainExtensionName };
static constexpr std::array<const char*, 1> required_vulkan_validation_layers = { "VK_LAYER_KHRONOS_validation" };
static constexpr vk::Format required_vulkan_default_format = vk::Format::eR8G8B8A8Unorm; // formats Preffered front to back. FIFO