vk_engine.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  1. #include "vk_engine.h"
  2. // VMA
  3. #define VMA_IMPLEMENTATION
  4. #include "vk_mem_alloc.h"
  5. // GLFW Window
  6. #define GLFW_INCLUDE_VULKAN
  7. #include <GLFW/glfw3.h>
  8. // GLM
  9. #include <gtx/transform.hpp>
  10. // Bootstrap library
  11. #include <VkBootstrap.h>
  12. // STL includes
  13. #include <iostream>
  14. #include <iomanip>
  15. #include <fstream>
  16. #pragma region macros
  17. // Vulkan error macro
  18. using namespace std;
  19. #define VK_CHECK(x) \
  20. do \
  21. { \
  22. VkResult err = x; \
  23. if (err) \
  24. { \
  25. std::cout << "Detected Vulkan error: " << err << "\n"; \
  26. abort(); \
  27. } \
  28. } while (0)
  29. #pragma endregion
  30. // Vulkan includes
  31. #include "vk_initializers.h"
  32. #include "vk_pipeline.h"
  33. #include "vk_texture.h"
  34. using namespace Coral3D;
  35. void VulkanEngine::init()
  36. {
  37. // WINDOW
  38. init_window();
  39. // VULKAN
  40. init_vulkan();
  41. init_swapchain();
  42. init_commands();
  43. init_def_renderpass();
  44. init_framebuffers();
  45. init_sync_structures();
  46. init_descriptors();
  47. init_pipelines();
  48. // SCENES
  49. load_images();
  50. load_meshes();
  51. init_scene();
  52. m_IsInitialized = true;
  53. std::cout << "VulkanEngine initialized\n";
  54. }
  55. void VulkanEngine::run()
  56. {
  57. while (!glfwWindowShouldClose(m_pWindow))
  58. {
  59. glfwPollEvents();
  60. draw();
  61. }
  62. glfwTerminate();
  63. }
  64. void VulkanEngine::init_window()
  65. {
  66. std::cout << "VulkanEngine created\n";
  67. // Init glfw library
  68. if (!glfwInit())
  69. return;
  70. // Create window without OpenGL context
  71. glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
  72. m_pWindow = glfwCreateWindow(1280, 720, "Coral3D", nullptr, nullptr);
  73. if (!m_pWindow)
  74. {
  75. glfwTerminate();
  76. throw std::runtime_error("Failed to create window");
  77. }
  78. if (!glfwInit())
  79. throw std::runtime_error("Failed to initialize glfw");
  80. }
  81. void VulkanEngine::immediate_submit(std::function<void(VkCommandBuffer cmd)>&& function)
  82. {
  83. VkCommandBuffer cmd{ m_UploadContext.command_buffer };
  84. // Begin command buffer recording. We use it exact once before resetting
  85. VkCommandBufferBeginInfo cmdBeginInfo{ vkinit::command_buffer_bi(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) };
  86. VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
  87. // Execute function
  88. function(cmd);
  89. VK_CHECK(vkEndCommandBuffer(cmd));
  90. VkSubmitInfo submit{ vkinit::submit_info(&cmd) };
  91. // Submit command buffer to queue and execute it
  92. // uploadFence will now block until the graphic commands finish execution
  93. VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &submit, m_UploadContext.upload_fence));
  94. vkWaitForFences(m_Device, 1, &m_UploadContext.upload_fence, true, UINT64_MAX);
  95. vkResetFences(m_Device, 1, &m_UploadContext.upload_fence);
  96. // Reset command buffers inside the pool
  97. vkResetCommandPool(m_Device, m_UploadContext.command_pool, 0);
  98. }
  99. void VulkanEngine::draw()
  100. {
  101. // Wait for the GPU to be done with the last frame
  102. VK_CHECK(vkWaitForFences(m_Device, 1, &get_current_frame().render_fence, true, UINT64_MAX));
  103. VK_CHECK(vkResetFences(m_Device, 1, &get_current_frame().render_fence));
  104. // Request image from the swap chain
  105. uint32_t swapchainImageIndex;
  106. VK_CHECK(vkAcquireNextImageKHR(m_Device, m_SwapChain, UINT64_MAX, get_current_frame().present_semaphore, nullptr, &swapchainImageIndex));
  107. // Commands have finished executing, so reset the buffer
  108. VK_CHECK(vkResetCommandBuffer(get_current_frame().main_command_buffer, 0));
  109. // Record commands
  110. VkCommandBufferBeginInfo cmdBeginInfo{};
  111. cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  112. cmdBeginInfo.pNext = nullptr;
  113. cmdBeginInfo.pInheritanceInfo = nullptr;
  114. // We record each frame to the command buffer, so we need to let Vulkan know that we're only executing it once
  115. cmdBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  116. // Begin recording
  117. VK_CHECK(vkBeginCommandBuffer(get_current_frame().main_command_buffer, &cmdBeginInfo));
  118. // Clear color
  119. VkClearValue clearValue;
  120. clearValue.color = { {0.1f, 0.1f, 0.85f, 1.0f} };
  121. // Depth clear value
  122. VkClearValue depthClear;
  123. depthClear.depthStencil.depth = 1.f;
  124. VkClearValue clearValues[] = { clearValue, depthClear };
  125. // Begin the render pass
  126. VkRenderPassBeginInfo rpInfo{};
  127. rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  128. rpInfo.pNext = nullptr;
  129. // Use the default render pass on the image with the index that we acquired
  130. rpInfo.renderPass = m_RenderPass;
  131. rpInfo.renderArea.offset.x = 0;
  132. rpInfo.renderArea.offset.y = 0;
  133. rpInfo.renderArea.extent = m_WindowExtent;
  134. rpInfo.framebuffer = m_Framebuffers[swapchainImageIndex];
  135. // Connect clear values
  136. rpInfo.clearValueCount = 2;
  137. rpInfo.pClearValues = &clearValues[0];
  138. // Send the begin command to Vulkan
  139. vkCmdBeginRenderPass(get_current_frame().main_command_buffer, &rpInfo, VK_SUBPASS_CONTENTS_INLINE);
  140. // RENDER STUFF HERE
  141. // ...
  142. draw_objects(get_current_frame().main_command_buffer, m_Renderables.data(), m_Renderables.size());
  143. // End the render pass
  144. vkCmdEndRenderPass(get_current_frame().main_command_buffer);
  145. // End recording
  146. VK_CHECK(vkEndCommandBuffer(get_current_frame().main_command_buffer));
  147. // Prepare to submit to the queue
  148. VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  149. VkSubmitInfo submit{};
  150. submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  151. submit.pNext = nullptr;
  152. submit.pWaitDstStageMask = &waitStage;
  153. // Wait for image to be ready for rendering before rendering to it
  154. submit.waitSemaphoreCount = 1;
  155. submit.pWaitSemaphores = &get_current_frame().present_semaphore;
  156. // Signal ready when finished rendering
  157. submit.signalSemaphoreCount = 1;
  158. submit.pSignalSemaphores = &get_current_frame().render_semaphore;
  159. submit.commandBufferCount = 1;
  160. submit.pCommandBuffers = &get_current_frame().main_command_buffer;
  161. // Submit to the graphics queue
  162. VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &submit, get_current_frame().render_fence));
  163. // Present the image to the window when the rendering semaphore has signaled that rendering is done
  164. VkPresentInfoKHR presentInfo{};
  165. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  166. presentInfo.pNext = nullptr;
  167. presentInfo.pSwapchains = &m_SwapChain;
  168. presentInfo.swapchainCount = 1;
  169. presentInfo.waitSemaphoreCount = 1;
  170. presentInfo.pWaitSemaphores = &get_current_frame().render_semaphore;
  171. // Which image to present
  172. presentInfo.pImageIndices = &swapchainImageIndex;
  173. VK_CHECK(vkQueuePresentKHR(m_GraphicsQueue, &presentInfo));
  174. m_FrameNumber++;
  175. }
  176. std::vector<IndirectBatch> Coral3D::VulkanEngine::batch_draws(const std::vector<RenderObject>& renderObjects)
  177. {
  178. std::vector<IndirectBatch> draws;
  179. int id{};
  180. std::for_each(begin(renderObjects), end(renderObjects), [&](const RenderObject& ro) {
  181. bool isMeshBatched { !draws.empty() && ro.mesh == draws.back().mesh };
  182. bool isMaterialBatched { !draws.empty() && ro.material == draws.back().material };
  183. // Mesh and material combo is already batched, just increase count
  184. if (isMeshBatched && isMaterialBatched)
  185. draws.back().count++;
  186. // Mesh and material combo is not already batched, add new draw
  187. else
  188. {
  189. IndirectBatch newDraw;
  190. newDraw.mesh = ro.mesh;
  191. newDraw.material = ro.material;
  192. newDraw.first = id;
  193. newDraw.count = 1;
  194. draws.emplace_back(newDraw);
  195. }
  196. id++;
  197. });
  198. return draws;
  199. }
  200. void VulkanEngine::cleanup()
  201. {
  202. if (m_IsInitialized)
  203. {
  204. // Wait for the GPU to be done with the last frame
  205. vkDeviceWaitIdle(m_Device);
  206. m_MainDeletionQueue.Flush();
  207. vkDestroyDevice(m_Device, nullptr);
  208. vkDestroySurfaceKHR(m_Instance, m_Surface, nullptr);
  209. vkb::destroy_debug_utils_messenger(m_Instance, m_DebugMessenger);
  210. vkDestroyInstance(m_Instance, nullptr);
  211. }
  212. }
  213. void VulkanEngine::init_vulkan()
  214. {
  215. std::cout << "Initializing Vulkan\n";
  216. vkb::InstanceBuilder builder;
  217. // Make the Vulkan instance, with basic debug features
  218. auto instanceDesc = builder.set_app_name("Coral3D")
  219. #ifdef NDEBUG
  220. .request_validation_layers(false)
  221. #else
  222. .request_validation_layers(true)
  223. #endif
  224. .require_api_version(1, 1, 0)
  225. .use_default_debug_messenger()
  226. .build();
  227. vkb::Instance vkbInstance = instanceDesc.value();
  228. // Store the instance
  229. m_Instance = vkbInstance.instance;
  230. // Store the debug messenger
  231. m_DebugMessenger = vkbInstance.debug_messenger;
  232. if (glfwCreateWindowSurface(m_Instance, m_pWindow, nullptr, &m_Surface) != VK_SUCCESS) {
  233. throw std::runtime_error("failed to create window surface!");
  234. }
  235. // Get the window size to use for the swap chain
  236. int width, height;
  237. glfwGetWindowSize(m_pWindow, &width, &height);
  238. m_WindowExtent.width = static_cast<uint32_t>(width);
  239. m_WindowExtent.height = static_cast<uint32_t>(height);
  240. // use vkbootstrap to select a GPU.
  241. // We want a GPU that can write to the GLFW surface and supports Vulkan 1.2
  242. vkb::PhysicalDeviceSelector selector{ vkbInstance };
  243. VkPhysicalDeviceFeatures features{};
  244. features.multiDrawIndirect = true;
  245. features.drawIndirectFirstInstance = true;
  246. selector.set_required_features(features);
  247. vkb::PhysicalDevice physicalDevice = selector
  248. .set_minimum_version(1, 1)
  249. .set_surface(m_Surface)
  250. .select()
  251. .value();
  252. // create the final Vulkan device
  253. vkb::DeviceBuilder deviceBuilder{ physicalDevice };
  254. VkPhysicalDeviceShaderDrawParameterFeatures shaderDrawParams{};
  255. shaderDrawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
  256. shaderDrawParams.pNext = nullptr;
  257. shaderDrawParams.shaderDrawParameters = VK_TRUE;
  258. vkb::Device vkbDevice = deviceBuilder.add_pNext(&shaderDrawParams).build().value();
  259. // Get the VkDevice handle used in the rest of a Vulkan application
  260. m_Device = vkbDevice.device;
  261. m_PhysicalDevice = physicalDevice.physical_device;
  262. // Get the graphics queue for the rest of the Vulkan application
  263. m_GraphicsQueue = vkbDevice.get_queue(vkb::QueueType::graphics).value();
  264. m_GraphicsQueueFamily = vkbDevice.get_queue_index(vkb::QueueType::graphics).value();
  265. VmaAllocatorCreateInfo allocatorInfo{};
  266. allocatorInfo.physicalDevice = m_PhysicalDevice;
  267. allocatorInfo.device = m_Device;
  268. allocatorInfo.instance = m_Instance;
  269. vmaCreateAllocator(&allocatorInfo, &m_Allocator);
  270. m_MainDeletionQueue.deletors.emplace_back([=]() {
  271. vmaDestroyAllocator(m_Allocator);
  272. });
  273. m_DeviceProperties = vkbDevice.physical_device.properties;
  274. std::cout << vkbDevice.physical_device.features.multiDrawIndirect << std::endl;
  275. std::cout << "The GPU has a minimum buffer alignment of " << m_DeviceProperties.limits.minUniformBufferOffsetAlignment << "\n";
  276. }
  277. void VulkanEngine::init_swapchain()
  278. {
  279. std::cout << "Initializing Swap Chain\n";
  280. vkb::SwapchainBuilder swapChainBuilder{ m_PhysicalDevice, m_Device, m_Surface };
  281. vkb::Swapchain vkbSwapChain = swapChainBuilder
  282. .use_default_format_selection()
  283. // use VSync present mode
  284. .set_desired_present_mode(VK_PRESENT_MODE_MAILBOX_KHR)
  285. .set_desired_extent(m_WindowExtent.width, m_WindowExtent.height)
  286. .build()
  287. .value();
  288. // store swap chain and its related images
  289. m_SwapChain = vkbSwapChain.swapchain;
  290. m_SwapChainImages = vkbSwapChain.get_images().value();
  291. m_SwapChainImageViews = vkbSwapChain.get_image_views().value();
  292. m_SwapChainImageFormat = vkbSwapChain.image_format;
  293. m_MainDeletionQueue.deletors.emplace_back([=]() {
  294. vkDestroySwapchainKHR(m_Device, m_SwapChain, nullptr);
  295. });
  296. // Depth buffer image matches window extents
  297. VkExtent3D depthImageExtent
  298. {
  299. m_WindowExtent.width,
  300. m_WindowExtent.height,
  301. 1
  302. };
  303. // Depth format (must be changed to support stencil)
  304. m_DepthFormat = VK_FORMAT_D32_SFLOAT;
  305. VkImageCreateInfo depthImageCreateInfo = vkinit::image_ci(m_DepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, depthImageExtent);
  306. // Allocate image on GPU
  307. VmaAllocationCreateInfo depthImageAllocInfo{};
  308. depthImageAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  309. depthImageAllocInfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  310. // Allocate mem and create image
  311. vmaCreateImage(m_Allocator, &depthImageCreateInfo, &depthImageAllocInfo, &m_DepthImage.image, &m_DepthImage.allocation, nullptr);
  312. // Build depth buffer image view
  313. VkImageViewCreateInfo depthImageViewCreateInfo = vkinit::image_view_ci(m_DepthFormat, m_DepthImage.image, VK_IMAGE_ASPECT_DEPTH_BIT);
  314. VK_CHECK(vkCreateImageView(m_Device, &depthImageViewCreateInfo, nullptr, &m_DepthImageView));
  315. m_MainDeletionQueue.deletors.emplace_back([=]() {
  316. vkDestroyImageView(m_Device, m_DepthImageView, nullptr);
  317. vmaDestroyImage(m_Allocator, m_DepthImage.image, m_DepthImage.allocation);
  318. });
  319. }
  320. void VulkanEngine::init_commands()
  321. {
  322. std::cout << "Initializing Commands\n";
  323. // Create pool for upload context
  324. VkCommandPoolCreateInfo uploadCommandPoolInfo{ vkinit::command_pool_ci(m_GraphicsQueueFamily) };
  325. VK_CHECK(vkCreateCommandPool(m_Device, &uploadCommandPoolInfo, nullptr, &m_UploadContext.command_pool));
  326. m_MainDeletionQueue.deletors.emplace_back([=]() {
  327. vkDestroyCommandPool(m_Device, m_UploadContext.command_pool, nullptr);
  328. });
  329. // Allocate default command buffer that we will use for immediate commands
  330. VkCommandBufferAllocateInfo cmdAllocInfo{ vkinit::command_buffer_ai(m_UploadContext.command_pool, 1) };
  331. VkCommandBuffer cmd;
  332. VK_CHECK(vkAllocateCommandBuffers(m_Device, &cmdAllocInfo, &m_UploadContext.command_buffer));
  333. // Create command pool for commands submitted to the graphics queue
  334. // We also want the pool to allow for resetting of individual command buffers
  335. auto commandPoolInfo = vkinit::command_pool_ci(m_GraphicsQueueFamily, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
  336. for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
  337. {
  338. VK_CHECK(vkCreateCommandPool(m_Device, &commandPoolInfo, nullptr, &m_Frames[i].command_pool));
  339. // Allocate the default command buffer that we will use for rendering
  340. auto commandBufferInfo = vkinit::command_buffer_ai(m_Frames[i].command_pool, 1);
  341. VK_CHECK(vkAllocateCommandBuffers(m_Device, &commandBufferInfo, &m_Frames[i].main_command_buffer));
  342. m_MainDeletionQueue.deletors.emplace_back([=]() {
  343. vkDestroyCommandPool(m_Device, m_Frames[i].command_pool, nullptr);
  344. });
  345. }
  346. }
  347. AllocatedBuffer VulkanEngine::create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage)
  348. {
  349. VkBufferCreateInfo info{};
  350. info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  351. info.pNext = nullptr;
  352. info.size = allocSize;
  353. info.usage = usage;
  354. VmaAllocationCreateInfo vmaallocInfo{};
  355. vmaallocInfo.usage = memoryUsage;
  356. AllocatedBuffer newBuffer{};
  357. VK_CHECK(vmaCreateBuffer(m_Allocator, &info, &vmaallocInfo,
  358. &newBuffer.buffer,
  359. &newBuffer.allocation,
  360. nullptr));
  361. return newBuffer;
  362. }
  363. void VulkanEngine::init_descriptors()
  364. {
  365. // Create descriptor pool, descriptor sets will be allocated from this pool
  366. std::vector<VkDescriptorPoolSize> sizes
  367. {
  368. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 10 },
  369. { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 10 },
  370. { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 10 },
  371. { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 10}
  372. };
  373. VkDescriptorPoolCreateInfo poolInfo{};
  374. poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  375. poolInfo.pNext = nullptr;
  376. poolInfo.flags = 0;
  377. poolInfo.maxSets = 10;
  378. poolInfo.poolSizeCount = static_cast<uint32_t>(sizes.size());
  379. poolInfo.pPoolSizes = sizes.data();
  380. vkCreateDescriptorPool(m_Device, &poolInfo, nullptr, &m_DescriptorPool);
  381. #pragma region DescriptorSet 1 (Global)
  382. // DescriptorSetLayout defines how the descriptor data is layed out in the descriptor set
  383. // Bindig 0: Uniform buffer (Camera data)
  384. VkDescriptorSetLayoutBinding camBufferBinding{ vkinit::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
  385. VK_SHADER_STAGE_VERTEX_BIT, 0) };
  386. // Binding 1: Uniform buffer (Scene data)
  387. VkDescriptorSetLayoutBinding sceneBufferBinding{ vkinit::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
  388. VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 1) };
  389. VkDescriptorSetLayoutBinding bindings[] = { camBufferBinding, sceneBufferBinding };
  390. VkDescriptorSetLayoutCreateInfo camSetInfo{};
  391. camSetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  392. camSetInfo.pNext = nullptr;
  393. // We currently only have one binding, the camera buffer
  394. camSetInfo.bindingCount = 2;
  395. camSetInfo.pBindings = bindings;
  396. camSetInfo.flags = 0;
  397. vkCreateDescriptorSetLayout(m_Device, &camSetInfo, nullptr, &m_GlobalSetLayout);
  398. #pragma endregion
  399. #pragma region DescriptorSet 2 (Object)
  400. VkDescriptorSetLayoutBinding objectBind{vkinit::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
  401. VK_SHADER_STAGE_VERTEX_BIT, 0) };
  402. VkDescriptorSetLayoutCreateInfo objectSetInfo{};
  403. objectSetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  404. objectSetInfo.pNext = nullptr;
  405. objectSetInfo.bindingCount = 1;
  406. objectSetInfo.pBindings = &objectBind;
  407. objectSetInfo.flags = 0;
  408. vkCreateDescriptorSetLayout(m_Device, &objectSetInfo, nullptr, &m_ObjectSetLayout);
  409. #pragma endregion
  410. #pragma region DescriptorSet 3 (Texture)
  411. VkDescriptorSetLayoutBinding textureBind{vkinit::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0)};
  412. VkDescriptorSetLayoutCreateInfo texSetInfo{};
  413. texSetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  414. texSetInfo.pNext = nullptr;
  415. texSetInfo.bindingCount = 1;
  416. texSetInfo.flags = 0;
  417. texSetInfo.pBindings = &textureBind;
  418. vkCreateDescriptorSetLayout(m_Device, &texSetInfo, nullptr, &m_SingleTextureSetLayout);
  419. #pragma endregion
  420. const size_t sceneDataBufferSize = MAX_FRAMES_IN_FLIGHT * pad_uniform_buffer_size(sizeof(GPUSceneData));
  421. m_SceneDataBuffer = create_buffer(sceneDataBufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
  422. const int MAX_OBJECTS = 10'000;
  423. for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
  424. {
  425. // Object data buffer
  426. m_Frames[i].object_buffer = create_buffer(sizeof(GPUObjectData) * MAX_OBJECTS,
  427. VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
  428. // Camera data buffer
  429. m_Frames[i].camera_buffer = create_buffer(sizeof(GPUCameraData), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
  430. // Indirect buffer
  431. m_Frames[i].indirect_buffer = create_buffer(sizeof(VkDrawIndirectCommand) * 10'000,
  432. VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);
  433. // Allocate one descriptor set for each frame
  434. VkDescriptorSetAllocateInfo allocInfo{};
  435. allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  436. allocInfo.pNext = nullptr;
  437. allocInfo.descriptorPool = m_DescriptorPool;
  438. allocInfo.descriptorSetCount = 1;
  439. allocInfo.pSetLayouts = &m_GlobalSetLayout;
  440. vkAllocateDescriptorSets(m_Device, &allocInfo, &m_Frames[i].global_descriptor);
  441. // Allocate one descriptor set that will point to the object buffer for each frame
  442. VkDescriptorSetAllocateInfo objectAlloc{};
  443. objectAlloc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  444. objectAlloc.pNext = nullptr;
  445. objectAlloc.descriptorPool = m_DescriptorPool;
  446. objectAlloc.descriptorSetCount = 1;
  447. objectAlloc.pSetLayouts = &m_ObjectSetLayout;
  448. vkAllocateDescriptorSets(m_Device, &objectAlloc, &m_Frames[i].object_descriptor);
  449. // Info about the camera buffer we want to point at in the descriptor
  450. VkDescriptorBufferInfo cameraInfo{};
  451. cameraInfo.buffer = m_Frames[i].camera_buffer.buffer;
  452. // Offset into the buffer
  453. cameraInfo.offset = 0;
  454. // Size of data to pass to the shader
  455. cameraInfo.range = sizeof(GPUCameraData);
  456. VkDescriptorBufferInfo sceneInfo{};
  457. sceneInfo.buffer = m_SceneDataBuffer.buffer;
  458. sceneInfo.offset = 0;
  459. sceneInfo.range = sizeof(GPUSceneData);
  460. VkDescriptorBufferInfo objectBufferInfo{};
  461. objectBufferInfo.buffer = m_Frames[i].object_buffer.buffer;
  462. objectBufferInfo.offset = 0;
  463. objectBufferInfo.range = sizeof(GPUObjectData) * MAX_OBJECTS;
  464. VkWriteDescriptorSet cameraWrite{vkinit::write_descriptor_buffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
  465. m_Frames[i].global_descriptor, &cameraInfo, 0)};
  466. VkWriteDescriptorSet sceneWrite{ vkinit::write_descriptor_buffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
  467. m_Frames[i].global_descriptor, &sceneInfo, 1) };
  468. VkWriteDescriptorSet objectWrite{ vkinit::write_descriptor_buffer(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
  469. m_Frames[i].object_descriptor, &objectBufferInfo, 0) };
  470. VkWriteDescriptorSet setWrites[] = { cameraWrite, sceneWrite, objectWrite };
  471. vkUpdateDescriptorSets(m_Device, 3, setWrites, 0, nullptr);
  472. }
  473. m_MainDeletionQueue.deletors.emplace_back([&]() {
  474. vkDestroyDescriptorPool(m_Device, m_DescriptorPool, nullptr);
  475. vkDestroyDescriptorSetLayout(m_Device, m_GlobalSetLayout, nullptr);
  476. vkDestroyDescriptorSetLayout(m_Device, m_ObjectSetLayout, nullptr);
  477. // Add buffers to deletion queue
  478. for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
  479. {
  480. vmaDestroyBuffer(m_Allocator, m_Frames[i].camera_buffer.buffer, m_Frames[i].camera_buffer.allocation);
  481. vmaDestroyBuffer(m_Allocator, m_Frames[i].object_buffer.buffer, m_Frames[i].object_buffer.allocation);
  482. }
  483. vmaDestroyBuffer(m_Allocator, m_SceneDataBuffer.buffer, m_SceneDataBuffer.allocation);
  484. });
  485. }
  486. void VulkanEngine::init_def_renderpass()
  487. {
  488. std::cout << "Initializing Default Render Pass\n";
  489. // Description of the image that we will be writing rendering commands to
  490. VkAttachmentDescription colorAttachment{};
  491. // format should be the same as the swap chain images
  492. colorAttachment.format = m_SwapChainImageFormat;
  493. // MSAA samples, set to 1 (no MSAA) by default
  494. colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
  495. // Clear when render pass begins
  496. colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  497. // Keep the attachment stored when render pass ends
  498. colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  499. // Don't care about stencil data
  500. colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  501. colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  502. // Image data layout before render pass starts (undefined = don't care)
  503. colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  504. // Image data layout after render pass (to change to), set to present by default
  505. colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
  506. VkAttachmentReference colorAttachmentRef{};
  507. // Attachment number will index into the pAttachments array in the parent render pass itself
  508. colorAttachmentRef.attachment = 0;
  509. // Optimal layout for writing to the image
  510. colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  511. // Description of the depth image
  512. VkAttachmentDescription depthAttachment{};
  513. depthAttachment.flags = 0;
  514. depthAttachment.format = m_DepthFormat;
  515. depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
  516. depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  517. depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  518. depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
  519. depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  520. depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  521. depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  522. VkAttachmentReference depthAttachmentRef{};
  523. depthAttachmentRef.attachment = 1;
  524. depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  525. // Create one sub pass (minimum one sub pass required)
  526. VkSubpassDescription subpass{};
  527. subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
  528. subpass.colorAttachmentCount = 1;
  529. subpass.pColorAttachments = &colorAttachmentRef;
  530. // Connect depth attachment to subpass
  531. subpass.pDepthStencilAttachment = &depthAttachmentRef;
  532. VkRenderPassCreateInfo renderPassInfo{};
  533. renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  534. VkAttachmentDescription attachments[2] = { colorAttachment, depthAttachment };
  535. // Connect the color attachment description to the info
  536. renderPassInfo.attachmentCount = 2;
  537. renderPassInfo.pAttachments = &attachments[0];
  538. // Connect the subpass(es) to the info
  539. renderPassInfo.subpassCount = 1;
  540. renderPassInfo.pSubpasses = &subpass;
  541. // These dependencies tell Vulkan that the attachment cannot be used before the previous renderpasses have finished using it
  542. VkSubpassDependency colorDependency{};
  543. colorDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
  544. colorDependency.dstSubpass = 0;
  545. colorDependency.srcAccessMask = 0;
  546. colorDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  547. colorDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  548. colorDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  549. VkSubpassDependency depthDependency{};
  550. depthDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
  551. depthDependency.dstSubpass = 0;
  552. depthDependency.srcAccessMask = 0;
  553. depthDependency.srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
  554. depthDependency.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  555. depthDependency.dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
  556. VkSubpassDependency dependencies[2] = { colorDependency, depthDependency };
  557. renderPassInfo.dependencyCount = 2;
  558. renderPassInfo.pDependencies = &dependencies[0];
  559. VK_CHECK(vkCreateRenderPass(m_Device, &renderPassInfo, nullptr, &m_RenderPass));
  560. m_MainDeletionQueue.deletors.emplace_back([=]() {
  561. vkDestroyRenderPass(m_Device, m_RenderPass, nullptr);
  562. });
  563. }
  564. void VulkanEngine::init_framebuffers()
  565. {
  566. std::cout << "Initializing Framebuffers\n";
  567. // Create the framebuffers for the swap chain images.
  568. // This will connect the render pass to the images for rendering
  569. VkFramebufferCreateInfo fbInfo{};
  570. fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  571. // Connect the render pass to the framebuffer
  572. fbInfo.renderPass = m_RenderPass;
  573. fbInfo.attachmentCount = 1;
  574. fbInfo.width = m_WindowExtent.width;
  575. fbInfo.height = m_WindowExtent.height;
  576. fbInfo.layers = 1;
  577. // Get the number of swap chain image views
  578. const uint32_t swapChainImageViewCount = static_cast<uint32_t>(m_SwapChainImageViews.size());
  579. m_Framebuffers = std::vector<VkFramebuffer>(swapChainImageViewCount);
  580. // Create the framebuffers for each image view
  581. for (uint32_t i = 0; i < swapChainImageViewCount; i++)
  582. {
  583. VkImageView attachments[2] = { m_SwapChainImageViews[i], m_DepthImageView };
  584. fbInfo.attachmentCount = 2;
  585. fbInfo.pAttachments = attachments;
  586. VK_CHECK(vkCreateFramebuffer(m_Device, &fbInfo, nullptr, &m_Framebuffers[i]));
  587. m_MainDeletionQueue.deletors.emplace_back([=]() {
  588. vkDestroyFramebuffer(m_Device, m_Framebuffers[i], nullptr);
  589. vkDestroyImageView(m_Device, m_SwapChainImageViews[i], nullptr);
  590. });
  591. }
  592. }
  593. FrameData& VulkanEngine::get_current_frame()
  594. {
  595. return m_Frames[m_FrameNumber % MAX_FRAMES_IN_FLIGHT];
  596. }
  597. void VulkanEngine::init_sync_structures()
  598. {
  599. std::cout << "Initializing Sync Structures\n";
  600. // Upload fence
  601. VkFenceCreateInfo uploadFenceCreateInfo{ vkinit::fence_ci() };
  602. VK_CHECK(vkCreateFence(m_Device, &uploadFenceCreateInfo, nullptr, &m_UploadContext.upload_fence));
  603. m_MainDeletionQueue.deletors.emplace_back([=]() {
  604. vkDestroyFence(m_Device, m_UploadContext.upload_fence, nullptr);
  605. });
  606. // Render fence
  607. VkFenceCreateInfo fenceCreateInfo{ vkinit::fence_ci(VK_FENCE_CREATE_SIGNALED_BIT) };
  608. // Sempahore needs no flags
  609. VkSemaphoreCreateInfo semaphoreCreateInfo{ vkinit::semaphore_ci() };
  610. for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
  611. {
  612. VK_CHECK(vkCreateFence(m_Device, &fenceCreateInfo, nullptr, &m_Frames[i].render_fence));
  613. m_MainDeletionQueue.deletors.emplace_back([=]() {
  614. vkDestroyFence(m_Device, m_Frames[i].render_fence, nullptr);
  615. });
  616. VK_CHECK(vkCreateSemaphore(m_Device, &semaphoreCreateInfo, nullptr, &m_Frames[i].present_semaphore));
  617. VK_CHECK(vkCreateSemaphore(m_Device, &semaphoreCreateInfo, nullptr, &m_Frames[i].render_semaphore));
  618. m_MainDeletionQueue.deletors.emplace_back([=]()
  619. {
  620. vkDestroySemaphore(m_Device, m_Frames[i].present_semaphore, nullptr);
  621. vkDestroySemaphore(m_Device, m_Frames[i].render_semaphore, nullptr);
  622. });
  623. }
  624. }
  625. bool VulkanEngine::load_shader_module(const char* filePath, VkShaderModule* outShaderModule)
  626. {
  627. // Open the file stream, seek to the end of the file
  628. std::ifstream file(filePath, std::ios::ate | std::ios::binary);
  629. if (!file.is_open())
  630. return false;
  631. // Get the file size
  632. size_t fileSize = static_cast<size_t>(file.tellg());
  633. // SPRIV expects the buffer to be on uint32_t, so make sure to reserve a buffer big enough for that
  634. std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t));
  635. // Put cursor at the beginning of the file
  636. file.seekg(0);
  637. // Load the entire file into the buffer
  638. file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
  639. // Close the file stream
  640. file.close();
  641. // Create a new shader module, using the buffer we loaded
  642. VkShaderModuleCreateInfo createInfo{};
  643. createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
  644. createInfo.pNext = nullptr;
  645. // Code size has to be in bytes, so multiply the int in the buffer by the size of an int
  646. createInfo.codeSize = buffer.size() * sizeof(uint32_t);
  647. createInfo.pCode = buffer.data();
  648. // Validate creation
  649. VkShaderModule shaderModule;
  650. if (vkCreateShaderModule(m_Device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS)
  651. return false;
  652. // Set the outShaderModule to the newly created shader module
  653. *outShaderModule = shaderModule;
  654. return true;
  655. }
  656. void VulkanEngine::init_pipelines()
  657. {
  658. std::cout << "Initializing Pipelines\n";
  659. VkShaderModule fragShader;
  660. if (!load_shader_module("shaders/PosNormCol.frag.spv", &fragShader))
  661. std::cout << "Error building the triangle fragment shader module\n";
  662. else
  663. std::cout << "Successfully built the fragment shader module\n";
  664. VkShaderModule vertShader;
  665. if (!load_shader_module("shaders/PosNormCol.vert.spv", &vertShader))
  666. std::cout << "Error building the triangle vertex shader module\n";
  667. else
  668. std::cout << "Successfully built the vertex shader module\n";
  669. // Build pipeline layout that controls inputs/outputs of the shader
  670. VkPipelineLayoutCreateInfo pipelineLayoutInfo{ vkinit::pipeline_layout_ci() };
  671. VkDescriptorSetLayout setLayouts[] = { m_GlobalSetLayout, m_ObjectSetLayout, m_SingleTextureSetLayout };
  672. pipelineLayoutInfo.setLayoutCount = 3;
  673. pipelineLayoutInfo.pSetLayouts = setLayouts;
  674. VK_CHECK(vkCreatePipelineLayout(m_Device, &pipelineLayoutInfo, nullptr, &m_MeshPipelineLayout));
  675. // Build the stage-create-info for both vertex and fragment stages.
  676. // This lets the pipeline know the shader modules per stage
  677. PipelineBuilder pipelineBuilder;
  678. pipelineBuilder.m_ShaderStages.push_back(
  679. vkinit::pipeline_shader_stage_ci(VK_SHADER_STAGE_VERTEX_BIT, vertShader)
  680. );
  681. pipelineBuilder.m_ShaderStages.push_back(
  682. vkinit::pipeline_shader_stage_ci(VK_SHADER_STAGE_FRAGMENT_BIT, fragShader)
  683. );
  684. // Vertex input controls how to read vertices from vertex buffers
  685. pipelineBuilder.m_VertexInputInfo = vkinit::vertex_input_state_ci();
  686. VertexInputDescription vertexDesc = Vertex::get_vert_desc();
  687. pipelineBuilder.m_VertexInputInfo.pVertexAttributeDescriptions = vertexDesc.attributes.data();
  688. pipelineBuilder.m_VertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexDesc.attributes.size());
  689. pipelineBuilder.m_VertexInputInfo.pVertexBindingDescriptions = vertexDesc.bindings.data();
  690. pipelineBuilder.m_VertexInputInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(vertexDesc.bindings.size());
  691. // Set input assembly state, which controls primitive topology
  692. pipelineBuilder.m_InputAssembly = vkinit::input_assembly_ci(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
  693. // Build the viewport and scissor from the swapchain extents
  694. pipelineBuilder.m_Viewport.x = 0.0f;
  695. pipelineBuilder.m_Viewport.y = 0.0f;
  696. pipelineBuilder.m_Viewport.width = static_cast<float>(m_WindowExtent.width);
  697. pipelineBuilder.m_Viewport.height = static_cast<float>(m_WindowExtent.height);
  698. pipelineBuilder.m_Viewport.minDepth = 0.0f;
  699. pipelineBuilder.m_Viewport.maxDepth = 1.0f;
  700. pipelineBuilder.m_Scissor.offset = { 0, 0 };
  701. pipelineBuilder.m_Scissor.extent = m_WindowExtent;
  702. // Build rasterizer
  703. pipelineBuilder.m_Rasterizer = vkinit::rasterization_state_ci(VK_POLYGON_MODE_FILL);
  704. // Build multisampling
  705. pipelineBuilder.m_Multisampling = vkinit::multisample_state_ci();
  706. // Build color blend attachment with no blending and writing to RGBA
  707. pipelineBuilder.m_ColorBlendAttachment = vkinit::color_blend_attachment_state();
  708. // Use the triangle layout
  709. pipelineBuilder.m_PipelineLayout = m_MeshPipelineLayout;
  710. // Depth testing
  711. pipelineBuilder.m_DepthStencil = vkinit::depth_stencil_ci(true, true, VK_COMPARE_OP_LESS_OR_EQUAL);
  712. // Build the pipeline
  713. m_MeshPipeline = pipelineBuilder.build_pipeline(m_Device, m_RenderPass);
  714. create_material("defaultmesh", m_MeshPipeline, m_MeshPipelineLayout);
  715. vkDestroyShaderModule(m_Device, vertShader, nullptr);
  716. vkDestroyShaderModule(m_Device, fragShader, nullptr);
  717. m_MainDeletionQueue.deletors.emplace_back([=]() {
  718. vkDestroyPipeline(m_Device, m_MeshPipeline, nullptr);
  719. vkDestroyPipelineLayout(m_Device, m_MeshPipelineLayout, nullptr);
  720. });
  721. }
  722. void VulkanEngine::load_meshes()
  723. {
  724. m_TeapotMesh.load_from_obj("../../../../assets/teapot.obj");
  725. upload_mesh(m_TeapotMesh);
  726. m_Meshes["Teapot"] = m_TeapotMesh;
  727. //Mesh lost_empire{};
  728. //lost_empire.load_from_obj("../../../../assets/lost_empire.obj");
  729. //upload_mesh(lost_empire);
  730. //m_Meshes["empire"] = lost_empire;
  731. }
  732. void VulkanEngine::upload_mesh(Mesh& mesh)
  733. {
  734. const size_t bufferSize{ mesh.vertices.size() * sizeof(Vertex) };
  735. // Allocate CPU side vertex buffer
  736. VkBufferCreateInfo stagingBufferInfo{};
  737. stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  738. stagingBufferInfo.pNext = nullptr;
  739. // Total size, in bytes, of the buffer
  740. // Should hold all vertices
  741. stagingBufferInfo.size = bufferSize;
  742. stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  743. // This data should be on CPU RAM
  744. VmaAllocationCreateInfo vmaallocInfo{};
  745. vmaallocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
  746. AllocatedBuffer stagingBuffer;
  747. VK_CHECK(vmaCreateBuffer(m_Allocator, &stagingBufferInfo, &vmaallocInfo,
  748. &stagingBuffer.buffer,
  749. &stagingBuffer.allocation,
  750. nullptr));
  751. // Copy vertex data into buffer
  752. void* data;
  753. vmaMapMemory(m_Allocator, stagingBuffer.allocation, &data);
  754. memcpy(data, mesh.vertices.data(), bufferSize);
  755. vmaUnmapMemory(m_Allocator, stagingBuffer.allocation);
  756. // Allocate GPU side vertex buffer
  757. VkBufferCreateInfo vertexBufferInfo{};
  758. vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  759. vertexBufferInfo.pNext = nullptr;
  760. vertexBufferInfo.size = bufferSize;
  761. vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  762. vmaallocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
  763. VK_CHECK(vmaCreateBuffer(m_Allocator, &vertexBufferInfo, &vmaallocInfo,
  764. &mesh.vertexBuffer.buffer,
  765. &mesh.vertexBuffer.allocation,
  766. nullptr));
  767. // Copy data from CPU to GPU
  768. immediate_submit([=](VkCommandBuffer cmd) {
  769. VkBufferCopy copy;
  770. copy.dstOffset = 0;
  771. copy.srcOffset = 0;
  772. copy.size = bufferSize;
  773. vkCmdCopyBuffer(cmd, stagingBuffer.buffer, mesh.vertexBuffer.buffer, 1, &copy);
  774. });
  775. m_MainDeletionQueue.deletors.emplace_back([=]() {
  776. vmaDestroyBuffer(m_Allocator, mesh.vertexBuffer.buffer, mesh.vertexBuffer.allocation);
  777. });
  778. vmaDestroyBuffer(m_Allocator, stagingBuffer.buffer, stagingBuffer.allocation);
  779. }
  780. size_t VulkanEngine::pad_uniform_buffer_size(size_t originalSize)
  781. {
  782. size_t minUboAlignment = m_DeviceProperties.limits.minUniformBufferOffsetAlignment;
  783. size_t alignedSize = originalSize;
  784. if (minUboAlignment > 0)
  785. {
  786. alignedSize = (alignedSize + minUboAlignment - 1) & ~(minUboAlignment - 1);
  787. }
  788. return alignedSize;
  789. }
  790. Material* VulkanEngine::create_material(const std::string& name, VkPipeline pipeline, VkPipelineLayout layout)
  791. {
  792. Material mat;
  793. mat.pipeline = pipeline;
  794. mat.pipeline_layout = layout;
  795. m_Materials[name] = mat;
  796. return &m_Materials[name];
  797. }
  798. Material* VulkanEngine::get_material(const std::string& name)
  799. {
  800. auto it = m_Materials.find(name);
  801. if (it == end(m_Materials))
  802. return nullptr;
  803. else
  804. return &(*it).second;
  805. }
  806. Mesh* VulkanEngine::get_mesh(const std::string& name)
  807. {
  808. auto it = m_Meshes.find(name);
  809. if (it == end(m_Meshes))
  810. return nullptr;
  811. else
  812. return &(*it).second;
  813. }
  814. void Coral3D::VulkanEngine::load_images()
  815. {
  816. //Texture lost_empire;
  817. //vkutil::load_image_from_file(*this, "../../../../assets/lost_empire-RGBA.png", lost_empire.image);
  818. //VkImageViewCreateInfo img_info = vkinit::image_view_ci(VK_FORMAT_R8G8B8A8_SRGB, lost_empire.image.image, VK_IMAGE_ASPECT_COLOR_BIT);
  819. //vkCreateImageView(m_Device, &img_info, nullptr, &lost_empire.image_view);
  820. //m_LoadedTextures["empire_diffuse"] = lost_empire;
  821. Texture uv_checker;
  822. vkutil::load_image_from_file(*this, "../../../../assets/uv_checker.jpg", uv_checker.image);
  823. VkImageViewCreateInfo img_info = vkinit::image_view_ci(VK_FORMAT_R8G8B8A8_SRGB, uv_checker.image.image, VK_IMAGE_ASPECT_COLOR_BIT);
  824. vkCreateImageView(m_Device, &img_info, nullptr, &uv_checker.image_view);
  825. m_LoadedTextures["checker_diffuse"] = uv_checker;
  826. }
  827. void VulkanEngine::draw_objects(VkCommandBuffer cmdBuffer, RenderObject* first, int count)
  828. {
  829. glm::vec3 camPos{0.f, -30.f, -1310.f};
  830. // glm::vec3 camPos{0.f, -5.f, 0.f};
  831. // Camera matrices
  832. glm::mat4 trans{glm::translate(glm::mat4{1.f}, camPos)};
  833. glm::mat4 rot{glm::rotate(glm::radians(25.f), glm::vec3{1, 0, 0})};
  834. glm::mat4 view = rot * trans;
  835. glm::mat4 proj{glm::perspective(glm::radians(70.f), (float)m_WindowExtent.width / (float)m_WindowExtent.height, 0.1f, 10000.f)};
  836. proj[1][1] *= -1;
  837. GPUCameraData camData;
  838. camData.proj = proj;
  839. camData.view = view;
  840. camData.view_proj = proj * view;
  841. camData.view_inv = glm::inverse(view);
  842. // Camera data
  843. void* data;
  844. vmaMapMemory(m_Allocator, get_current_frame().camera_buffer.allocation, &data);
  845. memcpy(data, &camData, sizeof(GPUCameraData));
  846. vmaUnmapMemory(m_Allocator, get_current_frame().camera_buffer.allocation);
  847. // Scene data
  848. char* sceneData;
  849. vmaMapMemory(m_Allocator, m_SceneDataBuffer.allocation, (void**)&sceneData);
  850. int frameIndex = m_FrameNumber % MAX_FRAMES_IN_FLIGHT;
  851. sceneData += pad_uniform_buffer_size(sizeof(GPUSceneData)) * frameIndex;
  852. memcpy(sceneData, &m_GPUSceneData, sizeof(GPUSceneData));
  853. vmaUnmapMemory(m_Allocator, m_SceneDataBuffer.allocation);
  854. // Object data
  855. void* objectData;
  856. vmaMapMemory(m_Allocator, get_current_frame().object_buffer.allocation, &objectData);
  857. GPUObjectData* objectSSBO = (GPUObjectData*)objectData;
  858. for (int i = 0; i < count; i++)
  859. {
  860. RenderObject& object = first[i];
  861. objectSSBO[i].world = object.transform *
  862. glm::rotate(glm::mat4{1.f}, glm::radians(m_FrameNumber * 0.4f), glm::vec3(0, 0, 1));
  863. }
  864. vmaUnmapMemory(m_Allocator, get_current_frame().object_buffer.allocation);
  865. auto draws = batch_draws(m_Renderables);
  866. void* drawData;
  867. vmaMapMemory(m_Allocator, get_current_frame().indirect_buffer.allocation, &drawData);
  868. VkDrawIndirectCommand* drawCommands = reinterpret_cast<VkDrawIndirectCommand*>(drawData);
  869. for (int i = 0; i < count; i++)
  870. {
  871. RenderObject& object{ first[i] };
  872. drawCommands[i].vertexCount = object.mesh->vertices.size();
  873. drawCommands[i].instanceCount = 1;
  874. drawCommands[i].firstVertex = 0;
  875. drawCommands[i].firstInstance = i;
  876. }
  877. vmaUnmapMemory(m_Allocator, get_current_frame().indirect_buffer.allocation);
  878. for (IndirectBatch& draw : draws)
  879. {
  880. // Bind pipeline
  881. vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, draw.material->pipeline);
  882. #pragma region Bind Descriptors
  883. uint32_t uniformOffset = pad_uniform_buffer_size(sizeof(GPUSceneData)) * frameIndex;
  884. // Bind global descriptor
  885. vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
  886. draw.material->pipeline_layout, 0, 1, &get_current_frame().global_descriptor, 1, &uniformOffset);
  887. // Bind object descriptor
  888. vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
  889. draw.material->pipeline_layout, 1, 1, &get_current_frame().object_descriptor, 0, nullptr);
  890. // Bind texture descriptor (if applicable)
  891. if (draw.material->texture_set != VK_NULL_HANDLE)
  892. vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, draw.material->pipeline_layout, 2, 1, &draw.material->texture_set, 0, nullptr);
  893. #pragma endregion
  894. // Bind mesh
  895. VkDeviceSize offset{ 0 };
  896. vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &draw.mesh->vertexBuffer.buffer, &offset);
  897. uint32_t draw_stride = sizeof(VkDrawIndirectCommand);
  898. VkDeviceSize indirectOffset = draw.first * draw_stride;
  899. vkCmdDrawIndirect(cmdBuffer, get_current_frame().indirect_buffer.buffer, indirectOffset, draw.count, draw_stride);
  900. }
  901. //Mesh* lastMesh = nullptr;
  902. //Material* lastMaterial = nullptr;
  903. //for (int i = 0; i < count; i++)
  904. //{
  905. // RenderObject& object = first[i];
  906. // // Only bind pipeline if it doesn't match with already bound one
  907. // if (object.material != lastMaterial)
  908. // {
  909. // vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, object.material->pipeline);
  910. // lastMaterial = object.material;
  911. // // Offset in scene buffer to access current frame data
  912. // uint32_t uniformOffset = pad_uniform_buffer_size(sizeof(GPUSceneData)) * frameIndex;
  913. // vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, object.material->pipeline_layout, 0, 1, &get_current_frame().global_descriptor, 1, &uniformOffset);
  914. //
  915. // // Object data descriptor
  916. // vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, object.material->pipeline_layout, 1, 1, &get_current_frame().object_descriptor, 0, nullptr);
  917. //
  918. // if (object.material->texture_set != VK_NULL_HANDLE)
  919. // vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, object.material->pipeline_layout, 2, 1, &object.material->texture_set, 0, nullptr);
  920. // }
  921. // // Only bind mesh if it's different from last bind
  922. // if (object.mesh != lastMesh)
  923. // {
  924. // // Bind the mesh vertex buffer with offset 0
  925. // VkDeviceSize offset{ 0 };
  926. // vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &object.mesh->vertexBuffer.buffer, &offset);
  927. // lastMesh = object.mesh;
  928. // }
  929. // vkCmdDraw(cmdBuffer, object.mesh->vertices.size(), 1, 0, i);
  930. //}
  931. }
  932. void VulkanEngine::init_scene()
  933. {
  934. Material* defaultMaterial = get_material("defaultmesh");
  935. VkSamplerCreateInfo samplerInfo{ vkinit::sampler_ci(VK_FILTER_NEAREST) };
  936. VkSampler nearesetSampler;
  937. vkCreateSampler(m_Device, &samplerInfo, nullptr, &nearesetSampler);
  938. // Allocate descriptor set for texture to use on the material
  939. VkDescriptorSetAllocateInfo allocInfo{};
  940. allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  941. allocInfo.pNext = nullptr;
  942. allocInfo.descriptorPool = m_DescriptorPool;
  943. allocInfo.descriptorSetCount = 1;
  944. allocInfo.pSetLayouts = &m_SingleTextureSetLayout;
  945. vkAllocateDescriptorSets(m_Device, &allocInfo, &defaultMaterial->texture_set);
  946. // Make descriptor set point to texture
  947. VkDescriptorImageInfo imageBufferInfo{};
  948. imageBufferInfo.sampler = nearesetSampler;
  949. imageBufferInfo.imageView = m_LoadedTextures["checker_diffuse"].image_view;
  950. imageBufferInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  951. VkWriteDescriptorSet texture{ vkinit::write_descriptor_image(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, defaultMaterial->texture_set, &imageBufferInfo, 0) };
  952. vkUpdateDescriptorSets(m_Device, 1, &texture, 0, nullptr);
  953. //RenderObject map;
  954. //map.mesh = get_mesh("empire");
  955. //map.material = get_material("defaultmesh");
  956. //map.transform = glm::translate(glm::vec3{5, -10, 0});
  957. //std::cout << std::setprecision(10) << "Number of triangles: " << map.mesh->vertices.size() << "\n";
  958. //m_Renderables.emplace_back(map);
  959. Mesh* teapotMesh = get_mesh("Teapot");
  960. const int vertCount = teapotMesh->vertices.size();
  961. constexpr int numObjects = 2;
  962. for (int x = -numObjects * 0.5f; x < numObjects * 0.5f; x++)
  963. {
  964. for (int y = -numObjects * 0.5f; y < numObjects * 0.5f; y++)
  965. {
  966. RenderObject teapot;
  967. teapot.mesh = teapotMesh;
  968. teapot.material = defaultMaterial;
  969. teapot.transform = glm::translate(glm::mat4{1.0f}, glm::vec3(x * 40.f, 0, y * 40.f)) * glm::rotate(glm::radians(-90.f), glm::vec3{1, 0, 0});
  970. m_Renderables.push_back(teapot);
  971. }
  972. }
  973. // Scene data
  974. m_GPUSceneData.ambient_color = { 0.625f, 0.0f, 0.24f, 0.1f };
  975. m_GPUSceneData.light_direction = { -0.577f, -0.577f, 0.577f, 1.f };
  976. std::cout << "Number of renderables: " << m_Renderables.size() << "\n";
  977. std::cout << std::setprecision(0) << "Number of triangles: " << (m_Renderables.size() * vertCount) / 3 << "\n";
  978. }