coral_renderer.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #include "coral_renderer.h"
  2. // STD
  3. #include <array>
  4. #include <stdexcept>
  5. #include "vk_initializers.h"
  6. using namespace coral_3d;
  7. coral_renderer::coral_renderer(coral_window& window, coral_device& device)
  8. : window_{window}
  9. , device_{device}
  10. {
  11. recreate_swapchain();
  12. create_command_buffers();
  13. }
  14. coral_renderer::~coral_renderer()
  15. {
  16. free_command_buffers();
  17. }
  18. VkCommandBuffer coral_renderer::begin_frame()
  19. {
  20. assert(!is_frame_started_ && "ERROR! coral_renderer::begin_frame() >> Can't call begin frame while already in progress!");
  21. auto result = swapchain_->aqcuire_next_image(&current_image_index_);
  22. // Window has been resized
  23. if (result == VK_ERROR_OUT_OF_DATE_KHR)
  24. {
  25. recreate_swapchain();
  26. return nullptr;
  27. }
  28. if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
  29. throw std::runtime_error("ERROR! coral_renderer::begin_frame() >> "
  30. "Failed to acquire swapchain image!");
  31. is_frame_started_ = true;
  32. auto command_buffer{ get_current_command_buffer() };
  33. VkCommandBufferBeginInfo begin_info{};
  34. begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  35. if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS)
  36. throw std::runtime_error("ERROR! coral_renderer::begin_frame() >> Failed to begin recording command buffer!");
  37. return command_buffer;
  38. }
  39. void coral_renderer::end_frame()
  40. {
  41. assert(is_frame_started_ && "ERROR! coral_renderer::end_frame() >> Can't call end_frame() if frame is not in progress!");
  42. auto command_buffer{ get_current_command_buffer() };
  43. if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
  44. throw std::runtime_error("ERROR! coral_renderer::end_frame() >> Failed to record command buffer!");
  45. auto result = swapchain_->submit_command_buffer(&command_buffer, &current_image_index_);
  46. if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || window_.was_window_resized())
  47. {
  48. window_.reset_window_resized();
  49. recreate_swapchain();
  50. }
  51. else if (result != VK_SUCCESS)
  52. throw std::runtime_error("ERROR! coral_renderer::end_frame() >> Failed to present swapchain image!");
  53. is_frame_started_ = false;
  54. current_frame_index_ = (current_frame_index_ + 1) % coral_swapchain::MAX_FRAMES_IN_FLIGHT;
  55. }
  56. void coral_renderer::begin_swapchain_render_pass(VkCommandBuffer command_buffer)
  57. {
  58. assert(is_frame_started_ && "ERROR! first_app::begin_swapchain_render_pass() >> Can't call begin_swapchain_render_pass() if frame is not in progress!");
  59. assert(command_buffer == get_current_command_buffer() &&
  60. "ERROR! first_app::begin_swapchain_render_pass() >> Can't begin render pass on a buffer from a different frame");
  61. VkRenderPassBeginInfo render_pass_info{};
  62. render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  63. render_pass_info.renderPass = swapchain_->get_render_pass();
  64. render_pass_info.framebuffer = swapchain_->get_frame_buffers(current_image_index_);
  65. render_pass_info.renderArea.offset = { 0, 0 };
  66. render_pass_info.renderArea.extent = swapchain_->get_swapchain_extent();
  67. std::array<VkClearValue, 2> clear_values{};
  68. clear_values[0].color = { {0.0078125f, 0.0078125f, 0.0078125f, 1.0f} };
  69. clear_values[1].depthStencil = { 1.0f, 0 };
  70. render_pass_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
  71. render_pass_info.pClearValues = clear_values.data();
  72. vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
  73. VkViewport viewport{};
  74. viewport.x = 0.0f;
  75. viewport.y = 0.0f;
  76. viewport.width = static_cast<float>(swapchain_->get_swapchain_extent().width);
  77. viewport.height = static_cast<float>(swapchain_->get_swapchain_extent().height);
  78. viewport.minDepth = 0.0f;
  79. viewport.maxDepth = 1.0f;
  80. VkRect2D scissor{ {0, 0}, swapchain_->get_swapchain_extent() };
  81. vkCmdSetViewport(command_buffer, 0, 1, &viewport);
  82. vkCmdSetScissor(command_buffer, 0, 1, &scissor);
  83. }
  84. void coral_renderer::end_swapchain_render_pass(VkCommandBuffer command_buffer)
  85. {
  86. assert(is_frame_started_ && "ERROR! coral_renderer::end_swapchain_render_pass() >> Can't call end_swapchain_render_pass() if frame is not in progress!");
  87. assert(command_buffer == get_current_command_buffer() &&
  88. "ERROR! coral_renderer::end_swapchain_render_pass() >> Can't end render pass on a buffer from a different frame");
  89. vkCmdEndRenderPass(command_buffer);
  90. }
  91. void coral_renderer::create_command_buffers()
  92. {
  93. command_buffers_.resize(coral_swapchain::MAX_FRAMES_IN_FLIGHT);
  94. VkCommandBufferAllocateInfo alloc_info{ vkinit::command_buffer_ai(device_.get_command_pool(), static_cast<uint32_t>(command_buffers_.size())) };
  95. if (vkAllocateCommandBuffers(device_.device(), &alloc_info, command_buffers_.data()) != VK_SUCCESS)
  96. throw std::runtime_error("ERROR! coral_renderer::create_command_buffers() >> Failed to allocate command buffers!");
  97. }
  98. void coral_renderer::free_command_buffers()
  99. {
  100. vkFreeCommandBuffers(
  101. device_.device(),
  102. device_.get_command_pool(),
  103. static_cast<uint32_t>(command_buffers_.size()),
  104. command_buffers_.data());
  105. command_buffers_.clear();
  106. }
  107. void coral_renderer::recreate_swapchain()
  108. {
  109. auto extent{ window_.get_extent() };
  110. // Idle when minimized
  111. while (extent.width == 0 || extent.height == 0)
  112. {
  113. extent = window_.get_extent();
  114. glfwWaitEvents();
  115. }
  116. vkDeviceWaitIdle(device_.device());
  117. if (swapchain_ == nullptr)
  118. swapchain_ = std::make_unique<coral_swapchain>(device_, extent);
  119. else
  120. {
  121. std::shared_ptr<coral_swapchain> old_swapchain { std::move(swapchain_) };
  122. swapchain_ = std::make_unique<coral_swapchain>(device_, extent, old_swapchain);
  123. if (!old_swapchain->compare_swap_formats(*swapchain_))
  124. throw std::runtime_error("ERROR! coral_renderer::recreate_swapchain() >> Swapchain image or depth format has changed!");
  125. }
  126. }