diff --git a/.gitmodules b/.gitmodules index 66576d5..f3c5f75 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "thirdparty/imgui"] path = thirdparty/imgui url = https://github.com/ocornut/imgui.git +[submodule "thirdparty/smath"] + path = thirdparty/smath + url = https://github.com/slendidev/smath.git diff --git a/meson.build b/meson.build index 423e2f3..6576d57 100644 --- a/meson.build +++ b/meson.build @@ -47,6 +47,8 @@ add_project_arguments( '-Wno-unsafe-buffer-usage', '-Wno-c23-extensions', '-Wno-old-style-cast', + '-Wno-implicit-int-float-conversion', + '-Wno-implicit-float-conversion', ], language : 'cpp' ) @@ -89,7 +91,11 @@ exe = executable('vr-compositor', 'src/VulkanRenderer.cpp', 'src/Application.cpp', ], - include_directories: [ vkbootstrap_inc, imgui_inc ], + include_directories: [ + vkbootstrap_inc, + imgui_inc, + 'thirdparty/smath/include' + ], link_with: imgui_lib, dependencies: [ wayland_dep, diff --git a/shaders/meson.build b/shaders/meson.build index ba0169b..c903de9 100644 --- a/shaders/meson.build +++ b/shaders/meson.build @@ -17,6 +17,8 @@ shader_sources = files( 'gradient.comp', 'triangle.frag', 'triangle.vert', + 'triangle_mesh.frag', + 'triangle_mesh.vert', ) spirv_shaders = [] diff --git a/shaders/triangle_mesh.frag b/shaders/triangle_mesh.frag new file mode 100644 index 0000000..6208dba --- /dev/null +++ b/shaders/triangle_mesh.frag @@ -0,0 +1,11 @@ +#version 450 + +layout (location = 0) in vec3 in_color; +layout (location = 1) in vec3 in_uv; + +layout (location = 0) out vec4 out_frag_color; + +void main() { + out_frag_color = vec4(in_color, 1.0f); +} + diff --git a/shaders/triangle_mesh.vert b/shaders/triangle_mesh.vert new file mode 100644 index 0000000..a9871c4 --- /dev/null +++ b/shaders/triangle_mesh.vert @@ -0,0 +1,32 @@ +#version 450 +#extension GL_EXT_buffer_reference : require + +layout (location = 0) out vec3 out_color; +layout (location = 1) out vec3 out_uv; + +struct Vertex { + vec3 position; + float uv_x; + vec3 normal; + float uv_y; + vec4 color; +}; + +layout(buffer_reference, std430) readonly buffer VertexBuffer{ + Vertex vertices[]; +}; + +layout(push_constant) uniform constants { + mat4 world_matrix; + VertexBuffer vertex_buffer; +} PushConstants; + +void main() { + Vertex v = PushConstants.vertex_buffer.vertices[gl_VertexIndex]; + + gl_Position = PushConstants.world_matrix * vec4(v.position, 1.0f); + out_color = v.color.xyz; + out_uv.x = v.uv_x; + out_uv.y = v.uv_y; +} + diff --git a/src/AllocatedImage.h b/src/AllocatedImage.h deleted file mode 100644 index 917bcc5..0000000 --- a/src/AllocatedImage.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -namespace Lunar { - -struct AllocatedImage { - VkImage image; - VkImageView image_view; - VmaAllocation allocation; - VkExtent3D extent; - VkFormat format; -}; - -} // namespace Lunar diff --git a/src/VulkanRenderer.cpp b/src/VulkanRenderer.cpp index e36956a..06af77c 100644 --- a/src/VulkanRenderer.cpp +++ b/src/VulkanRenderer.cpp @@ -33,6 +33,7 @@ VulkanRenderer::VulkanRenderer(SDL_Window *window, Logger &logger) sync_init(); descriptors_init(); pipelines_init(); + default_data_init(); imgui_init(); } @@ -150,6 +151,10 @@ auto VulkanRenderer::vk_init() -> void features_13.pNext = nullptr; features_13.synchronization2 = VK_TRUE; features_13.dynamicRendering = VK_TRUE; + VkPhysicalDeviceBufferDeviceAddressFeatures buffer_device_address_features {}; + buffer_device_address_features.sType + = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; + buffer_device_address_features.bufferDeviceAddress = VK_TRUE; phys_device_selector.set_surface(m_vk.surface) .add_desired_extensions({ VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, @@ -163,8 +168,10 @@ auto VulkanRenderer::vk_init() -> void VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME, + VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, }) - .set_required_features_13(features_13); + .set_required_features_13(features_13) + .add_required_extension_features(buffer_device_address_features); auto physical_device_selector_return { phys_device_selector.select() }; if (!physical_device_selector_return) { std::println(std::cerr, @@ -207,6 +214,7 @@ auto VulkanRenderer::vk_init() -> void allocator_ci.physicalDevice = m_vkb.phys_dev; allocator_ci.device = m_vkb.dev; allocator_ci.instance = m_vkb.instance; + allocator_ci.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; vmaCreateAllocator(&allocator_ci, &m_vk.allocator); m_vk.deletion_queue.emplace( @@ -321,6 +329,7 @@ auto VulkanRenderer::pipelines_init() -> void { background_pipelines_init(); triangle_pipeline_init(); + mesh_pipeline_init(); } auto VulkanRenderer::background_pipelines_init() -> void @@ -423,6 +432,70 @@ auto VulkanRenderer::triangle_pipeline_init() -> void }); } +auto VulkanRenderer::mesh_pipeline_init() -> void +{ + uint8_t triangle_vert_shader_data[] { +#embed "triangle_mesh_vert.spv" + }; + VkShaderModule triangle_vert_shader {}; + if (!vkutil::load_shader_module( + std::span( + triangle_vert_shader_data, sizeof(triangle_vert_shader_data)), + m_vkb.dev, &triangle_vert_shader)) { + m_logger.err("Failed to load triangle vert shader"); + } + + uint8_t triangle_frag_shader_data[] { +#embed "triangle_mesh_frag.spv" + }; + VkShaderModule triangle_frag_shader {}; + if (!vkutil::load_shader_module( + std::span( + triangle_frag_shader_data, sizeof(triangle_frag_shader_data)), + m_vkb.dev, &triangle_frag_shader)) { + m_logger.err("Failed to load triangle frag shader"); + } + + VkPushConstantRange push_constant_range {}; + push_constant_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constant_range.offset = 0; + push_constant_range.size = sizeof(GPUDrawPushConstants); + + VkPipelineLayoutCreateInfo layout_ci {}; + layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_ci.pNext = nullptr; + layout_ci.pushConstantRangeCount = 1; + layout_ci.pPushConstantRanges = &push_constant_range; + + VK_CHECK(m_logger, + vkCreatePipelineLayout( + m_vkb.dev, &layout_ci, nullptr, &m_vk.mesh_pipeline_layout)); + + auto pip { + GraphicsPipelineBuilder { m_logger } + .set_pipeline_layout(m_vk.mesh_pipeline_layout) + .set_shaders(triangle_vert_shader, triangle_frag_shader) + .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) + .set_polygon_mode(VK_POLYGON_MODE_FILL) + .set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE) + .set_multisampling_none() + .disable_blending() + .disable_depth_testing() + .set_color_attachment_format(m_vk.draw_image.format) + .set_depth_format(VK_FORMAT_UNDEFINED) + .build(m_vkb.dev), + }; + m_vk.mesh_pipeline = pip; + + vkDestroyShaderModule(m_vkb.dev, triangle_vert_shader, nullptr); + vkDestroyShaderModule(m_vkb.dev, triangle_frag_shader, nullptr); + + m_vk.deletion_queue.emplace([&]() { + vkDestroyPipelineLayout(m_vkb.dev, m_vk.mesh_pipeline_layout, nullptr); + vkDestroyPipeline(m_vkb.dev, m_vk.mesh_pipeline, nullptr); + }); +} + auto VulkanRenderer::imgui_init() -> void { VkDescriptorPoolSize pool_sizes[] = { @@ -488,6 +561,38 @@ auto VulkanRenderer::imgui_init() -> void }); } +auto VulkanRenderer::default_data_init() -> void +{ + std::array rect_vertices; + + rect_vertices[0].position = { 0.5, -0.5, 0 }; + rect_vertices[1].position = { 0.5, 0.5, 0 }; + rect_vertices[2].position = { -0.5, -0.5, 0 }; + rect_vertices[3].position = { -0.5, 0.5, 0 }; + + rect_vertices[0].color = { 0, 0, 0, 1 }; + rect_vertices[1].color = { 0.5, 0.5, 0.5, 1 }; + rect_vertices[2].color = { 1, 0, 0, 1 }; + rect_vertices[3].color = { 0, 1, 0, 1 }; + + std::array rect_indices; + + rect_indices[0] = 0; + rect_indices[1] = 1; + rect_indices[2] = 2; + + rect_indices[3] = 2; + rect_indices[4] = 1; + rect_indices[5] = 3; + + m_vk.rectangle = upload_mesh(rect_indices, rect_vertices); + + m_vk.deletion_queue.emplace([&]() { + destroy_buffer(m_vk.rectangle.index_buffer); + destroy_buffer(m_vk.rectangle.vertex_buffer); + }); +} + auto VulkanRenderer::render() -> void { defer(m_vk.frame_number++); @@ -645,6 +750,19 @@ auto VulkanRenderer::draw_geometry(VkCommandBuffer cmd) -> void vkCmdDraw(cmd, 3, 1, 0, 0); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_vk.mesh_pipeline); + + GPUDrawPushConstants push_constants; + push_constants.world_matrix = smath::Mat4 { 1.0f }; + push_constants.vertex_buffer = m_vk.rectangle.vertex_buffer_address; + + vkCmdPushConstants(cmd, m_vk.mesh_pipeline_layout, + VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants), &push_constants); + vkCmdBindIndexBuffer( + cmd, m_vk.rectangle.index_buffer.buffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0); + vkCmdEndRendering(cmd); } @@ -804,4 +922,105 @@ auto VulkanRenderer::destroy_swapchain() -> void m_vk.swapchain_extent = { 0, 0 }; } +auto VulkanRenderer::create_buffer(size_t alloc_size, VkBufferUsageFlags usage, + VmaMemoryUsage memory_usage) -> AllocatedBuffer +{ + VkBufferCreateInfo buffer_ci {}; + buffer_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_ci.pNext = nullptr; + buffer_ci.flags = 0; + buffer_ci.size = alloc_size; + buffer_ci.usage = usage; + buffer_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo alloc_ci {}; + alloc_ci.usage = memory_usage; + alloc_ci.flags = 0; + if (memory_usage == VMA_MEMORY_USAGE_CPU_ONLY) { + alloc_ci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT + | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + } + + AllocatedBuffer buffer; + VK_CHECK(m_logger, + vmaCreateBuffer(m_vk.allocator, &buffer_ci, &alloc_ci, &buffer.buffer, + &buffer.allocation, &buffer.info)); + + return buffer; +} + +auto VulkanRenderer::destroy_buffer(AllocatedBuffer &buffer) -> void +{ + vmaDestroyBuffer(m_vk.allocator, buffer.buffer, buffer.allocation); +} + +auto VulkanRenderer::upload_mesh( + std::span indices, std::span vertices) -> GPUMeshBuffers +{ + auto const vertex_buffer_size { vertices.size() * sizeof(Vertex) }; + auto const index_buffer_size { indices.size() * sizeof(uint32_t) }; + + GPUMeshBuffers new_surface; + new_surface.vertex_buffer = create_buffer(vertex_buffer_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + VkBufferDeviceAddressInfo device_address_info {}; + device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + device_address_info.buffer = new_surface.vertex_buffer.buffer; + + new_surface.vertex_buffer_address + = vkGetBufferDeviceAddress(m_vkb.dev, &device_address_info); + + new_surface.index_buffer = create_buffer(index_buffer_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + auto staging { create_buffer(vertex_buffer_size + index_buffer_size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) }; + + VmaAllocationInfo info {}; + vmaGetAllocationInfo(m_vk.allocator, staging.allocation, &info); + + void *data = info.pMappedData; + if (!data) { + VkResult res = vmaMapMemory(m_vk.allocator, staging.allocation, &data); + assert(res == VK_SUCCESS); + } + defer({ + if (info.pMappedData == nullptr) { + vmaUnmapMemory(m_vk.allocator, staging.allocation); + } + }); + + memcpy(data, vertices.data(), vertex_buffer_size); + memcpy(reinterpret_cast( + reinterpret_cast(data) + vertex_buffer_size), + indices.data(), index_buffer_size); + + immediate_submit([&](VkCommandBuffer cmd) { + VkBufferCopy vertex_copy {}; + vertex_copy.dstOffset = 0; + vertex_copy.srcOffset = 0; + vertex_copy.size = vertex_buffer_size; + + vkCmdCopyBuffer(cmd, staging.buffer, new_surface.vertex_buffer.buffer, + 1, &vertex_copy); + + VkBufferCopy index_copy {}; + index_copy.dstOffset = 0; + index_copy.srcOffset = vertex_buffer_size; + index_copy.size = index_buffer_size; + + vkCmdCopyBuffer(cmd, staging.buffer, new_surface.index_buffer.buffer, 1, + &index_copy); + }); + + destroy_buffer(staging); + + return new_surface; +} + } // namespace Lunar diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 65f3fe1..19e645f 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -5,16 +5,30 @@ #include #include +#include #include #include -#include "AllocatedImage.h" #include "DeletionQueue.h" +#include "DescriptorAllocator.h" #include "Logger.h" -#include "src/DescriptorAllocator.h" namespace Lunar { +struct AllocatedImage { + VkImage image; + VkImageView image_view; + VmaAllocation allocation; + VkExtent3D extent; + VkFormat format; +}; + +struct AllocatedBuffer { + VkBuffer buffer; + VmaAllocation allocation; + VmaAllocationInfo info; +}; + struct FrameData { VkCommandPool command_pool; VkCommandBuffer main_command_buffer; @@ -24,6 +38,24 @@ struct FrameData { DeletionQueue deletion_queue; }; +struct Vertex { + smath::Vec3 position; + float uv_x; + smath::Vec3 normal; + float uv_y; + smath::Vec4 color; +}; + +struct GPUMeshBuffers { + AllocatedBuffer index_buffer, vertex_buffer; + VkDeviceAddress vertex_buffer_address; +}; + +struct GPUDrawPushConstants { + smath::Mat4 world_matrix; + VkDeviceAddress vertex_buffer; +}; + constexpr unsigned FRAME_OVERLAP = 2; class VulkanRenderer { @@ -46,7 +78,9 @@ private: auto pipelines_init() -> void; auto background_pipelines_init() -> void; auto triangle_pipeline_init() -> void; + auto mesh_pipeline_init() -> void; auto imgui_init() -> void; + auto default_data_init() -> void; auto draw_background(VkCommandBuffer cmd) -> void; auto draw_geometry(VkCommandBuffer cmd) -> void; @@ -59,6 +93,12 @@ private: auto recreate_swapchain(uint32_t width, uint32_t height) -> void; auto destroy_swapchain() -> void; + auto create_buffer(size_t alloc_size, VkBufferUsageFlags usage, + VmaMemoryUsage memory_usage) -> AllocatedBuffer; + auto destroy_buffer(AllocatedBuffer &buffer) -> void; + auto upload_mesh(std::span indices, std::span vertices) + -> GPUMeshBuffers; + struct { vkb::Instance instance; vkb::PhysicalDevice phys_dev; @@ -100,6 +140,11 @@ private: VkPipeline triangle_pipeline {}; VkPipelineLayout triangle_pipeline_layout {}; + VkPipeline mesh_pipeline {}; + VkPipelineLayout mesh_pipeline_layout {}; + + GPUMeshBuffers rectangle; + VkDescriptorPool imgui_descriptor_pool { VK_NULL_HANDLE }; DeletionQueue deletion_queue; diff --git a/thirdparty/smath b/thirdparty/smath new file mode 160000 index 0000000..e32204d --- /dev/null +++ b/thirdparty/smath @@ -0,0 +1 @@ +Subproject commit e32204db0cf87870d6fa85ed5623520c682c29ea