Expanded basic program to use a vertex buffer via the new basalt::Buffer

Updated vertex function get_attribute_descriptions to conform to new standard for template-based binding
Moved definition of triangle verticies inside of the application function
Maps, copies into and unmaps the vertex buffer from the darray<Vertex>
Uses a reference to refer to the current frames command buffer to not repeat the ugly indexing
render area and viewport extent is updated every frame with the swapchain extent
No longer directly recreate the framebuffers, now using the recreate function with the renderpass passed as a paramater
This commit is contained in:
2025-07-10 22:00:35 +10:00
parent 8858c89f30
commit c87271d2f5

View File

@@ -3,6 +3,7 @@
#include "vulkan/basalt_command_buffer.h" #include "vulkan/basalt_command_buffer.h"
#include "vulkan/basalt_swapchain.h" #include "vulkan/basalt_swapchain.h"
#include "vulkan/basalt_buffer.h"
#include <glm/glm.hpp> #include <glm/glm.hpp>
struct Vertex struct Vertex
@@ -11,19 +12,19 @@ struct Vertex
glm::vec3 colour; glm::vec3 colour;
static VkVertexInputBindingDescription get_binding_description(void); static VkVertexInputBindingDescription get_binding_description(void);
static VkResult get_attribute_descriptions(VkVertexInputAttributeDescription** out_attributes, u32* out_num_attributes); static VkResult get_attribute_descriptions(VkVertexInputAttributeDescription* out_attributes, u32* out_num_attributes);
}; };
static basalt::darray<Vertex> verts({
{{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}}
}, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_32);
void framebuffer_resized(GLFWwindow* window, int width, int height); void framebuffer_resized(GLFWwindow* window, int width, int height);
void application() void application()
{ {
basalt::darray<Vertex> verts({
{{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}}
}, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_32);
VkResult err = VK_SUCCESS; VkResult err = VK_SUCCESS;
basalt::Context ctx("Basic", basalt::Context ctx("Basic",
@@ -87,9 +88,6 @@ void application()
}) })
.build(); .build();
VkVertexInputAttributeDescription* vertex_attribs = nullptr;
u32 num_vertex_attribs = 0;
VK_ASSERT(Vertex::get_attribute_descriptions(&vertex_attribs, &num_vertex_attribs), "Failed to get vertex input attribute description(s)\n\tAt %s:%d\n\tError %s\n\tVertex class %s\n", typeid(Vertex).name());
basalt::Pipeline pipeline = basalt::PipelineBuilder(dev, swapchain.swapchain_extent, VK_NULL_HANDLE) basalt::Pipeline pipeline = basalt::PipelineBuilder(dev, swapchain.swapchain_extent, VK_NULL_HANDLE)
.add_dynamic_state(VK_DYNAMIC_STATE_SCISSOR) .add_dynamic_state(VK_DYNAMIC_STATE_SCISSOR)
.add_dynamic_state(VK_DYNAMIC_STATE_VIEWPORT) .add_dynamic_state(VK_DYNAMIC_STATE_VIEWPORT)
@@ -106,12 +104,18 @@ void application()
}) })
.add_shader("shaders/out/simple.vert.spv", VK_SHADER_STAGE_VERTEX_BIT) .add_shader("shaders/out/simple.vert.spv", VK_SHADER_STAGE_VERTEX_BIT)
.add_shader("shaders/out/simple.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT) .add_shader("shaders/out/simple.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT)
.add_vertex_binding(Vertex::get_binding_description(), vertex_attribs, num_vertex_attribs) .add_vertex_binding<Vertex>()
.build(); .build();
basalt::mem::dealloc(vertex_attribs, sizeof(VkVertexInputAttributeDescription) * num_vertex_attribs, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_ANY);
swapchain.create_framebuffers(pass.render_pass); swapchain.create_framebuffers(pass.render_pass);
basalt::Buffer vertex_buffer(dev, verts.m_nelements * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
{
void* dst = vertex_buffer.map();
memcpy(dst, verts.m_pdata, vertex_buffer.size);
vertex_buffer.unmap();
}
basalt::CommandPool cmdpool(dev, phy_dev.indicies.graphics); basalt::CommandPool cmdpool(dev, phy_dev.indicies.graphics);
basalt::darray<basalt::CommandBuffer> cmdbufs(swapchain.max_frames_in_flight, MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_32); basalt::darray<basalt::CommandBuffer> cmdbufs(swapchain.max_frames_in_flight, MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_32);
for (u32 i = 0; i < swapchain.max_frames_in_flight; ++i) for (u32 i = 0; i < swapchain.max_frames_in_flight; ++i)
@@ -133,32 +137,41 @@ void application()
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f .maxDepth = 1.0f
}; };
VkBuffer buffers[] = { vertex_buffer.buffer };
VkDeviceSize offsets[] = { 0 };
while (!window.should_close()) while (!window.should_close())
{ {
render_area.extent = swapchain.swapchain_extent;
viewport.width = render_area.extent.width;
viewport.height = render_area.extent.height;
glfwPollEvents(); glfwPollEvents();
basalt::CommandBuffer& cmdbuf = cmdbufs[swapchain.current_frame];
u32 image_index = swapchain.wait_acquire_reset(); u32 image_index = swapchain.wait_acquire_reset();
if (image_index == -1 || !swapchain.framebuffers_created) if (image_index == -1 || !swapchain.framebuffers_created)
{ {
swapchain.create_framebuffers(pass.render_pass); swapchain.recreate(pass.render_pass);
swapchain.current_frame = (swapchain.current_frame + 1) % swapchain.max_frames_in_flight; swapchain.current_frame = (swapchain.current_frame + 1) % swapchain.max_frames_in_flight;
continue; continue;
} }
cmdbufs[swapchain.current_frame].reset(); cmdbuf.reset();
cmdbufs[swapchain.current_frame].start(pass, swapchain.framebuffers[image_index], render_area); cmdbuf.start(pass, swapchain.framebuffers[image_index], render_area);
cmdbufs[swapchain.current_frame].bind_pipeline(pipeline, VK_PIPELINE_BIND_POINT_GRAPHICS); cmdbuf.bind_pipeline(pipeline, VK_PIPELINE_BIND_POINT_GRAPHICS);
cmdbufs[swapchain.current_frame].set_scissor(render_area); vkCmdBindVertexBuffers(cmdbuf.vk, 0, sizeof(buffers) / sizeof(buffers[0]), buffers, offsets);
cmdbufs[swapchain.current_frame].set_viewport(viewport); cmdbuf.set_scissor(render_area);
vkCmdDraw(cmdbufs[swapchain.current_frame].vk, 3, 1, 0, 0); cmdbuf.set_viewport(viewport);
cmdbufs[swapchain.current_frame].stop(); vkCmdDraw(cmdbuf.vk, vertex_buffer.size / sizeof(Vertex), 1, 0, 0);
cmdbuf.stop();
VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO}; VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
VkSemaphore wait_semaphores[] = {swapchain.semaphores_image_available[swapchain.current_frame]}; VkSemaphore wait_semaphores[] = {swapchain.semaphores_image_available[swapchain.current_frame]};
VkSemaphore signal_semaphores[] = {swapchain.semaphores_render_finished[image_index]}; VkSemaphore signal_semaphores[] = {swapchain.semaphores_render_finished[image_index]};
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submit_info.commandBufferCount = 1; submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmdbufs[swapchain.current_frame].vk; submit_info.pCommandBuffers = &cmdbuf.vk;
submit_info.waitSemaphoreCount = 1; submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = wait_semaphores; submit_info.pWaitSemaphores = wait_semaphores;
submit_info.pWaitDstStageMask = wait_stages; submit_info.pWaitDstStageMask = wait_stages;
@@ -227,20 +240,28 @@ VkVertexInputBindingDescription Vertex::get_binding_description(void)
return ret; return ret;
} }
VkResult Vertex::get_attribute_descriptions(VkVertexInputAttributeDescription** out_attributes, u32* out_num_attributes) VkResult Vertex::get_attribute_descriptions(VkVertexInputAttributeDescription* out_attributes, u32* out_num_attributes)
{ {
*out_attributes = basalt::mem::allocT<VkVertexInputAttributeDescription>(2, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_APPLICATION | MEMORY_TAG_ALIGN_ANY); constexpr u32 num_attribs = 2;
if (out_attributes == nullptr) if (out_attributes == nullptr)
return VK_ERROR_OUT_OF_HOST_MEMORY; {
*out_num_attributes = 2; *out_num_attributes = num_attribs;
VkVertexInputAttributeDescription* ptr = *out_attributes; return VK_SUCCESS;
ptr[0].binding = 0; }
ptr[0].location = 0; BASSERT_ERROR(*out_num_attributes == num_attribs,
ptr[0].format = VK_FORMAT_R32G32_SFLOAT; return VK_ERROR_OUT_OF_HOST_MEMORY;,
ptr[0].offset = offsetof(Vertex, pos); "Assertion %s failed at %s:%d\n\tAttempted to get attribute descriptions for object type %s but the allocated size %u was not sufficient. Expected %u\n",
ptr[1].binding = 0; typeid(Vertex).name(), out_num_attributes, num_attribs
ptr[1].location = 1; );
ptr[1].format = VK_FORMAT_R32G32B32_SFLOAT;
ptr[1].offset = offsetof(Vertex, colour); out_attributes[0].binding = 0;
out_attributes[0].location = 0;
out_attributes[0].format = VK_FORMAT_R32G32_SFLOAT;
out_attributes[0].offset = offsetof(Vertex, pos);
out_attributes[1].binding = 0;
out_attributes[1].location = 1;
out_attributes[1].format = VK_FORMAT_R32G32B32_SFLOAT;
out_attributes[1].offset = offsetof(Vertex, colour);
return VK_SUCCESS; return VK_SUCCESS;
} }