일단 완성
This commit is contained in:
		| @@ -6,8 +6,6 @@ find_package(Vulkan REQUIRED) | |||||||
| include(cmake/Shaders.cmake) | include(cmake/Shaders.cmake) | ||||||
| include(FetchContent) | include(FetchContent) | ||||||
|  |  | ||||||
| set(FMT_HEADER_ONLY ON) |  | ||||||
|  |  | ||||||
| FetchContent_Declare( | FetchContent_Declare( | ||||||
|     glm |     glm | ||||||
|     GIT_REPOSITORY "https://github.com/g-truc/glm.git" |     GIT_REPOSITORY "https://github.com/g-truc/glm.git" | ||||||
| @@ -65,3 +63,5 @@ file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS | |||||||
|  |  | ||||||
| add_shaders(VulkanEngineShaders ${ShaderSources}) | add_shaders(VulkanEngineShaders ${ShaderSources}) | ||||||
| add_dependencies(VulkanEngine VulkanEngineShaders) | add_dependencies(VulkanEngine VulkanEngineShaders) | ||||||
|  |  | ||||||
|  | file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/assets/paving-stones.jpg" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/assets") | ||||||
							
								
								
									
										15
									
								
								CMakeSettings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								CMakeSettings.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | { | ||||||
|  |   "configurations": [ | ||||||
|  |     { | ||||||
|  |       "name": "x64-Debug", | ||||||
|  |       "generator": "Ninja", | ||||||
|  |       "configurationType": "Debug", | ||||||
|  |       "inheritEnvironments": [ "msvc_x64_x64" ], | ||||||
|  |       "buildRoot": "${projectDir}\\out\\build\\${name}", | ||||||
|  |       "installRoot": "${projectDir}\\out\\install\\${name}", | ||||||
|  |       "cmakeCommandArgs": "", | ||||||
|  |       "buildCommandArgs": "", | ||||||
|  |       "ctestCommandArgs": "" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/paving-stones.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/paving-stones.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.7 MiB | 
							
								
								
									
										8422
									
								
								include/stb/stb_image.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8422
									
								
								include/stb/stb_image.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								include/vulkan/buffer_handle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								include/vulkan/buffer_handle.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  |  | ||||||
|  | struct BufferHandle { | ||||||
|  |   VkBuffer buffer = VK_NULL_HANDLE; | ||||||
|  |   VkDeviceMemory memory = VK_NULL_HANDLE; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
| @@ -1,15 +1,33 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include <vulkan/vulkan.h> | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | #include "buffer_handle.h" | ||||||
| #include "glfw/glfw_window.h" | #include "glfw/glfw_window.h" | ||||||
| #include "precomp.h" | #include "precomp.h" | ||||||
|  | #include "texture_handle.h" | ||||||
|  | #include "vertex.h" | ||||||
|  |  | ||||||
| namespace veng { | namespace veng { | ||||||
| class Graphics final { | class Graphics final { | ||||||
|  public: |  public: | ||||||
|   Graphics(gsl::not_null<Window *> window); |   Graphics(gsl::not_null<Window*> window); | ||||||
|   ~Graphics(); |   ~Graphics(); | ||||||
|  |  | ||||||
|  |   bool BeginFrame(); | ||||||
|  |   void SetModelMatrix(glm::mat4 model); | ||||||
|  |   void SetViewProjection(glm::mat4 view, glm::mat4 projection); | ||||||
|  |   void SetTexture(TextureHandle handle); | ||||||
|  |   void RenderBuffer(BufferHandle handle, std::uint32_t vertex_count); | ||||||
|  |   void RenderIndexedBuffer(BufferHandle vertex_buffer, | ||||||
|  |                            BufferHandle index_buffer, std::uint32_t count); | ||||||
|  |   void EndFrame(); | ||||||
|  |  | ||||||
|  |   BufferHandle CreateVertexBuffer(gsl::span<Vertex> vertices); | ||||||
|  |   BufferHandle CreateIndexBuffer(gsl::span<std::uint32_t> indices); | ||||||
|  |   void DestroyBuffer(BufferHandle handle); | ||||||
|  |   TextureHandle CreateTexture(gsl::czstring path); | ||||||
|  |   void DestroyTexture(TextureHandle handle); | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   struct QueueFamilyIndices { |   struct QueueFamilyIndices { | ||||||
|     std::optional<std::uint32_t> graphics_family = std::nullopt; |     std::optional<std::uint32_t> graphics_family = std::nullopt; | ||||||
| @@ -28,6 +46,8 @@ class Graphics final { | |||||||
|     bool IsValid() const { return !formats.empty() && !present_modes.empty(); } |     bool IsValid() const { return !formats.empty() && !present_modes.empty(); } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   // 초기화 | ||||||
|  |  | ||||||
|   void InitializeVulkan(); |   void InitializeVulkan(); | ||||||
|   void CreateInstance(); |   void CreateInstance(); | ||||||
|   void SetupDebugMessenger(); |   void SetupDebugMessenger(); | ||||||
| @@ -38,6 +58,22 @@ class Graphics final { | |||||||
|   void CreateImageViews(); |   void CreateImageViews(); | ||||||
|   void CreateRenderPass(); |   void CreateRenderPass(); | ||||||
|   void CreateGraphicsPipeline(); |   void CreateGraphicsPipeline(); | ||||||
|  |   void CreateFramebuffers(); | ||||||
|  |   void CreateCommandPool(); | ||||||
|  |   void CreateCommandBuffer(); | ||||||
|  |   void CreateSignals(); | ||||||
|  |   void CreateDescriptorSetLayouts(); | ||||||
|  |   void CreateDescriptorPools(); | ||||||
|  |   void CreateDescriptorSets(); | ||||||
|  |   void CreateTextureSampler(); | ||||||
|  |  | ||||||
|  |   void RecreateSwapChain(); | ||||||
|  |   void CleanupSwapChain(); | ||||||
|  |  | ||||||
|  |   // 랜더링 | ||||||
|  |  | ||||||
|  |   void BeginCommands(); | ||||||
|  |   void EndCommands(); | ||||||
|  |  | ||||||
|   std::vector<gsl::czstring> GetRequiredInstanceExtentions(); |   std::vector<gsl::czstring> GetRequiredInstanceExtentions(); | ||||||
|  |  | ||||||
| @@ -61,10 +97,29 @@ class Graphics final { | |||||||
|   VkPresentModeKHR ChooseSwapPresentMode( |   VkPresentModeKHR ChooseSwapPresentMode( | ||||||
|       gsl::span<VkPresentModeKHR> present_modes); |       gsl::span<VkPresentModeKHR> present_modes); | ||||||
|   VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); |   VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); | ||||||
|   std::uint32_t ChooseSwapImageCount(const VkSurfaceCapabilitiesKHR& capabilities); |   std::uint32_t ChooseSwapImageCount( | ||||||
|  |       const VkSurfaceCapabilitiesKHR& capabilities); | ||||||
|  |  | ||||||
|   VkShaderModule CreateShaderModule(gsl::span<std::uint8_t> buffer); |   VkShaderModule CreateShaderModule(gsl::span<std::uint8_t> buffer); | ||||||
|  |  | ||||||
|  |   std::uint32_t FindMemoryType(std::uint32_t type_bits_filter, | ||||||
|  |                                VkMemoryPropertyFlags required_properties); | ||||||
|  |  | ||||||
|  |   BufferHandle CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, | ||||||
|  |                             VkMemoryPropertyFlags properties); | ||||||
|  |   VkCommandBuffer BeginTransientCommandBuffer(); | ||||||
|  |   void EndTransientCommandBuffer(VkCommandBuffer command_buffer); | ||||||
|  |   void CreateUniformBuffers(); | ||||||
|  |  | ||||||
|  |   TextureHandle CreateImage(glm::ivec2 size, VkBufferUsageFlags usage, | ||||||
|  |                             VkMemoryPropertyFlags properties); | ||||||
|  |   void TransitionImageLayout(VkImage image, VkImageLayout old_layout, VkImageLayout new_layout); | ||||||
|  |   void CopyBufferToImage(VkBuffer buffer, VkImage image, glm::ivec2 image_size); | ||||||
|  |   VkImageView CreateImageView(VkImage image, VkFormat format); | ||||||
|  |  | ||||||
|  |   VkViewport GetViewport(); | ||||||
|  |   VkRect2D GetScissor(); | ||||||
|  |  | ||||||
|   std::array<gsl::czstring, 1> required_device_extentions_ = { |   std::array<gsl::czstring, 1> required_device_extentions_ = { | ||||||
|       VK_KHR_SWAPCHAIN_EXTENSION_NAME}; |       VK_KHR_SWAPCHAIN_EXTENSION_NAME}; | ||||||
|  |  | ||||||
| @@ -81,14 +136,36 @@ class Graphics final { | |||||||
|   VkSurfaceFormatKHR surface_format_; |   VkSurfaceFormatKHR surface_format_; | ||||||
|   VkPresentModeKHR present_mode_; |   VkPresentModeKHR present_mode_; | ||||||
|   VkExtent2D extent_; |   VkExtent2D extent_; | ||||||
|  |  | ||||||
|   std::vector<VkImage> swap_chain_images_; |   std::vector<VkImage> swap_chain_images_; | ||||||
|   std::vector<VkImageView> swap_chain_image_views_; |   std::vector<VkImageView> swap_chain_image_views_; | ||||||
|  |   std::vector<VkFramebuffer> swap_chain_framebuffers_; | ||||||
|  |  | ||||||
|   VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; |   VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; | ||||||
|   VkRenderPass render_pass_ = VK_NULL_HANDLE; |   VkRenderPass render_pass_ = VK_NULL_HANDLE; | ||||||
|   VkPipeline pipeline_ = VK_NULL_HANDLE; |   VkPipeline pipeline_ = VK_NULL_HANDLE; | ||||||
|  |   VkDescriptorSetLayout descriptor_set_layout_ = VK_NULL_HANDLE; | ||||||
|  |  | ||||||
|   gsl::not_null<Window *> window_; |   VkCommandPool command_pool_ = VK_NULL_HANDLE; | ||||||
|  |   VkCommandBuffer command_buffer_ = VK_NULL_HANDLE; | ||||||
|  |  | ||||||
|  |   VkSemaphore image_available_signal_ = VK_NULL_HANDLE; | ||||||
|  |   VkSemaphore render_finished_signal_ = VK_NULL_HANDLE; | ||||||
|  |   VkFence still_rendering_fence_ = VK_NULL_HANDLE; | ||||||
|  |  | ||||||
|  |   std::uint32_t current_image_index_ = 0; | ||||||
|  |  | ||||||
|  |   VkDescriptorSetLayout uniform_set_layout_ = VK_NULL_HANDLE; | ||||||
|  |   VkDescriptorPool uniform_pool_ = VK_NULL_HANDLE; | ||||||
|  |   VkDescriptorSet uniform_set_ = VK_NULL_HANDLE; | ||||||
|  |   BufferHandle uniform_buffer_; | ||||||
|  |   void* uniform_buffer_location_; | ||||||
|  |  | ||||||
|  |   VkDescriptorSetLayout texture_set_layout_ = VK_NULL_HANDLE; | ||||||
|  |   VkDescriptorPool texture_pool_ = VK_NULL_HANDLE; | ||||||
|  |   VkSampler texture_sampler_ = VK_NULL_HANDLE; | ||||||
|  |  | ||||||
|  |   gsl::not_null<Window*> window_; | ||||||
|   bool validation_enabled_ = false; |   bool validation_enabled_ = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								include/vulkan/texture_handle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								include/vulkan/texture_handle.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  |  | ||||||
|  | struct TextureHandle { | ||||||
|  |   VkImage image = VK_NULL_HANDLE; | ||||||
|  |   VkImageView image_view = VK_NULL_HANDLE; | ||||||
|  |   VkDeviceMemory memory = VK_NULL_HANDLE; | ||||||
|  |   VkDescriptorSet set = VK_NULL_HANDLE; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
							
								
								
									
										8
									
								
								include/vulkan/uniform_transformations.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								include/vulkan/uniform_transformations.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  | struct UniformTransformations { | ||||||
|  |   glm::mat4 view; | ||||||
|  |   glm::mat4 projection; | ||||||
|  | }; | ||||||
|  | }  // namespace veng | ||||||
							
								
								
									
										38
									
								
								include/vulkan/vertex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								include/vulkan/vertex.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  | struct Vertex { | ||||||
|  |   Vertex() : position(glm::vec3(0.f)), uv(glm::vec2(0.f)) {} | ||||||
|  |   Vertex(glm::vec3 _position, glm::vec2 _uv) : position(_position), uv(_uv) {} | ||||||
|  |  | ||||||
|  |   glm::vec3 position; | ||||||
|  |   glm::vec2 uv; | ||||||
|  |  | ||||||
|  |   static VkVertexInputBindingDescription GetBindingDescription() { | ||||||
|  |     VkVertexInputBindingDescription description = {}; | ||||||
|  |     description.binding = 0; | ||||||
|  |     description.stride = sizeof(Vertex); | ||||||
|  |     description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | ||||||
|  |  | ||||||
|  |     return description; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static std::array<VkVertexInputAttributeDescription, 2> GetAttributeDescriptions() { | ||||||
|  |     std::array<VkVertexInputAttributeDescription, 2> descriptions = {}; | ||||||
|  |  | ||||||
|  |     descriptions[0].binding = 0; | ||||||
|  |     descriptions[0].location = 0; | ||||||
|  |     descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; | ||||||
|  |     descriptions[0].offset = offsetof(Vertex, position); | ||||||
|  |  | ||||||
|  |     descriptions[1].binding = 0; | ||||||
|  |     descriptions[1].location = 1; | ||||||
|  |     descriptions[1].format = VK_FORMAT_R32G32_SFLOAT; | ||||||
|  |     descriptions[1].offset = offsetof(Vertex, uv); | ||||||
|  |  | ||||||
|  |     return descriptions; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | }  // namespace veng | ||||||
| @@ -1,7 +1,11 @@ | |||||||
| #version 450 | #version 450 | ||||||
|  | #include "common.glsl" | ||||||
|  |  | ||||||
|  | layout(location = 0) in vec2 vertex_uv; | ||||||
| layout(location = 0) out vec4 out_color; | layout(location = 0) out vec4 out_color; | ||||||
|  |  | ||||||
|  | layout(set = 1, binding = 0) uniform sampler2D texture_sampler; | ||||||
|  |  | ||||||
| void main() { | void main() { | ||||||
| 	out_color = vec4(1.0, 0.0, 0.5, 1.0); | 	out_color = texture(texture_sampler, vertex_uv); | ||||||
| } | } | ||||||
| @@ -1,13 +1,16 @@ | |||||||
| #version 450 | #version 450 | ||||||
| #include "common.glsl" | #include "common.glsl" | ||||||
|  |  | ||||||
| vec2 hardcoded_positions[3] = vec2[]( | layout(location = 0) in vec3 input_position; | ||||||
|     vec2(0.0, -0.5), | layout(location = 1) in vec2 input_uv; | ||||||
|     vec2(0.5, 0.5), |  | ||||||
|     vec2(-0.5, 0.5) | layout(location = 0) out vec2 vertex_uv; | ||||||
| ); |  | ||||||
|  | layout(push_constant) uniform Model { | ||||||
|  |     mat4 transformation; | ||||||
|  | } model; | ||||||
|  |  | ||||||
| void main() { | void main() { | ||||||
|     vec2 current_Position = hardcoded_positions[gl_VertexIndex]; |     gl_Position = camera.projection * camera.view * model.transformation * vec4(input_position, 1.0); | ||||||
|     gl_Position = vec4(current_Position, 0.0, 1.0); |     vertex_uv = input_uv; | ||||||
| } | } | ||||||
| @@ -1 +1,7 @@ | |||||||
| #extension GL_KHR_vulkan_glsl : enable | #extension GL_KHR_vulkan_glsl : enable | ||||||
|  |  | ||||||
|  | layout(set = 0, binding = 0) uniform UniformTransformations { | ||||||
|  |   mat4 view; | ||||||
|  |   mat4 projection; | ||||||
|  | } | ||||||
|  | camera; | ||||||
| @@ -7,7 +7,7 @@ | |||||||
| namespace veng { | namespace veng { | ||||||
|  |  | ||||||
| Window::Window(gsl::czstring name, glm::ivec2 size) { | Window::Window(gsl::czstring name, glm::ivec2 size) { | ||||||
|   glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); |   // glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); | ||||||
|   glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); |   glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | ||||||
|  |  | ||||||
|   window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr); |   window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr); | ||||||
|   | |||||||
							
								
								
									
										47
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -1,10 +1,15 @@ | |||||||
| #include <GLFW/glfw3.h> | #include <GLFW/glfw3.h> | ||||||
|  |  | ||||||
|  | #include <glm/gtc/matrix_transform.hpp> | ||||||
|  |  | ||||||
| #include "glfw/glfw_initialization.h" | #include "glfw/glfw_initialization.h" | ||||||
| #include "glfw/glfw_monitor.h" | #include "glfw/glfw_monitor.h" | ||||||
| #include "glfw/glfw_window.h" | #include "glfw/glfw_window.h" | ||||||
|  | #include "precomp.h" | ||||||
| #include "vulkan/graphics.h" | #include "vulkan/graphics.h" | ||||||
|  |  | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
| std::int32_t main(std::int32_t argc, gsl::zstring* argv) { | std::int32_t main(std::int32_t argc, gsl::zstring* argv) { | ||||||
|   const veng::GlfwInitialization _glfw; |   const veng::GlfwInitialization _glfw; | ||||||
|  |  | ||||||
| @@ -13,9 +18,51 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) { | |||||||
|  |  | ||||||
|   veng::Graphics graphics(&window); |   veng::Graphics graphics(&window); | ||||||
|  |  | ||||||
|  |   std::array<veng::Vertex, 4> vertices = { | ||||||
|  |       veng::Vertex{{-.5f, -.5f, 0.f}, {0.f, 1.f}}, | ||||||
|  |       veng::Vertex{{.5f, -.5f, 0.f}, {1.f, 1.f}}, | ||||||
|  |       veng::Vertex{{-.5f, .5f, 0.f}, {0.f, 0.f}}, | ||||||
|  |       veng::Vertex{{.5f, .5f, 0.f}, {1.f, 0.f}}}; | ||||||
|  |   veng::BufferHandle buffer = graphics.CreateVertexBuffer(vertices); | ||||||
|  |  | ||||||
|  |   std::array<std::uint32_t, 6> indices = {0, 3, 2, 0, 1, 3}; | ||||||
|  |   veng::BufferHandle index_buffer = graphics.CreateIndexBuffer(indices); | ||||||
|  |  | ||||||
|  |   glm::mat4 rotation = glm::rotate(glm::mat4(1.0f), glm::radians(45.f), | ||||||
|  |                                    glm::vec3(0.f, 1.f, 0.f)); | ||||||
|  |   glm::mat4 view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -2.f)); | ||||||
|  |   glm::mat4 projection = | ||||||
|  |       glm::perspective(glm::radians(60.f), 800.f / 600.f, 0.1f, 100.f); | ||||||
|  |   graphics.SetViewProjection(view, projection); | ||||||
|  |  | ||||||
|  |   veng::TextureHandle texture = graphics.CreateTexture("assets/paving-stones.jpg"); | ||||||
|  |  | ||||||
|  |   double last_time = glfwGetTime(); | ||||||
|  |  | ||||||
|   while (!window.ShouldClose()) { |   while (!window.ShouldClose()) { | ||||||
|     glfwPollEvents(); |     glfwPollEvents(); | ||||||
|  |  | ||||||
|  |     if (graphics.BeginFrame()) { | ||||||
|  |       double current_time = glfwGetTime(); | ||||||
|  |       float delta_time = static_cast<float>(current_time - last_time); | ||||||
|  |       last_time = current_time; | ||||||
|  |  | ||||||
|  |       std::cout << 1.f / delta_time << std::endl; | ||||||
|  |  | ||||||
|  |       graphics.SetTexture(texture); | ||||||
|  |       graphics.RenderIndexedBuffer(buffer, index_buffer, indices.size()); | ||||||
|  |       rotation = glm::rotate(rotation, delta_time * glm::radians(3600.f), | ||||||
|  |                              glm::vec3(0.f, 0.f, 1.f)); | ||||||
|  |       graphics.SetModelMatrix(rotation); | ||||||
|  |       graphics.RenderIndexedBuffer(buffer, index_buffer, indices.size()); | ||||||
|  |  | ||||||
|  |       graphics.EndFrame(); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   graphics.DestroyTexture(texture); | ||||||
|  |   graphics.DestroyBuffer(buffer); | ||||||
|  |   graphics.DestroyBuffer(index_buffer); | ||||||
|  |  | ||||||
|   return EXIT_SUCCESS; |   return EXIT_SUCCESS; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								src/stb/stb_image.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/stb/stb_image.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | #define STB_IMAGE_IMPLEMENTATION | ||||||
|  | #include "stb/stb_image.h" | ||||||
							
								
								
									
										314
									
								
								src/vulkan/buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								src/vulkan/buffers.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | |||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | #include "precomp.h" | ||||||
|  | #include "vulkan/graphics.h" | ||||||
|  | #include "vulkan/uniform_transformations.h" | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  |  | ||||||
|  | std::uint32_t Graphics::FindMemoryType( | ||||||
|  |     std::uint32_t type_bits_filter, VkMemoryPropertyFlags required_properties) { | ||||||
|  |   VkPhysicalDeviceMemoryProperties memory_properties; | ||||||
|  |   vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties); | ||||||
|  |   gsl::span<VkMemoryType> memory_types(memory_properties.memoryTypes, | ||||||
|  |                                        memory_properties.memoryTypeCount); | ||||||
|  |  | ||||||
|  |   for (std::uint32_t i = 0; i < memory_types.size(); i++) { | ||||||
|  |     bool passes_filter = type_bits_filter & (1 << i); | ||||||
|  |     bool has_property_flags = | ||||||
|  |         memory_types[i].propertyFlags & required_properties; | ||||||
|  |  | ||||||
|  |     if (passes_filter && has_property_flags) return i; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   throw std::runtime_error("Cannot find memory type!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BufferHandle Graphics::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, | ||||||
|  |                                     VkMemoryPropertyFlags properties) { | ||||||
|  |   BufferHandle handle = {}; | ||||||
|  |  | ||||||
|  |   VkBufferCreateInfo buffer_info = {}; | ||||||
|  |   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | ||||||
|  |   buffer_info.size = size; | ||||||
|  |   buffer_info.usage = usage; | ||||||
|  |   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | ||||||
|  |  | ||||||
|  |   VkResult result = | ||||||
|  |       vkCreateBuffer(logical_device_, &buffer_info, nullptr, &handle.buffer); | ||||||
|  |   if (result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to create vertex buffer!"); | ||||||
|  |  | ||||||
|  |   VkMemoryRequirements memory_requirements; | ||||||
|  |   vkGetBufferMemoryRequirements(logical_device_, handle.buffer, | ||||||
|  |                                 &memory_requirements); | ||||||
|  |  | ||||||
|  |   std::uint32_t chosen_memory_type = | ||||||
|  |       FindMemoryType(memory_requirements.memoryTypeBits, properties); | ||||||
|  |  | ||||||
|  |   VkMemoryAllocateInfo allocation_info = {}; | ||||||
|  |   allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | ||||||
|  |   allocation_info.allocationSize = memory_requirements.size; | ||||||
|  |   allocation_info.memoryTypeIndex = chosen_memory_type; | ||||||
|  |  | ||||||
|  |   VkResult allocation_result = vkAllocateMemory( | ||||||
|  |       logical_device_, &allocation_info, nullptr, &handle.memory); | ||||||
|  |   if (allocation_result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to allocate buffer memory!"); | ||||||
|  |  | ||||||
|  |   vkBindBufferMemory(logical_device_, handle.buffer, handle.memory, 0); | ||||||
|  |  | ||||||
|  |   return handle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BufferHandle Graphics::CreateVertexBuffer(gsl::span<Vertex> vertices) { | ||||||
|  |   VkDeviceSize size = sizeof(Vertex) * vertices.size(); | ||||||
|  |   BufferHandle staging_handle = CreateBuffer( | ||||||
|  |       size, | ||||||
|  |       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | ||||||
|  |       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||||||
|  |           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||||
|  |  | ||||||
|  |   void* data; | ||||||
|  |   vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data); | ||||||
|  |   std::memcpy(data, vertices.data(), size); | ||||||
|  |   vkUnmapMemory(logical_device_, staging_handle.memory); | ||||||
|  |  | ||||||
|  |   BufferHandle gpu_handle = CreateBuffer( | ||||||
|  |       size, | ||||||
|  |       VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||||||
|  |       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||||
|  |  | ||||||
|  |   VkCommandBuffer transient_commands = BeginTransientCommandBuffer(); | ||||||
|  |  | ||||||
|  |   VkBufferCopy copy_info = {}; | ||||||
|  |   copy_info.srcOffset = 0; | ||||||
|  |   copy_info.dstOffset = 0; | ||||||
|  |   copy_info.size = size; | ||||||
|  |   vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer, | ||||||
|  |                   1, ©_info); | ||||||
|  |  | ||||||
|  |   EndTransientCommandBuffer(transient_commands); | ||||||
|  |  | ||||||
|  |   DestroyBuffer(staging_handle); | ||||||
|  |  | ||||||
|  |   return gpu_handle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | BufferHandle Graphics::CreateIndexBuffer(gsl::span<std::uint32_t> indices) { | ||||||
|  |   VkDeviceSize size = sizeof(std::uint32_t) * indices.size(); | ||||||
|  |   BufferHandle staging_handle = | ||||||
|  |       CreateBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | ||||||
|  |                    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||||||
|  |                        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||||
|  |  | ||||||
|  |   void* data; | ||||||
|  |   vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data); | ||||||
|  |   std::memcpy(data, indices.data(), size); | ||||||
|  |   vkUnmapMemory(logical_device_, staging_handle.memory); | ||||||
|  |  | ||||||
|  |   BufferHandle gpu_handle = CreateBuffer( | ||||||
|  |       size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, | ||||||
|  |       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||||
|  |  | ||||||
|  |   VkCommandBuffer transient_commands = BeginTransientCommandBuffer(); | ||||||
|  |  | ||||||
|  |   VkBufferCopy copy_info = {}; | ||||||
|  |   copy_info.srcOffset = 0; | ||||||
|  |   copy_info.dstOffset = 0; | ||||||
|  |   copy_info.size = size; | ||||||
|  |   vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer, | ||||||
|  |                   1, ©_info); | ||||||
|  |  | ||||||
|  |   EndTransientCommandBuffer(transient_commands); | ||||||
|  |  | ||||||
|  |   DestroyBuffer(staging_handle); | ||||||
|  |  | ||||||
|  |   return gpu_handle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::DestroyBuffer(BufferHandle handle) { | ||||||
|  |   vkDeviceWaitIdle(logical_device_); | ||||||
|  |   vkDestroyBuffer(logical_device_, handle.buffer, nullptr); | ||||||
|  |   vkFreeMemory(logical_device_, handle.memory, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::SetModelMatrix(glm::mat4 model) { | ||||||
|  |   vkCmdPushConstants(command_buffer_, pipeline_layout_, | ||||||
|  |                      VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &model); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::SetViewProjection(glm::mat4 view, glm::mat4 projection) { | ||||||
|  |   UniformTransformations transformations{view, projection}; | ||||||
|  |   std::memcpy(uniform_buffer_location_, &transformations, | ||||||
|  |               sizeof(UniformTransformations)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::RenderBuffer(BufferHandle handle, std::uint32_t vertex_count) { | ||||||
|  |   VkDeviceSize offset = 0; | ||||||
|  |   vkCmdBindDescriptorSets(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, | ||||||
|  |                           pipeline_layout_, 0, 1, &uniform_set_, 0, nullptr); | ||||||
|  |   vkCmdBindVertexBuffers(command_buffer_, 0, 1, &handle.buffer, &offset); | ||||||
|  |   vkCmdDraw(command_buffer_, vertex_count, 1, 0, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::RenderIndexedBuffer(BufferHandle vertex_buffer, | ||||||
|  |                                    BufferHandle index_buffer, | ||||||
|  |                                    std::uint32_t count) { | ||||||
|  |   VkDeviceSize offset = 0; | ||||||
|  |   vkCmdBindDescriptorSets(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, | ||||||
|  |                           pipeline_layout_, 0, 1, &uniform_set_, 0, nullptr); | ||||||
|  |   vkCmdBindVertexBuffers(command_buffer_, 0, 1, &vertex_buffer.buffer, &offset); | ||||||
|  |   vkCmdBindIndexBuffer(command_buffer_, index_buffer.buffer, 0, | ||||||
|  |                        VK_INDEX_TYPE_UINT32); | ||||||
|  |   vkCmdDrawIndexed(command_buffer_, count, 1, 0, 0, 0); | ||||||
|  |   SetModelMatrix(glm::mat4(1.f)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VkCommandBuffer Graphics::BeginTransientCommandBuffer() { | ||||||
|  |   VkCommandBufferAllocateInfo allocation_info = {}; | ||||||
|  |   allocation_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; | ||||||
|  |   allocation_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; | ||||||
|  |   allocation_info.commandPool = command_pool_; | ||||||
|  |   allocation_info.commandBufferCount = 1; | ||||||
|  |  | ||||||
|  |   VkCommandBuffer buffer; | ||||||
|  |   vkAllocateCommandBuffers(logical_device_, &allocation_info, &buffer); | ||||||
|  |  | ||||||
|  |   VkCommandBufferBeginInfo begin_info = {}; | ||||||
|  |   begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | ||||||
|  |   begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; | ||||||
|  |   vkBeginCommandBuffer(buffer, &begin_info); | ||||||
|  |  | ||||||
|  |   return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::EndTransientCommandBuffer(VkCommandBuffer command_buffer) { | ||||||
|  |   vkEndCommandBuffer(command_buffer); | ||||||
|  |  | ||||||
|  |   VkSubmitInfo submit_info = {}; | ||||||
|  |   submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | ||||||
|  |   submit_info.commandBufferCount = 1; | ||||||
|  |   submit_info.pCommandBuffers = &command_buffer; | ||||||
|  |  | ||||||
|  |   vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE); | ||||||
|  |   vkQueueWaitIdle(graphics_queue_); | ||||||
|  |   vkFreeCommandBuffers(logical_device_, command_pool_, 1, &command_buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateUniformBuffers() { | ||||||
|  |   VkDeviceSize buffer_size = sizeof(UniformTransformations); | ||||||
|  |   uniform_buffer_ = | ||||||
|  |       CreateBuffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | ||||||
|  |                    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||||||
|  |                        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||||
|  |  | ||||||
|  |   vkMapMemory(logical_device_, uniform_buffer_.memory, 0, buffer_size, 0, | ||||||
|  |               &uniform_buffer_location_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateDescriptorSetLayouts() { | ||||||
|  |   VkDescriptorSetLayoutBinding uniform_layout_binding = {}; | ||||||
|  |   uniform_layout_binding.binding = 0; | ||||||
|  |   uniform_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | ||||||
|  |   uniform_layout_binding.descriptorCount = 1; | ||||||
|  |   uniform_layout_binding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; | ||||||
|  |  | ||||||
|  |   VkDescriptorSetLayoutCreateInfo uniform_layout_info = {}; | ||||||
|  |   uniform_layout_info.sType = | ||||||
|  |       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | ||||||
|  |   uniform_layout_info.bindingCount = 1; | ||||||
|  |   uniform_layout_info.pBindings = &uniform_layout_binding; | ||||||
|  |  | ||||||
|  |   if (vkCreateDescriptorSetLayout(logical_device_, &uniform_layout_info, | ||||||
|  |                                   nullptr, | ||||||
|  |                                   &uniform_set_layout_) != VK_SUCCESS) { | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   VkDescriptorSetLayoutBinding texture_layout_binding = {}; | ||||||
|  |   texture_layout_binding.binding = 0; | ||||||
|  |   texture_layout_binding.descriptorType = | ||||||
|  |       VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | ||||||
|  |   texture_layout_binding.descriptorCount = 1; | ||||||
|  |   texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; | ||||||
|  |  | ||||||
|  |   VkDescriptorSetLayoutCreateInfo texture_layout_info = {}; | ||||||
|  |   texture_layout_info.sType = | ||||||
|  |       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | ||||||
|  |   texture_layout_info.bindingCount = 1; | ||||||
|  |   texture_layout_info.pBindings = &texture_layout_binding; | ||||||
|  |  | ||||||
|  |   if (vkCreateDescriptorSetLayout(logical_device_, &texture_layout_info, | ||||||
|  |                                   nullptr, | ||||||
|  |                                   &texture_set_layout_) != VK_SUCCESS) { | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateDescriptorPools() { | ||||||
|  |   VkDescriptorPoolSize uniform_pool_size = {}; | ||||||
|  |   uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | ||||||
|  |   uniform_pool_size.descriptorCount = 1; | ||||||
|  |  | ||||||
|  |   VkDescriptorPoolCreateInfo uniform_create_info = {}; | ||||||
|  |   uniform_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | ||||||
|  |   uniform_create_info.poolSizeCount = 1; | ||||||
|  |   uniform_create_info.pPoolSizes = &uniform_pool_size; | ||||||
|  |   uniform_create_info.maxSets = 1; | ||||||
|  |  | ||||||
|  |   if (vkCreateDescriptorPool(logical_device_, &uniform_create_info, nullptr, | ||||||
|  |                              &uniform_pool_) != VK_SUCCESS) { | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   VkPhysicalDeviceProperties properties = {}; | ||||||
|  |   vkGetPhysicalDeviceProperties(physical_device_, &properties); | ||||||
|  |  | ||||||
|  |   VkDescriptorPoolSize texture_pool_size = {}; | ||||||
|  |   texture_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | ||||||
|  |   texture_pool_size.descriptorCount = | ||||||
|  |       properties.limits.maxSamplerAllocationCount; | ||||||
|  |  | ||||||
|  |   VkDescriptorPoolCreateInfo texture_create_info = {}; | ||||||
|  |   texture_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | ||||||
|  |   texture_create_info.poolSizeCount = 1; | ||||||
|  |   texture_create_info.pPoolSizes = &texture_pool_size; | ||||||
|  |   texture_create_info.maxSets = properties.limits.maxSamplerAllocationCount; | ||||||
|  |   texture_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; | ||||||
|  |  | ||||||
|  |   if (vkCreateDescriptorPool(logical_device_, &texture_create_info, nullptr, | ||||||
|  |                              &texture_pool_) != VK_SUCCESS) { | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateDescriptorSets() { | ||||||
|  |   VkDescriptorSetAllocateInfo set_info = {}; | ||||||
|  |   set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; | ||||||
|  |   set_info.descriptorPool = uniform_pool_; | ||||||
|  |   set_info.descriptorSetCount = 1; | ||||||
|  |   set_info.pSetLayouts = &uniform_set_layout_; | ||||||
|  |  | ||||||
|  |   VkResult result = | ||||||
|  |       vkAllocateDescriptorSets(logical_device_, &set_info, &uniform_set_); | ||||||
|  |   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); | ||||||
|  |  | ||||||
|  |   VkDescriptorBufferInfo buffer_info = {}; | ||||||
|  |   buffer_info.buffer = uniform_buffer_.buffer; | ||||||
|  |   buffer_info.offset = 0; | ||||||
|  |   buffer_info.range = sizeof(UniformTransformations); | ||||||
|  |  | ||||||
|  |   VkWriteDescriptorSet descriptor_write = {}; | ||||||
|  |   descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | ||||||
|  |   descriptor_write.dstSet = uniform_set_; | ||||||
|  |   descriptor_write.dstBinding = 0; | ||||||
|  |   descriptor_write.dstArrayElement = 0; | ||||||
|  |   descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | ||||||
|  |   descriptor_write.descriptorCount = 1; | ||||||
|  |   descriptor_write.pBufferInfo = &buffer_info; | ||||||
|  |  | ||||||
|  |   vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
							
								
								
									
										94
									
								
								src/vulkan/class.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/vulkan/class.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | #include <GLFW/glfw3.h> | ||||||
|  |  | ||||||
|  | #include "precomp.h" | ||||||
|  | #include "vulkan/graphics.h" | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  |  | ||||||
|  | Graphics::Graphics(gsl::not_null<Window*> window) : window_(window) { | ||||||
|  | #if !defined(NDEBUG) | ||||||
|  |   validation_enabled_ = true; | ||||||
|  | #endif | ||||||
|  |   InitializeVulkan(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Graphics::~Graphics() { | ||||||
|  |   if (logical_device_ != VK_NULL_HANDLE) { | ||||||
|  |     vkDeviceWaitIdle(logical_device_); | ||||||
|  |     CleanupSwapChain(); | ||||||
|  |  | ||||||
|  |     if (texture_pool_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyDescriptorPool(logical_device_, texture_pool_, nullptr); | ||||||
|  |  | ||||||
|  |     if (texture_set_layout_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyDescriptorSetLayout(logical_device_, texture_set_layout_, | ||||||
|  |                                    nullptr); | ||||||
|  |  | ||||||
|  |     if (texture_sampler_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroySampler(logical_device_, texture_sampler_, nullptr); | ||||||
|  |  | ||||||
|  |     if (uniform_pool_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyDescriptorPool(logical_device_, uniform_pool_, nullptr); | ||||||
|  |  | ||||||
|  |     DestroyBuffer(uniform_buffer_); | ||||||
|  |  | ||||||
|  |     if (uniform_set_layout_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyDescriptorSetLayout(logical_device_, uniform_set_layout_, | ||||||
|  |                                    nullptr); | ||||||
|  |  | ||||||
|  |     if (image_available_signal_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroySemaphore(logical_device_, image_available_signal_, nullptr); | ||||||
|  |  | ||||||
|  |     if (render_finished_signal_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroySemaphore(logical_device_, render_finished_signal_, nullptr); | ||||||
|  |  | ||||||
|  |     if (still_rendering_fence_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyFence(logical_device_, still_rendering_fence_, nullptr); | ||||||
|  |  | ||||||
|  |     if (command_pool_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyCommandPool(logical_device_, command_pool_, nullptr); | ||||||
|  |  | ||||||
|  |     if (logical_device_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyPipeline(logical_device_, pipeline_, nullptr); | ||||||
|  |  | ||||||
|  |     if (pipeline_layout_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyPipelineLayout(logical_device_, pipeline_layout_, nullptr); | ||||||
|  |  | ||||||
|  |     if (render_pass_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyRenderPass(logical_device_, render_pass_, nullptr); | ||||||
|  |  | ||||||
|  |     vkDestroyDevice(logical_device_, nullptr); | ||||||
|  |   } | ||||||
|  |   if (instance_ != VK_NULL_HANDLE) { | ||||||
|  |     if (surface_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroySurfaceKHR(instance_, surface_, nullptr); | ||||||
|  |  | ||||||
|  |     if (debug_messenger_ != VK_NULL_HANDLE) | ||||||
|  |       vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr); | ||||||
|  |  | ||||||
|  |     vkDestroyInstance(instance_, nullptr); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::InitializeVulkan() { | ||||||
|  |   CreateInstance(); | ||||||
|  |   SetupDebugMessenger(); | ||||||
|  |   CreateSurface(); | ||||||
|  |   PickPhysicalDevice(); | ||||||
|  |   CreateLogicalDeviceAndQueues(); | ||||||
|  |   CreateSwapChain(); | ||||||
|  |   CreateImageViews(); | ||||||
|  |   CreateRenderPass(); | ||||||
|  |   CreateDescriptorSetLayouts(); | ||||||
|  |   CreateGraphicsPipeline(); | ||||||
|  |   CreateFramebuffers(); | ||||||
|  |   CreateCommandPool(); | ||||||
|  |   CreateCommandBuffer(); | ||||||
|  |   CreateSignals(); | ||||||
|  |   CreateUniformBuffers(); | ||||||
|  |   CreateDescriptorPools(); | ||||||
|  |   CreateDescriptorSets(); | ||||||
|  |   CreateTextureSampler(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
							
								
								
									
										169
									
								
								src/vulkan/drawing.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/vulkan/drawing.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | #include <GLFW/glfw3.h> | ||||||
|  |  | ||||||
|  | #include "precomp.h" | ||||||
|  | #include "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++) { | ||||||
|  |     VkFramebufferCreateInfo info = {}; | ||||||
|  |     info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | ||||||
|  |     info.renderPass = render_pass_; | ||||||
|  |     info.attachmentCount = 1; | ||||||
|  |     info.pAttachments = &swap_chain_image_views_[i]; | ||||||
|  |     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; | ||||||
|  |  | ||||||
|  |   VkResult result = | ||||||
|  |       vkAllocateCommandBuffers(logical_device_, &info, &command_buffer_); | ||||||
|  |   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::BeginCommands() { | ||||||
|  |   vkResetCommandBuffer(command_buffer_, 0); | ||||||
|  |  | ||||||
|  |   VkCommandBufferBeginInfo begin_info = {}; | ||||||
|  |   begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | ||||||
|  |  | ||||||
|  |   VkResult result = vkBeginCommandBuffer(command_buffer_, &begin_info); | ||||||
|  |   if (result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to begin command buffer!"); | ||||||
|  |  | ||||||
|  |   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_; | ||||||
|  |  | ||||||
|  |   VkClearValue clear_color = {{{0.f, 0.f, 0.f, 1.f}}}; | ||||||
|  |   render_pass_begin_info.clearValueCount = 1; | ||||||
|  |   render_pass_begin_info.pClearValues = &clear_color; | ||||||
|  |  | ||||||
|  |   vkCmdBeginRenderPass(command_buffer_, &render_pass_begin_info, | ||||||
|  |                        VK_SUBPASS_CONTENTS_INLINE); | ||||||
|  |   vkCmdBindPipeline(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, | ||||||
|  |                     pipeline_); | ||||||
|  |   VkViewport viewport = GetViewport(); | ||||||
|  |   VkRect2D scissor = GetScissor(); | ||||||
|  |  | ||||||
|  |   vkCmdSetViewport(command_buffer_, 0, 1, &viewport); | ||||||
|  |   vkCmdSetScissor(command_buffer_, 0, 1, &scissor); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::EndCommands() { | ||||||
|  |   vkCmdEndRenderPass(command_buffer_); | ||||||
|  |   VkResult result = vkEndCommandBuffer(command_buffer_); | ||||||
|  |   if (result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to record command buffer!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateSignals() { | ||||||
|  |   VkSemaphoreCreateInfo semafore_info = {}; | ||||||
|  |   semafore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | ||||||
|  |  | ||||||
|  |   if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr, | ||||||
|  |                         &image_available_signal_) != VK_SUCCESS) | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr, | ||||||
|  |                         &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, | ||||||
|  |                     &still_rendering_fence_) != VK_SUCCESS) | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Graphics::BeginFrame() { | ||||||
|  |   vkWaitForFences(logical_device_, 1, &still_rendering_fence_, VK_TRUE, | ||||||
|  |                   UINT64_MAX); | ||||||
|  |   VkResult image_acquire_result = vkAcquireNextImageKHR( | ||||||
|  |       logical_device_, swap_chain_, UINT64_MAX, 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, &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 = &image_available_signal_; | ||||||
|  |   submit_info.pWaitDstStageMask = &wait_stage; | ||||||
|  |   submit_info.commandBufferCount = 1; | ||||||
|  |   submit_info.pCommandBuffers = &command_buffer_; | ||||||
|  |   submit_info.signalSemaphoreCount = 1; | ||||||
|  |   submit_info.pSignalSemaphores = &render_finished_signal_; | ||||||
|  |  | ||||||
|  |   VkResult submit_result = | ||||||
|  |       vkQueueSubmit(graphics_queue_, 1, &submit_info, 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 = &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!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
| @@ -8,52 +8,4 @@ | |||||||
|  |  | ||||||
| namespace veng { | namespace veng { | ||||||
|  |  | ||||||
| Graphics::Graphics(gsl::not_null<Window*> window) : window_(window) { |  | ||||||
| #if !defined(NDEBUG) |  | ||||||
|   validation_enabled_ = true; |  | ||||||
| #endif |  | ||||||
|   InitializeVulkan(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Graphics::~Graphics() { |  | ||||||
|   if (logical_device_ != VK_NULL_HANDLE) { |  | ||||||
|     if (logical_device_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroyPipeline(logical_device_, pipeline_, nullptr); |  | ||||||
|  |  | ||||||
|     if (pipeline_layout_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroyPipelineLayout(logical_device_, pipeline_layout_, nullptr); |  | ||||||
|  |  | ||||||
|     if (render_pass_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroyRenderPass(logical_device_, render_pass_, nullptr); |  | ||||||
|  |  | ||||||
|     for (VkImageView image_view : swap_chain_image_views_) |  | ||||||
|       vkDestroyImageView(logical_device_, image_view, nullptr); |  | ||||||
|  |  | ||||||
|     if (swap_chain_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroySwapchainKHR(logical_device_, swap_chain_, nullptr); |  | ||||||
|  |  | ||||||
|     vkDestroyDevice(logical_device_, nullptr); |  | ||||||
|   } |  | ||||||
|   if (instance_ != VK_NULL_HANDLE) { |  | ||||||
|     if (surface_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroySurfaceKHR(instance_, surface_, nullptr); |  | ||||||
|  |  | ||||||
|     if (debug_messenger_ != VK_NULL_HANDLE) |  | ||||||
|       vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr); |  | ||||||
|  |  | ||||||
|     vkDestroyInstance(instance_, nullptr); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void Graphics::InitializeVulkan() { |  | ||||||
|   CreateInstance(); |  | ||||||
|   SetupDebugMessenger(); |  | ||||||
|   CreateSurface(); |  | ||||||
|   PickPhysicalDevice(); |  | ||||||
|   CreateLogicalDeviceAndQueues(); |  | ||||||
|   CreateSwapChain(); |  | ||||||
|   CreateRenderPass(); |  | ||||||
|   CreateGraphicsPipeline(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| }  // namespace veng | }  // namespace veng | ||||||
|   | |||||||
| @@ -21,6 +21,26 @@ VkShaderModule Graphics::CreateShaderModule(gsl::span<std::uint8_t> buffer) { | |||||||
|   return shader_module; |   return shader_module; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | VkViewport Graphics::GetViewport() { | ||||||
|  |   VkViewport viewport = {}; | ||||||
|  |   viewport.x = 0.f; | ||||||
|  |   viewport.y = 0.f; | ||||||
|  |   viewport.width = static_cast<std::float_t>(extent_.width); | ||||||
|  |   viewport.height = static_cast<std::float_t>(extent_.height); | ||||||
|  |   viewport.minDepth = 0.f; | ||||||
|  |   viewport.maxDepth = 1.f; | ||||||
|  |  | ||||||
|  |   return viewport; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | VkRect2D Graphics::GetScissor() { | ||||||
|  |   VkRect2D scissor = {}; | ||||||
|  |   scissor.offset = {0, 0}; | ||||||
|  |   scissor.extent = extent_; | ||||||
|  |  | ||||||
|  |   return scissor; | ||||||
|  | } | ||||||
|  |  | ||||||
| void Graphics::CreateGraphicsPipeline() { | void Graphics::CreateGraphicsPipeline() { | ||||||
|   std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv"); |   std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv"); | ||||||
|   VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data); |   VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data); | ||||||
| @@ -62,17 +82,9 @@ void Graphics::CreateGraphicsPipeline() { | |||||||
|   dynamic_state_info.dynamicStateCount = dynamic_states.size(); |   dynamic_state_info.dynamicStateCount = dynamic_states.size(); | ||||||
|   dynamic_state_info.pDynamicStates = dynamic_states.data(); |   dynamic_state_info.pDynamicStates = dynamic_states.data(); | ||||||
|  |  | ||||||
|   VkViewport viewport = {}; |   VkViewport viewport = GetViewport(); | ||||||
|   viewport.x = 0.f; |  | ||||||
|   viewport.y = 0.f; |  | ||||||
|   viewport.width = static_cast<std::float_t>(extent_.width); |  | ||||||
|   viewport.height = static_cast<std::float_t>(extent_.height); |  | ||||||
|   viewport.minDepth = 0.f; |  | ||||||
|   viewport.maxDepth = 1.f; |  | ||||||
|  |  | ||||||
|   VkRect2D scissor = {}; |   VkRect2D scissor = GetScissor(); | ||||||
|   scissor.offset = {0, 0}; |  | ||||||
|   scissor.extent = extent_; |  | ||||||
|  |  | ||||||
|   VkPipelineViewportStateCreateInfo viewport_info = {}; |   VkPipelineViewportStateCreateInfo viewport_info = {}; | ||||||
|   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; |   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | ||||||
| @@ -81,11 +93,18 @@ void Graphics::CreateGraphicsPipeline() { | |||||||
|   viewport_info.scissorCount = 1; |   viewport_info.scissorCount = 1; | ||||||
|   viewport_info.pScissors = &scissor; |   viewport_info.pScissors = &scissor; | ||||||
|  |  | ||||||
|  |   auto vertex_binding_description = Vertex::GetBindingDescription(); | ||||||
|  |   auto vertex_attribute_descriptions = Vertex::GetAttributeDescriptions(); | ||||||
|  |  | ||||||
|   VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; |   VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; | ||||||
|   vertex_input_info.sType = |   vertex_input_info.sType = | ||||||
|       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; |       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | ||||||
|   vertex_input_info.vertexBindingDescriptionCount = 0; |   vertex_input_info.vertexBindingDescriptionCount = 1; | ||||||
|   vertex_input_info.vertexAttributeDescriptionCount = 0; |   vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description; | ||||||
|  |   vertex_input_info.vertexAttributeDescriptionCount = | ||||||
|  |       vertex_attribute_descriptions.size(); | ||||||
|  |   vertex_input_info.pVertexAttributeDescriptions = | ||||||
|  |       vertex_attribute_descriptions.data(); | ||||||
|  |  | ||||||
|   VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {}; |   VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {}; | ||||||
|   input_assembly_info.sType = |   input_assembly_info.sType = | ||||||
| @@ -111,10 +130,17 @@ void Graphics::CreateGraphicsPipeline() { | |||||||
|   multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; |   multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; | ||||||
|  |  | ||||||
|   VkPipelineColorBlendAttachmentState color_blend_attachment = {}; |   VkPipelineColorBlendAttachmentState color_blend_attachment = {}; | ||||||
|   color_blend_attachment.blendEnable = VK_FALSE; |  | ||||||
|   color_blend_attachment.colorWriteMask = |   color_blend_attachment.colorWriteMask = | ||||||
|       VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | |       VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | ||||||
|       VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; |       VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | ||||||
|  |   color_blend_attachment.blendEnable = VK_TRUE; | ||||||
|  |   color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; | ||||||
|  |   color_blend_attachment.dstColorBlendFactor = | ||||||
|  |       VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; | ||||||
|  |   color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; | ||||||
|  |   color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; | ||||||
|  |   color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | ||||||
|  |   color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; | ||||||
|  |  | ||||||
|   VkPipelineColorBlendStateCreateInfo color_blending_info = {}; |   VkPipelineColorBlendStateCreateInfo color_blending_info = {}; | ||||||
|   color_blending_info.sType = |   color_blending_info.sType = | ||||||
| @@ -123,8 +149,20 @@ void Graphics::CreateGraphicsPipeline() { | |||||||
|   color_blending_info.attachmentCount = 1; |   color_blending_info.attachmentCount = 1; | ||||||
|   color_blending_info.pAttachments = &color_blend_attachment; |   color_blending_info.pAttachments = &color_blend_attachment; | ||||||
|  |  | ||||||
|  |   VkPushConstantRange model_matrix_range = {}; | ||||||
|  |   model_matrix_range.offset = 0; | ||||||
|  |   model_matrix_range.size = sizeof(glm::mat4); | ||||||
|  |   model_matrix_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; | ||||||
|  |  | ||||||
|  |   std::array<VkDescriptorSetLayout, 2> set_layouts = {uniform_set_layout_, | ||||||
|  |                                                       texture_set_layout_}; | ||||||
|  |  | ||||||
|   VkPipelineLayoutCreateInfo layout_info = {}; |   VkPipelineLayoutCreateInfo layout_info = {}; | ||||||
|   layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |   layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | ||||||
|  |   layout_info.pushConstantRangeCount = 1; | ||||||
|  |   layout_info.pPushConstantRanges = &model_matrix_range; | ||||||
|  |   layout_info.setLayoutCount = set_layouts.size(); | ||||||
|  |   layout_info.pSetLayouts = set_layouts.data(); | ||||||
|  |  | ||||||
|   VkResult layout_result = vkCreatePipelineLayout(logical_device_, &layout_info, |   VkResult layout_result = vkCreatePipelineLayout(logical_device_, &layout_info, | ||||||
|                                                   nullptr, &pipeline_layout_); |                                                   nullptr, &pipeline_layout_); | ||||||
| @@ -183,4 +221,33 @@ void Graphics::CreateRenderPass() { | |||||||
|   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); |   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void veng::Graphics::RecreateSwapChain() { | ||||||
|  |   glm::ivec2 size = window_->GetFramebufferSize(); | ||||||
|  |   while (size.x == 0 || size.y == 0) { | ||||||
|  |     size = window_->GetFramebufferSize(); | ||||||
|  |     // glfwWaitEvents(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   vkDeviceWaitIdle(logical_device_); | ||||||
|  |   CleanupSwapChain(); | ||||||
|  |  | ||||||
|  |   CreateSwapChain(); | ||||||
|  |   CreateImageViews(); | ||||||
|  |   CreateFramebuffers(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void veng::Graphics::CleanupSwapChain() { | ||||||
|  |   if (logical_device_ == VK_NULL_HANDLE) return; | ||||||
|  |  | ||||||
|  |   for (VkFramebuffer framebuffer : swap_chain_framebuffers_) | ||||||
|  |     vkDestroyFramebuffer(logical_device_, framebuffer, nullptr); | ||||||
|  |  | ||||||
|  |   for (VkImageView image_view : swap_chain_image_views_) | ||||||
|  |     vkDestroyImageView(logical_device_, image_view, nullptr); | ||||||
|  |  | ||||||
|  |   if (swap_chain_ != VK_NULL_HANDLE) | ||||||
|  |     vkDestroySwapchainKHR(logical_device_, swap_chain_, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace veng | }  // namespace veng | ||||||
|   | |||||||
| @@ -140,29 +140,35 @@ void Graphics::CreateSwapChain() { | |||||||
|                           swap_chain_images_.data()); |                           swap_chain_images_.data()); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Graphics::CreateImageViews() { | VkImageView Graphics::CreateImageView(VkImage image, VkFormat format) { | ||||||
|   swap_chain_image_views_.resize(swap_chain_images_.size()); |  | ||||||
|  |  | ||||||
|   auto image_view_it = swap_chain_image_views_.begin(); |  | ||||||
|   for (VkImage image : swap_chain_images_) { |  | ||||||
|   VkImageViewCreateInfo info = {}; |   VkImageViewCreateInfo info = {}; | ||||||
|   info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |   info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | ||||||
|   info.image = image; |   info.image = image; | ||||||
|   info.viewType = VK_IMAGE_VIEW_TYPE_2D; |   info.viewType = VK_IMAGE_VIEW_TYPE_2D; | ||||||
|     info.format = surface_format_.format; |   info.format = format; | ||||||
|   info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; |   info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; | ||||||
|   info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; |   info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; | ||||||
|   info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; |   info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; | ||||||
|   info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; |   info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; | ||||||
|   info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |   info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | ||||||
|   info.subresourceRange.baseMipLevel = 0; |   info.subresourceRange.baseMipLevel = 0; | ||||||
|     info.subresourceRange.layerCount = 1; |   info.subresourceRange.levelCount = 1; | ||||||
|   info.subresourceRange.baseArrayLayer = 0; |   info.subresourceRange.baseArrayLayer = 0; | ||||||
|   info.subresourceRange.layerCount = 1; |   info.subresourceRange.layerCount = 1; | ||||||
|  |  | ||||||
|     VkResult result = |   VkImageView view; | ||||||
|         vkCreateImageView(logical_device_, &info, nullptr, &*image_view_it); |   VkResult result = vkCreateImageView(logical_device_, &info, nullptr, &view); | ||||||
|   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); |   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); | ||||||
|  |   return view; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CreateImageViews() { | ||||||
|  |   swap_chain_image_views_.resize(swap_chain_images_.size()); | ||||||
|  |  | ||||||
|  |   auto image_view_it = swap_chain_image_views_.begin(); | ||||||
|  |   for (VkImage image : swap_chain_images_) { | ||||||
|  |     *image_view_it = CreateImageView(image, surface_format_.format); | ||||||
|  |      | ||||||
|     std::advance(image_view_it, 1); |     std::advance(image_view_it, 1); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										219
									
								
								src/vulkan/texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								src/vulkan/texture.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | |||||||
|  | #include <vulkan/vulkan.h> | ||||||
|  |  | ||||||
|  | #include "stb/stb_image.h" | ||||||
|  | #include "vulkan/graphics.h" | ||||||
|  |  | ||||||
|  | namespace veng { | ||||||
|  |  | ||||||
|  | void Graphics::CreateTextureSampler() { | ||||||
|  |   VkSamplerCreateInfo sampler_info = {}; | ||||||
|  |   sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; | ||||||
|  |   sampler_info.magFilter = VK_FILTER_LINEAR; | ||||||
|  |   sampler_info.minFilter = VK_FILTER_LINEAR; | ||||||
|  |   sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||||
|  |   sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||||
|  |   sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||||
|  |   sampler_info.anisotropyEnable = VK_FALSE; | ||||||
|  |   sampler_info.maxAnisotropy = 1.f; | ||||||
|  |   sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | ||||||
|  |   sampler_info.unnormalizedCoordinates = VK_FALSE; | ||||||
|  |   sampler_info.compareEnable = VK_FALSE; | ||||||
|  |   sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; | ||||||
|  |   sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; | ||||||
|  |   sampler_info.mipLodBias = 0.f; | ||||||
|  |   sampler_info.minLod = 0.f; | ||||||
|  |   sampler_info.maxLod = 0.f; | ||||||
|  |  | ||||||
|  |   if (vkCreateSampler(logical_device_, &sampler_info, nullptr, | ||||||
|  |                       &texture_sampler_) != VK_SUCCESS) { | ||||||
|  |     std::exit(EXIT_FAILURE); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TextureHandle Graphics::CreateTexture(gsl::czstring path) { | ||||||
|  |   glm::ivec2 image_extents; | ||||||
|  |   std::int32_t channels; | ||||||
|  |   std::vector<std::uint8_t> image_file_data = ReadFile(path); | ||||||
|  |   stbi_uc* pixel_data = stbi_load_from_memory( | ||||||
|  |       image_file_data.data(), image_file_data.size(), &image_extents.x, | ||||||
|  |       &image_extents.y, &channels, STBI_rgb_alpha); | ||||||
|  |  | ||||||
|  |   VkDeviceSize buffer_size = image_extents.x * image_extents.y * 4; | ||||||
|  |   BufferHandle staging = | ||||||
|  |       CreateBuffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | ||||||
|  |                    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | | ||||||
|  |                        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); | ||||||
|  |   void* data_location; | ||||||
|  |   vkMapMemory(logical_device_, staging.memory, 0, buffer_size, 0, | ||||||
|  |               &data_location); | ||||||
|  |   std::memcpy(data_location, pixel_data, buffer_size); | ||||||
|  |   vkUnmapMemory(logical_device_, staging.memory); | ||||||
|  |  | ||||||
|  |   stbi_image_free(pixel_data); | ||||||
|  |  | ||||||
|  |   TextureHandle handle = | ||||||
|  |       CreateImage(image_extents, | ||||||
|  |                   VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, | ||||||
|  |                   VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||||||
|  |  | ||||||
|  |   TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_UNDEFINED, | ||||||
|  |                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | ||||||
|  |   CopyBufferToImage(staging.buffer, handle.image, image_extents); | ||||||
|  |   TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||||||
|  |                         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | ||||||
|  |  | ||||||
|  |   handle.image_view = CreateImageView(handle.image, VK_FORMAT_R8G8B8A8_SRGB); | ||||||
|  |  | ||||||
|  |   VkDescriptorSetAllocateInfo set_info = {}; | ||||||
|  |   set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; | ||||||
|  |   set_info.descriptorPool = texture_pool_; | ||||||
|  |   set_info.descriptorSetCount = 1; | ||||||
|  |   set_info.pSetLayouts = &texture_set_layout_; | ||||||
|  |  | ||||||
|  |   VkResult result = | ||||||
|  |       vkAllocateDescriptorSets(logical_device_, &set_info, &handle.set); | ||||||
|  |   if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); | ||||||
|  |  | ||||||
|  |   VkDescriptorImageInfo image_info = {}; | ||||||
|  |   image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | ||||||
|  |   image_info.imageView = handle.image_view; | ||||||
|  |   image_info.sampler = texture_sampler_; | ||||||
|  |  | ||||||
|  |   VkWriteDescriptorSet descriptor_write = {}; | ||||||
|  |   descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | ||||||
|  |   descriptor_write.dstSet = handle.set; | ||||||
|  |   descriptor_write.dstBinding = 0; | ||||||
|  |   descriptor_write.dstArrayElement = 0; | ||||||
|  |   descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | ||||||
|  |   descriptor_write.descriptorCount = 1; | ||||||
|  |   descriptor_write.pImageInfo = &image_info; | ||||||
|  |  | ||||||
|  |   vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr); | ||||||
|  |  | ||||||
|  |   DestroyBuffer(staging); | ||||||
|  |   return handle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::DestroyTexture(TextureHandle handle) { | ||||||
|  |   vkDeviceWaitIdle(logical_device_); | ||||||
|  |   vkFreeDescriptorSets(logical_device_, texture_pool_, 1, &handle.set); | ||||||
|  |   vkDestroyImageView(logical_device_, handle.image_view, nullptr); | ||||||
|  |   vkDestroyImage(logical_device_, handle.image, nullptr); | ||||||
|  |   vkFreeMemory(logical_device_, handle.memory, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::SetTexture(TextureHandle handle) { | ||||||
|  |   vkCmdBindDescriptorSets(command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, | ||||||
|  |                           pipeline_layout_, 1, 1, &handle.set, 0, nullptr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::TransitionImageLayout(VkImage image, VkImageLayout old_layout, | ||||||
|  |                                      VkImageLayout new_layout) { | ||||||
|  |   VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer(); | ||||||
|  |  | ||||||
|  |   VkImageMemoryBarrier barrier = {}; | ||||||
|  |   barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | ||||||
|  |   barrier.oldLayout = old_layout; | ||||||
|  |   barrier.newLayout = new_layout; | ||||||
|  |   barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||||||
|  |   barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | ||||||
|  |   barrier.image = image; | ||||||
|  |   barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | ||||||
|  |   barrier.subresourceRange.baseArrayLayer = 0; | ||||||
|  |   barrier.subresourceRange.baseMipLevel = 0; | ||||||
|  |   barrier.subresourceRange.levelCount = 1; | ||||||
|  |   barrier.subresourceRange.layerCount = 1; | ||||||
|  |  | ||||||
|  |   VkPipelineStageFlags source_stage = {}; | ||||||
|  |   VkPipelineStageFlags destination_stage = {}; | ||||||
|  |  | ||||||
|  |   if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && | ||||||
|  |       new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { | ||||||
|  |     barrier.srcAccessMask = 0; | ||||||
|  |     barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||||||
|  |     source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; | ||||||
|  |     destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; | ||||||
|  |   } else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && | ||||||
|  |              new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { | ||||||
|  |     barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | ||||||
|  |     barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | ||||||
|  |     source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; | ||||||
|  |     destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   vkCmdPipelineBarrier(local_command_buffer, source_stage, destination_stage, 0, | ||||||
|  |                        0, nullptr, 0, nullptr, 1, &barrier); | ||||||
|  |  | ||||||
|  |   EndTransientCommandBuffer(local_command_buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Graphics::CopyBufferToImage(VkBuffer buffer, VkImage image, | ||||||
|  |                                  glm::ivec2 image_size) { | ||||||
|  |   VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer(); | ||||||
|  |  | ||||||
|  |   VkBufferImageCopy region = {}; | ||||||
|  |   region.bufferOffset = 0; | ||||||
|  |   region.bufferRowLength = 0; | ||||||
|  |   region.bufferImageHeight = 0; | ||||||
|  |   region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | ||||||
|  |   region.imageSubresource.mipLevel = 0; | ||||||
|  |   region.imageSubresource.baseArrayLayer = 0; | ||||||
|  |   region.imageSubresource.layerCount = 1; | ||||||
|  |   region.imageOffset = {0, 0, 0}; | ||||||
|  |   region.imageExtent = {static_cast<std::uint32_t>(image_size.x), | ||||||
|  |                         static_cast<std::uint32_t>(image_size.y), 1}; | ||||||
|  |  | ||||||
|  |   vkCmdCopyBufferToImage(local_command_buffer, buffer, image, | ||||||
|  |                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); | ||||||
|  |  | ||||||
|  |   EndTransientCommandBuffer(local_command_buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TextureHandle Graphics::CreateImage(glm::ivec2 size, VkBufferUsageFlags usage, | ||||||
|  |                                     VkMemoryPropertyFlags properties) { | ||||||
|  |   TextureHandle handle = {}; | ||||||
|  |  | ||||||
|  |   VkImageCreateInfo image_info = {}; | ||||||
|  |   image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | ||||||
|  |   image_info.usage = usage; | ||||||
|  |   image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | ||||||
|  |   image_info.imageType = VK_IMAGE_TYPE_2D; | ||||||
|  |   image_info.extent.width = size.x; | ||||||
|  |   image_info.extent.height = size.y; | ||||||
|  |   image_info.extent.depth = 1; | ||||||
|  |   image_info.mipLevels = 1; | ||||||
|  |   image_info.arrayLayers = 1; | ||||||
|  |   image_info.format = VK_FORMAT_R8G8B8A8_SRGB; | ||||||
|  |   image_info.tiling = VK_IMAGE_TILING_OPTIMAL; | ||||||
|  |   image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | ||||||
|  |   image_info.samples = VK_SAMPLE_COUNT_1_BIT; | ||||||
|  |   image_info.flags = 0; | ||||||
|  |  | ||||||
|  |   VkResult result = | ||||||
|  |       vkCreateImage(logical_device_, &image_info, nullptr, &handle.image); | ||||||
|  |   if (result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to create vertex buffer!"); | ||||||
|  |  | ||||||
|  |   VkMemoryRequirements memory_requirements; | ||||||
|  |   vkGetImageMemoryRequirements(logical_device_, handle.image, | ||||||
|  |                                &memory_requirements); | ||||||
|  |  | ||||||
|  |   std::uint32_t chosen_memory_type = | ||||||
|  |       FindMemoryType(memory_requirements.memoryTypeBits, properties); | ||||||
|  |  | ||||||
|  |   VkMemoryAllocateInfo allocation_info = {}; | ||||||
|  |   allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | ||||||
|  |   allocation_info.allocationSize = memory_requirements.size; | ||||||
|  |   allocation_info.memoryTypeIndex = chosen_memory_type; | ||||||
|  |  | ||||||
|  |   VkResult allocation_result = vkAllocateMemory( | ||||||
|  |       logical_device_, &allocation_info, nullptr, &handle.memory); | ||||||
|  |   if (allocation_result != VK_SUCCESS) | ||||||
|  |     throw std::runtime_error("Failed to allocate image memory!"); | ||||||
|  |  | ||||||
|  |   vkBindImageMemory(logical_device_, handle.image, handle.memory, 0); | ||||||
|  |  | ||||||
|  |   return handle; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace veng | ||||||
		Reference in New Issue
	
	Block a user