192 lines
6.9 KiB
C++
192 lines
6.9 KiB
C++
#include <GLFW/glfw3.h>
|
|
|
|
#include "precomp.h"
|
|
#include "vulkan_engine/vulkan/graphics.h"
|
|
|
|
namespace veng {
|
|
|
|
void Graphics::CreateFramebuffers() {
|
|
swap_chain_framebuffers_.resize(swap_chain_image_views_.size());
|
|
|
|
for (std::uint32_t i = 0; i < swap_chain_image_views_.size(); i++) {
|
|
std::array<VkImageView, 2> attachments = {swap_chain_image_views_[i],
|
|
depth_texture_.image_view};
|
|
|
|
VkFramebufferCreateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
info.renderPass = render_pass_;
|
|
info.attachmentCount = attachments.size();
|
|
info.pAttachments = attachments.data();
|
|
info.width = extent_.width;
|
|
info.height = extent_.height;
|
|
info.layers = 1;
|
|
|
|
VkResult result = vkCreateFramebuffer(logical_device_, &info, nullptr,
|
|
&swap_chain_framebuffers_[i]);
|
|
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void Graphics::CreateCommandPool() {
|
|
QueueFamilyIndices indices = FindQueueFamilies(physical_device_);
|
|
VkCommandPoolCreateInfo pool_info = {};
|
|
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
pool_info.queueFamilyIndex = indices.graphics_family.value();
|
|
|
|
VkResult result =
|
|
vkCreateCommandPool(logical_device_, &pool_info, nullptr, &command_pool_);
|
|
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void Graphics::CreateCommandBuffer() {
|
|
VkCommandBufferAllocateInfo info = {};
|
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
info.commandPool = command_pool_;
|
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
info.commandBufferCount = 1;
|
|
|
|
for (Frame& frame : frames_) {
|
|
VkResult result =
|
|
vkAllocateCommandBuffers(logical_device_, &info, &frame.command_buffer);
|
|
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
void Graphics::BeginCommands() {
|
|
vkResetCommandBuffer(frames_[current_frame_].command_buffer, 0);
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
VkResult result = vkBeginCommandBuffer(
|
|
frames_[current_frame_].command_buffer, &begin_info);
|
|
if (result != VK_SUCCESS)
|
|
throw std::runtime_error("Failed to begin command buffer!");
|
|
|
|
std::array<VkClearValue, 2> clear_values;
|
|
clear_values[0].color = {{0.f, 0.f, 0.f, 1.f}};
|
|
clear_values[1].depthStencil = {1.f, 0};
|
|
|
|
VkRenderPassBeginInfo render_pass_begin_info = {};
|
|
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
render_pass_begin_info.renderPass = render_pass_;
|
|
render_pass_begin_info.framebuffer =
|
|
swap_chain_framebuffers_[current_image_index_];
|
|
render_pass_begin_info.renderArea.offset = {0, 0};
|
|
render_pass_begin_info.renderArea.extent = extent_;
|
|
render_pass_begin_info.clearValueCount = clear_values.size();
|
|
render_pass_begin_info.pClearValues = clear_values.data();
|
|
|
|
vkCmdBeginRenderPass(frames_[current_frame_].command_buffer,
|
|
&render_pass_begin_info,
|
|
VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(frames_[current_frame_].command_buffer,
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
pipeline_);
|
|
VkViewport viewport = GetViewport();
|
|
VkRect2D scissor = GetScissor();
|
|
|
|
vkCmdSetViewport(frames_[current_frame_].command_buffer, 0, 1, &viewport);
|
|
vkCmdSetScissor(frames_[current_frame_].command_buffer, 0, 1, &scissor);
|
|
}
|
|
|
|
void Graphics::EndCommands() {
|
|
vkCmdEndRenderPass(frames_[current_frame_].command_buffer);
|
|
VkResult result = vkEndCommandBuffer(frames_[current_frame_].command_buffer);
|
|
if (result != VK_SUCCESS)
|
|
throw std::runtime_error("Failed to record command buffer!");
|
|
}
|
|
|
|
void Graphics::CreateSignals() {
|
|
for (Frame& frame : frames_) {
|
|
VkSemaphoreCreateInfo semafore_info = {};
|
|
semafore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
|
|
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
|
&frame.image_available_signal) !=
|
|
VK_SUCCESS)
|
|
std::exit(EXIT_FAILURE);
|
|
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
|
&frame.render_finished_signal) !=
|
|
VK_SUCCESS)
|
|
std::exit(EXIT_FAILURE);
|
|
|
|
VkFenceCreateInfo fence_info = {};
|
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
|
|
if (vkCreateFence(logical_device_, &fence_info, nullptr,
|
|
&frame.still_rendering_fence) !=
|
|
VK_SUCCESS)
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
bool Graphics::BeginFrame() {
|
|
vkWaitForFences(logical_device_, 1,
|
|
&frames_[current_frame_].still_rendering_fence, VK_TRUE,
|
|
UINT64_MAX);
|
|
VkResult image_acquire_result = vkAcquireNextImageKHR(logical_device_, swap_chain_, UINT64_MAX,
|
|
frames_[current_frame_].image_available_signal,
|
|
VK_NULL_HANDLE, ¤t_image_index_);
|
|
|
|
if (image_acquire_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
|
RecreateSwapChain();
|
|
return false;
|
|
}
|
|
|
|
if (image_acquire_result != VK_SUCCESS &&
|
|
image_acquire_result != VK_SUBOPTIMAL_KHR)
|
|
throw std::runtime_error("Couldn't acquire render image!");
|
|
|
|
vkResetFences(logical_device_, 1,
|
|
&frames_[current_frame_].still_rendering_fence);
|
|
|
|
BeginCommands();
|
|
SetModelMatrix(glm::mat4(1.f));
|
|
|
|
return true;
|
|
}
|
|
|
|
void veng::Graphics::EndFrame() {
|
|
EndCommands();
|
|
VkSubmitInfo submit_info = {};
|
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
|
submit_info.waitSemaphoreCount = 1;
|
|
submit_info.pWaitSemaphores = &frames_[current_frame_].image_available_signal;
|
|
submit_info.pWaitDstStageMask = &wait_stage;
|
|
submit_info.commandBufferCount = 1;
|
|
submit_info.pCommandBuffers = &frames_[current_frame_].command_buffer;
|
|
submit_info.signalSemaphoreCount = 1;
|
|
submit_info.pSignalSemaphores =
|
|
&frames_[current_frame_].render_finished_signal;
|
|
|
|
VkResult submit_result =
|
|
vkQueueSubmit(graphics_queue_, 1, &submit_info,
|
|
frames_[current_frame_].still_rendering_fence);
|
|
if (submit_result != VK_SUCCESS)
|
|
throw std::runtime_error("failed to submit draw commands!");
|
|
|
|
VkPresentInfoKHR present_info = {};
|
|
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
present_info.waitSemaphoreCount = 1;
|
|
present_info.pWaitSemaphores =
|
|
&frames_[current_frame_].render_finished_signal;
|
|
present_info.swapchainCount = 1;
|
|
present_info.pSwapchains = &swap_chain_;
|
|
present_info.pImageIndices = ¤t_image_index_;
|
|
|
|
VkResult result = vkQueuePresentKHR(present_queue_, &present_info);
|
|
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
|
RecreateSwapChain();
|
|
else if (result != VK_SUCCESS)
|
|
throw std::runtime_error("Failed to present swap chain image!");
|
|
|
|
current_frame_ = (current_frame_++) % MAX_BUFFERED_FRAMES;
|
|
}
|
|
|
|
} // namespace veng
|