#include #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 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 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