first_app.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include "first_app.h"
  2. // STD
  3. #include <stdexcept>
  4. #include <array>
  5. #include "vk_initializers.h"
  6. using namespace coral_3d;
  7. first_app::first_app()
  8. {
  9. load_gameobjects();
  10. create_pipeline_layout();
  11. recreate_swapchain();
  12. create_command_buffers();
  13. }
  14. first_app::~first_app()
  15. {
  16. vkDestroyPipelineLayout(device_.device(), pipeline_layout_, nullptr);
  17. }
  18. void first_app::run()
  19. {
  20. while (!window_.should_close())
  21. {
  22. glfwPollEvents();
  23. draw_frame();
  24. }
  25. vkDeviceWaitIdle(device_.device());
  26. }
  27. void first_app::load_gameobjects()
  28. {
  29. std::vector<Vertex> vertices
  30. {
  31. {{0.0f, -0.5f, 0.0f}, { 1.0f, 0.0f, 0.0f }},
  32. {{-0.5f, 0.5f, 0.0f}, { 0.0f, 1.0f, 0.0f }},
  33. {{0.5f, 0.5f, 0.0f}, { 0.0f, 0.0f, 1.0f }},
  34. };
  35. auto mesh{ std::make_shared<coral_mesh>(device_, vertices) };
  36. auto triangle = coral_gameobject::create_gameobject();
  37. triangle.mesh_ = mesh;
  38. triangle.color_ = { 0.1f, 0.8f, 0.1f };
  39. triangle.transform_.translation.x = -.2f;
  40. gameobjects_.emplace_back(std::move(triangle));
  41. }
  42. void first_app::create_pipeline_layout()
  43. {
  44. VkPushConstantRange push_constant_range{};
  45. push_constant_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
  46. push_constant_range.offset = 0;
  47. push_constant_range.size = sizeof(PushConstant);
  48. VkPipelineLayoutCreateInfo layout_info{ vkinit::pipeline_layout_ci() };
  49. layout_info.pushConstantRangeCount = 1;
  50. layout_info.pPushConstantRanges = &push_constant_range;
  51. if (vkCreatePipelineLayout(device_.device(), &layout_info, nullptr, &pipeline_layout_) != VK_SUCCESS)
  52. throw std::runtime_error("ERROR! first_app::create_pipeline_layout() >> Failed to create pipeline layout!");
  53. }
  54. void first_app::create_pipeline()
  55. {
  56. auto pipeline_config{ coral_pipeline::default_pipeline_config_info(swapchain_->width(), swapchain_->height()) };
  57. pipeline_config.render_pass = swapchain_->get_render_pass();
  58. pipeline_config.pipeline_layout = pipeline_layout_;
  59. pipeline_ = std::make_unique<coral_pipeline>(
  60. device_,
  61. // "shaders/PosNormCol.vert.spv",
  62. // "shaders/PosNormCol.frag.spv",
  63. "shaders/simple_shader.vert.spv",
  64. "shaders/simple_shader.frag.spv",
  65. pipeline_config
  66. );
  67. }
  68. void first_app::create_command_buffers()
  69. {
  70. command_buffers_.resize(swapchain_->image_count());
  71. VkCommandBufferAllocateInfo alloc_info{ vkinit::command_buffer_ai(device_.get_command_pool(), static_cast<uint32_t>(command_buffers_.size())) };
  72. if (vkAllocateCommandBuffers(device_.device(), &alloc_info, command_buffers_.data()) != VK_SUCCESS)
  73. throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to allocate command buffers!");
  74. }
  75. void first_app::free_command_buffers()
  76. {
  77. vkFreeCommandBuffers(
  78. device_.device(),
  79. device_.get_command_pool(),
  80. static_cast<uint32_t>(command_buffers_.size()),
  81. command_buffers_.data());
  82. command_buffers_.clear();
  83. }
  84. void first_app::draw_frame()
  85. {
  86. uint32_t image_index;
  87. auto result = swapchain_->aqcuire_next_image(&image_index);
  88. // Window has been resized
  89. if (result == VK_ERROR_OUT_OF_DATE_KHR)
  90. {
  91. recreate_swapchain();
  92. return;
  93. }
  94. if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
  95. throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to aquire swapchain image!");
  96. record_command_buffer(image_index);
  97. result = swapchain_->submit_command_buffer(&command_buffers_[image_index], &image_index);
  98. if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || window_.was_window_resized())
  99. {
  100. window_.reset_window_resized();
  101. recreate_swapchain();
  102. return;
  103. }
  104. if(result != VK_SUCCESS)
  105. throw std::runtime_error("ERROR! first_app::draw_frame() >> Failed to present swapchain image!");
  106. }
  107. void first_app::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. swapchain_ = std::make_unique<coral_swapchain>(device_, extent, std::move(swapchain_));
  122. if (swapchain_->image_count() != command_buffers_.size())
  123. {
  124. free_command_buffers();
  125. create_command_buffers();
  126. }
  127. }
  128. create_pipeline();
  129. }
  130. void first_app::record_command_buffer(int image_index)
  131. {
  132. VkCommandBufferBeginInfo begin_info{};
  133. begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  134. if (vkBeginCommandBuffer(command_buffers_[image_index], &begin_info) != VK_SUCCESS)
  135. throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to begin recording command buffer!");
  136. VkRenderPassBeginInfo render_pass_info{};
  137. render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  138. render_pass_info.renderPass = swapchain_->get_render_pass();
  139. render_pass_info.framebuffer = swapchain_->get_frame_buffers(image_index);
  140. render_pass_info.renderArea.offset = { 0, 0 };
  141. render_pass_info.renderArea.extent = swapchain_->get_swapchain_extent();
  142. std::array<VkClearValue, 2> clear_values{};
  143. clear_values[0].color = { 0.1f, 0.1f, 0.1f, 1.0f };
  144. clear_values[1].depthStencil = { 1.0f, 0 };
  145. render_pass_info.clearValueCount = static_cast<uint32_t>(clear_values.size());
  146. render_pass_info.pClearValues = clear_values.data();
  147. vkCmdBeginRenderPass(command_buffers_[image_index], &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
  148. render_gameobjects(command_buffers_[image_index]);
  149. vkCmdEndRenderPass(command_buffers_[image_index]);
  150. if (vkEndCommandBuffer(command_buffers_[image_index]) != VK_SUCCESS)
  151. throw std::runtime_error("ERROR! first_app::create_command_buffers() >> Failed to record command buffer!");
  152. }
  153. void coral_3d::first_app::render_gameobjects(VkCommandBuffer command_buffer)
  154. {
  155. pipeline_->bind(command_buffer);
  156. for (auto& obj : gameobjects_)
  157. {
  158. PushConstant push{};
  159. push.offset = obj.transform_.translation;
  160. push.color = obj.color_;
  161. push.transform = obj.transform_.mat3();
  162. vkCmdPushConstants(
  163. command_buffer,
  164. pipeline_layout_,
  165. VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
  166. 0, sizeof(PushConstant), &push);
  167. obj.mesh_->bind(command_buffer);
  168. obj.mesh_->draw(command_buffer);
  169. }
  170. }