diff --git a/Makefile b/Makefile index e6a7c36..99a8005 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ shaders: glslangValidator -V gradient_color.comp -o gradient_color.comp.spv glslangValidator -V colored_triangle.frag -o colored_triangle.frag.spv glslangValidator -V colored_triangle.vert -o colored_triangle.vert.spv + glslangValidator -V colored_triangle_mesh.vert -o colored_triangle_mesh.vert.spv %.cpp : %.rl ragel -I $(ROOT_DIR) -G1 -o $@ $< diff --git a/colored_triangle_mesh.vert b/colored_triangle_mesh.vert new file mode 100644 index 0000000..fe9bec5 --- /dev/null +++ b/colored_triangle_mesh.vert @@ -0,0 +1,37 @@ +#version 450 +#extension GL_EXT_buffer_reference : require + +layout (location = 0) out vec3 outColor; +layout (location = 1) out vec2 outUV; + +struct Vertex { + + vec3 position; + float uv_x; + vec3 normal; + float uv_y; + vec4 color; +}; + +layout(buffer_reference, std430) readonly buffer VertexBuffer{ + Vertex vertices[]; +}; + +//push constants block +layout( push_constant ) uniform constants +{ + mat4 render_matrix; + VertexBuffer vertexBuffer; +} PushConstants; + +void main() +{ + //load vertex data from device adress + Vertex v = PushConstants.vertexBuffer.vertices[gl_VertexIndex]; + + //output data + gl_Position = PushConstants.render_matrix *vec4(v.position, 1.0f); + outColor = v.color.xyz; + outUV.x = v.uv_x; + outUV.y = v.uv_y; +} diff --git a/colored_triangle_mesh.vert.spv b/colored_triangle_mesh.vert.spv new file mode 100644 index 0000000..7461a40 Binary files /dev/null and b/colored_triangle_mesh.vert.spv differ diff --git a/vk_engine.cpp b/vk_engine.cpp index 1106b6d..51695b6 100644 --- a/vk_engine.cpp +++ b/vk_engine.cpp @@ -201,6 +201,19 @@ void VulkanEngine::draw_geometry(VkCommandBuffer cmd) vkCmdDraw(cmd, 3, 1, 0, 0); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _meshPipeline); + + GPUDrawPushConstants push_constants{ + .worldMatrix = glm::mat4{ 1.0f }, + .vertexBuffer = rectangle.vertexBufferAddress, + }; + + vkCmdPushConstants(cmd, _meshPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(GPUDrawPushConstants), +&push_constants); + vkCmdBindIndexBuffer(cmd, rectangle.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0); + vkCmdEndRendering(cmd); } @@ -465,6 +478,7 @@ void VulkanEngine::init_pipelines() { init_background_pipelines(); init_triangle_pipelines(); + init_mesh_pipeline(); init_shaders(); } @@ -566,6 +580,60 @@ void VulkanEngine::immediate_submit(std::function&& f VK_CHECK(vkWaitForFences(_device, 1, &_immFence, true,9999999999)); } +void VulkanEngine::init_mesh_pipeline() +{ + VkShaderModule triangleFragShader; + if (!vkutil::load_shader_module("colored_triangle.frag.spv", _device, &triangleFragShader)) { + std::print("Error when building the triangle fragment shader module"); + } + else { + std::print("Triangle fragment shader succesfully loaded"); + } + + VkShaderModule triangleVertexShader; + if (!vkutil::load_shader_module("colored_triangle_mesh.vert.spv", _device, &triangleVertexShader)) { + std::print("Error when building the triangle vertex shader module"); + } + else { + std::print("Triangle vertex shader succesfully loaded"); + } + + VkPushConstantRange bufferRange{ + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .offset = 0, + .size = sizeof(GPUDrawPushConstants), + }; + + VkPipelineLayoutCreateInfo pipeline_layout_info = vkinit::pipeline_layout_create_info(); + pipeline_layout_info.pPushConstantRanges = &bufferRange; + pipeline_layout_info.pushConstantRangeCount = 1; + + VK_CHECK(vkCreatePipelineLayout(_device, &pipeline_layout_info, nullptr, &_meshPipelineLayout)); + + + PipelineBuilder pipelineBuilder; + + pipelineBuilder._pipelineLayout = _meshPipelineLayout; + pipelineBuilder.set_shaders(triangleVertexShader, triangleFragShader); + pipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + pipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL); + pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE); + pipelineBuilder.set_multisampling_none(); + pipelineBuilder.disable_blending(); + pipelineBuilder.disable_depthtest(); + pipelineBuilder.set_color_attachment_format(_drawImage.imageFormat); + pipelineBuilder.set_depth_format(VK_FORMAT_UNDEFINED); + + _meshPipeline = pipelineBuilder.build_pipeline(_device); + vkDestroyShaderModule(_device, triangleFragShader, nullptr); + vkDestroyShaderModule(_device, triangleVertexShader, nullptr); + + _mainDeletionQueue.push_function([&]() { + vkDestroyPipelineLayout(_device, _meshPipelineLayout, nullptr); + vkDestroyPipeline(_device, _meshPipeline, nullptr); + }); +} + void VulkanEngine::init_triangle_pipelines() { @@ -613,3 +681,124 @@ void VulkanEngine::init_triangle_pipelines() vkDestroyPipeline(_device, _trianglePipeline, nullptr); }); } + + +AllocatedBuffer VulkanEngine::create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage) +{ + VkBufferCreateInfo bufferInfo{ + .sType=VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = allocSize, + .usage = usage, + }; + + VmaAllocationCreateInfo vmaallocInfo{ + .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, + .usage = memoryUsage, + }; + + AllocatedBuffer newBuffer; + + VK_CHECK(vmaCreateBuffer(_allocator, &bufferInfo, + &vmaallocInfo, &newBuffer.buffer, + &newBuffer.allocation, &newBuffer.info)); + + return newBuffer; +} + +void VulkanEngine::destroy_buffer(const AllocatedBuffer& buffer) +{ + vmaDestroyBuffer(_allocator, buffer.buffer, buffer.allocation); +} + + +GPUMeshBuffers VulkanEngine::uploadMesh(std::span indices, std::span vertices) +{ + const size_t vertexBufferSize = vertices.size() * sizeof(Vertex); + const size_t indexBufferSize = indices.size() * sizeof(uint32_t); + + GPUMeshBuffers newSurface; + + newSurface.vertexBuffer = create_buffer( + vertexBufferSize, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + VkBufferDeviceAddressInfo deviceAddressInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = newSurface.vertexBuffer.buffer + }; + + newSurface.vertexBufferAddress = vkGetBufferDeviceAddress(_device, &deviceAddressInfo); + + newSurface.indexBuffer = create_buffer(indexBufferSize, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VMA_MEMORY_USAGE_GPU_ONLY); + + AllocatedBuffer staging = create_buffer(vertexBufferSize + indexBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + + void* data = staging.allocation->GetMappedData(); + + memcpy(data, vertices.data(), vertexBufferSize); + memcpy((char *)data + vertexBufferSize, indices.data(), indexBufferSize); + + immediate_submit([&](VkCommandBuffer cmd) { + VkBufferCopy vertexCopy{ + .srcOffset = 0, + .dstOffset = 0, + .size = vertexBufferSize, + }; + + vkCmdCopyBuffer(cmd, staging.buffer, + newSurface.vertexBuffer.buffer, 1, + &vertexCopy); + + VkBufferCopy indexCopy{ + .srcOffset = vertexBufferSize, + .dstOffset = 0, + .size = indexBufferSize, + }; + + vkCmdCopyBuffer(cmd, staging.buffer, + newSurface.indexBuffer.buffer, 1, + &indexCopy); + }); + + destroy_buffer(staging); + + return newSurface; +} + +void VulkanEngine::init_default_data() { + 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; + + rectangle = uploadMesh(rect_indices, rect_vertices); + + _mainDeletionQueue.push_function([&](){ + destroy_buffer(rectangle.indexBuffer); + destroy_buffer(rectangle.vertexBuffer); + }); +} + + diff --git a/vk_engine.h b/vk_engine.h index 465088c..dcececa 100644 --- a/vk_engine.h +++ b/vk_engine.h @@ -96,6 +96,10 @@ public: int currentBackgroundEffect{0}; VkPipelineLayout _trianglePipelineLayout; VkPipeline _trianglePipeline; + VkPipelineLayout _meshPipelineLayout; + VkPipeline _meshPipeline; + + GPUMeshBuffers rectangle; // ZED's REFACTOR VkGUI _gui; @@ -128,11 +132,19 @@ private: void init_pipelines(); void init_background_pipelines(); void init_shaders(); - void load_shader(const char *file_name, const char *entry_point, ComputeEffect data); void init_triangle_pipelines(); + void init_mesh_pipeline(); + void init_default_data(); + + void load_shader(const char *file_name, const char *entry_point, ComputeEffect data); void create_swapchain(uint32_t width, uint32_t height); + AllocatedBuffer create_buffer(size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage); + void destroy_swapchain(); + void destroy_buffer(const AllocatedBuffer& buffer); void draw_background(VkCommandBuffer cmd); void draw_geometry(VkCommandBuffer cmd); + + GPUMeshBuffers uploadMesh(std::span indices, std::span vertices); }; diff --git a/vk_types.h b/vk_types.h index ed4264a..4f93e18 100644 --- a/vk_types.h +++ b/vk_types.h @@ -30,6 +30,14 @@ } while (0) +constexpr unsigned int FRAME_OVERLAP=2; + +struct AllocatedBuffer { + VkBuffer buffer; + VmaAllocation allocation; + VmaAllocationInfo info; +}; + struct AllocatedImage { VkImage image; VkImageView imageView; @@ -53,4 +61,22 @@ struct ComputeEffect { ComputePushConstants data; }; -constexpr unsigned int FRAME_OVERLAP=2; +struct Vertex { + glm::vec3 position; + float uv_x; + glm::vec3 normal; + float uv_y; + glm::vec4 color; +}; + +struct GPUMeshBuffers { + AllocatedBuffer indexBuffer; + AllocatedBuffer vertexBuffer; + VkDeviceAddress vertexBufferAddress; +}; + +struct GPUDrawPushConstants { + glm::mat4 worldMatrix; + VkDeviceAddress vertexBuffer; +}; +