diff --git a/shaders/shader.vert b/shaders/shader.vert index f5b2f8d..9f27f54 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,20 +1,11 @@ #version 450 -layout(location = 0) out vec3 fragColor; - -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; -vec3 colors[3] = vec3[]( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0) -); +layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - fragColor = colors[gl_VertexIndex]; + gl_Position = vec4(inPosition, 0.0, 1.0); + fragColor = inColor; } diff --git a/src/VulkanTutorial.cpp b/src/VulkanTutorial.cpp index 1ce168e..ad2db88 100644 --- a/src/VulkanTutorial.cpp +++ b/src/VulkanTutorial.cpp @@ -17,6 +17,39 @@ PFN_vkCreateDebugUtilsMessengerEXT vkeCreateDebugUtilsMessengerEXT = nullptr; PFN_vkDestroyDebugUtilsMessengerEXT vkeDestroyDebugUtilsMessengerEXT = nullptr; +VkVertexInputBindingDescription Vertex::binding_description() { + return { + .binding = 0, + .stride = sizeof(Vertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; +} + +std::array Vertex::attributes_description() { + return { + VkVertexInputAttributeDescription { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(Vertex, position), + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32_SFLOAT, + .offset = offsetof(Vertex, color), + }, + }; +} + + +const std::vector vertices = { + {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, + {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} +}; + + VulkanTutorial::VulkanTutorial() { } @@ -36,6 +69,7 @@ void VulkanTutorial::initialize(SDL_Window* window) { create_graphic_pipeline(); create_framebuffers(); create_command_pool(); + create_vertex_buffer(); create_command_buffers(); create_sync_objects(); } @@ -64,6 +98,16 @@ void VulkanTutorial::shutdown() { m_command_pool = VK_NULL_HANDLE; } + if(m_vertex_buffer != VK_NULL_HANDLE) { + vkDestroyBuffer(m_device, m_vertex_buffer, nullptr); + m_vertex_buffer = VK_NULL_HANDLE; + } + + if(m_vertex_buffer_memory != VK_NULL_HANDLE) { + vkFreeMemory(m_device, m_vertex_buffer_memory, nullptr); + m_vertex_buffer_memory = VK_NULL_HANDLE; + } + cleanup_swap_chain(); if(m_device) { @@ -600,12 +644,17 @@ void VulkanTutorial::create_graphic_pipeline() { }, }; + const VkVertexInputBindingDescription vertex_bindings[] = { + Vertex::binding_description(), + }; + const auto vertex_attributes = Vertex::attributes_description(); + VkPipelineVertexInputStateCreateInfo vertex_info { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 0, - .pVertexBindingDescriptions = nullptr, - .vertexAttributeDescriptionCount = 0, - .pVertexAttributeDescriptions = nullptr, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = vertex_bindings, + .vertexAttributeDescriptionCount = uint32_t(vertex_attributes.size()), + .pVertexAttributeDescriptions = vertex_attributes.data(), }; VkPipelineInputAssemblyStateCreateInfo assembly_info { @@ -748,6 +797,42 @@ void VulkanTutorial::create_command_pool() { throw std::runtime_error("failed to create command pool"); } +void VulkanTutorial::create_vertex_buffer() { + VkBufferCreateInfo buffer_info { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = sizeof(vertices[0]) * vertices.size(), + .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + + if(vkCreateBuffer(m_device, &buffer_info, nullptr, &m_vertex_buffer) != VK_SUCCESS) + throw std::runtime_error("failed to create vertex buffer"); + + VkMemoryRequirements memory_requirements; + vkGetBufferMemoryRequirements(m_device, m_vertex_buffer, &memory_requirements); + + const auto memory_type = find_memory(memory_requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if(memory_type < 0) + throw std::runtime_error("failed to find suitable memory type for vertex buffer"); + + VkMemoryAllocateInfo alloc_info { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memory_requirements.size, + .memoryTypeIndex = uint32_t(memory_type), + }; + + if(vkAllocateMemory(m_device, &alloc_info, nullptr, &m_vertex_buffer_memory) != VK_SUCCESS) + throw std::runtime_error("failed to allocate vertex buffer memory"); + + vkBindBufferMemory(m_device, m_vertex_buffer, m_vertex_buffer_memory, 0); + + void* buffer = nullptr; + vkMapMemory(m_device, m_vertex_buffer_memory, 0, buffer_info.size, 0, &buffer); + memcpy(buffer, vertices.data(), size_t(buffer_info.size)); + vkUnmapMemory(m_device, m_vertex_buffer_memory); +} + void VulkanTutorial::create_command_buffers() { m_command_buffers.resize(m_framebuffers.size()); @@ -794,8 +879,19 @@ void VulkanTutorial::create_command_buffers() { }; vkCmdBeginRenderPass(command_buffer, &pass_info, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); - vkCmdDraw(command_buffer, 3, 1, 0, 0); + + VkBuffer vertex_buffers[] = { + m_vertex_buffer, + }; + VkDeviceSize offsets[] = { + 0, + }; + vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets); + + vkCmdDraw(command_buffer, uint32_t(vertices.size()), 1, 0, 0); + vkCmdEndRenderPass(command_buffer); if(vkEndCommandBuffer(command_buffer) != VK_SUCCESS) @@ -902,6 +998,19 @@ VkShaderModule VulkanTutorial::create_shader_module_from_file(const char* path) return VK_NULL_HANDLE; } +int32_t VulkanTutorial::find_memory(uint32_t type_filter, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memory_properties; + vkGetPhysicalDeviceMemoryProperties(m_physical_device, &memory_properties); + + for(uint32_t type_index = 0; type_index < memory_properties.memoryTypeCount; type_index += 1) { + if(((1 << type_index) & type_filter) && + (memory_properties.memoryTypes[type_index].propertyFlags & properties) == properties) + return type_index; + } + + return -1; +} + std::vector VulkanTutorial::get_physical_devices() const { uint32_t devices_count = 0; vkEnumeratePhysicalDevices(m_instance, &devices_count, nullptr); diff --git a/src/VulkanTutorial.h b/src/VulkanTutorial.h index 8b269c8..f23603f 100644 --- a/src/VulkanTutorial.h +++ b/src/VulkanTutorial.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -15,6 +16,15 @@ extern PFN_vkCreateDebugUtilsMessengerEXT vkeCreateDebugUtilsMessengerEXT; extern PFN_vkDestroyDebugUtilsMessengerEXT vkeDestroyDebugUtilsMessengerEXT; +struct Vertex { + Eigen::Vector2f position; + Eigen::Vector3f color; + + static VkVertexInputBindingDescription binding_description(); + static std::array attributes_description(); +}; + + class VulkanTutorial { public: VulkanTutorial(); @@ -49,6 +59,7 @@ private: void create_graphic_pipeline(); void create_framebuffers(); void create_command_pool(); + void create_vertex_buffer(); void create_command_buffers(); void create_sync_objects(); @@ -58,6 +69,8 @@ private: VkShaderModule create_shader_module(const std::vector bytecode); VkShaderModule create_shader_module_from_file(const char* path); + int32_t find_memory(uint32_t type_filter, VkMemoryPropertyFlags properties); + std::vector get_physical_devices() const; std::vector get_queue_families(VkPhysicalDevice physical_device) const; std::vector get_device_extensions(VkPhysicalDevice physical_device) const; @@ -84,6 +97,8 @@ private: VkPipeline m_pipeline = VK_NULL_HANDLE; std::vector m_framebuffers; VkCommandPool m_command_pool = VK_NULL_HANDLE; + VkBuffer m_vertex_buffer = VK_NULL_HANDLE; + VkDeviceMemory m_vertex_buffer_memory = VK_NULL_HANDLE; std::vector m_command_buffers; std::vector m_image_available_semaphores; std::vector m_render_finished_semaphores;