Add instanced rendering :3

This commit is contained in:
Luna 2025-02-16 19:42:55 +01:00
parent 988e00fd2e
commit 95d90bfbd9
4 changed files with 157 additions and 32 deletions

View file

@ -2,6 +2,7 @@
layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in mat3 offset;
layout(set = 0, binding = 0) uniform UBO {
mat3 model;
@ -13,7 +14,7 @@ layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragUV;
void main() {
gl_Position = vec4(ubo.proj * ubo.view * ubo.model * vec3(inPosition, 1.0), 1.0);
gl_Position = vec4(ubo.proj * ubo.view * offset * ubo.model * vec3(inPosition, 1.0), 1.0);
fragColor = inColor;
fragUV = inPosition;
}

167
kitty.c
View file

@ -13,6 +13,7 @@ struct Kitty *kitty_make() {
memset(kitty, 0, sizeof(struct Kitty));
dyn_array_create_inplace(&kitty->attatchments);
dyn_array_create_inplace(&kitty->vertex_buffer.format);
dyn_array_create_inplace(&kitty->instance_buffer.format);
meow("alloced a kitty at %p", kitty);
return kitty;
}
@ -40,8 +41,18 @@ void kitty_add_index_buffer(struct Kitty *kitty, void *data, uint32_t count) {
kitty->index_buffer.count = count;
}
void kitty_add_instance_buffer(struct Kitty *kitty, void *data, uint32_t count,
int element_size) {
kitty->instance_buffer.data = data;
kitty->instance_buffer.count = count;
kitty->instance_buffer.element_size = element_size;
}
void kitty_add_instance_buffer_format(struct Kitty *kitty,
enum VkFormat format) {
dyn_array_append(&kitty->instance_buffer.format, format);
}
void kitty_add_vertex_buffer_format(struct Kitty *kitty, enum VkFormat format) {
meow("attatched %d to the buffer", format);
dyn_array_append(&kitty->vertex_buffer.format, format);
}
void kitty_attatch_image(struct Kitty *kitty, const char *path) {
@ -68,6 +79,9 @@ void kitty_finalise(struct Vk *state, struct Kitty *kitty) {
kitty_create_ubo_attatchments(kitty, state);
kitty_create_descriptor_sets(kitty, state);
kitty_create_vertex_buffer(kitty, state);
if (kitty->instance_buffer.count != 0) {
kitty_create_instance_buffer(kitty, state);
}
dyn_array_append(&state->kitties, kitty);
}
@ -76,6 +90,10 @@ void free_kitty(struct Vk *state, struct Kitty *kitty) {
vkDeviceWaitIdle(state->device);
vkDestroyBuffer(state->device, kitty->vertex_buffer.buffer, NULL);
vkFreeMemory(state->device, kitty->vertex_buffer.memory, NULL);
if (kitty->instance_buffer.count != 0) {
vkDestroyBuffer(state->device, kitty->instance_buffer.buffer, NULL);
vkFreeMemory(state->device, kitty->instance_buffer.memory, NULL);
}
vkDestroyDescriptorPool(state->device, kitty->descriptor_pool, NULL);
vkDestroyDescriptorSetLayout(state->device, kitty->descriptor_set_layout,
NULL);
@ -142,16 +160,26 @@ void kitty_draw(struct Vk *state, uint32_t image_index, struct Kitty *kitty) {
scissor.extent = (VkExtent2D){state->width, state->heigh};
vkCmdSetScissor(flight.command_buffer, 0, 1, &scissor);
VkBuffer vertex_buffer[] = {kitty->vertex_buffer.buffer};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(flight.command_buffer, 0, 1, vertex_buffer, offsets);
uint64_t offsets[1] = {0};
vkCmdBindVertexBuffers(flight.command_buffer, 0, 1,
&kitty->vertex_buffer.buffer, offsets);
if (kitty->instance_buffer.count != 0) {
vkCmdBindVertexBuffers(flight.command_buffer, 1, 1,
&kitty->instance_buffer.buffer, offsets);
}
vkCmdBindDescriptorSets(
flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
kitty->pipeline_layout, 0, 1,
&kitty->descriptor_sets[state->current_frame], 0, NULL);
vkCmdDraw(flight.command_buffer, kitty->vertex_buffer.count, 1, 0, 0);
if (kitty->instance_buffer.count == 0) {
vkCmdDraw(flight.command_buffer, kitty->vertex_buffer.count, 1, 0, 0);
} else {
vkCmdDraw(flight.command_buffer, kitty->vertex_buffer.count,
kitty->instance_buffer.count, 0, 0);
}
}
void kitty_create_layout_bindings(struct Kitty *kitty, struct Vk *state) {
@ -210,33 +238,79 @@ void kitty_create_pipeline(struct Kitty *kitty, struct Vk *state) {
VkPipelineShaderStageCreateInfo shader_stage_info[] = {vert_stage_info,
frag_stage_info};
VkVertexInputBindingDescription vertex_binding_description = {0};
vertex_binding_description.binding = 0;
vertex_binding_description.stride = kitty->vertex_buffer.vertex_size;
vertex_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription *vertex_attribute_descriptions =
alloca(sizeof(VkVertexInputAttributeDescription) *
kitty->vertex_buffer.format.count);
int offset = 0;
for (int i = 0; i < kitty->vertex_buffer.format.count; i++) {
vertex_attribute_descriptions[i].binding = 0;
vertex_attribute_descriptions[i].location = i;
vertex_attribute_descriptions[i].format =
kitty->vertex_buffer.format.items[i];
vertex_attribute_descriptions[i].offset = offset;
offset += get_size_of_format(kitty->vertex_buffer.format.items[i]);
}
VkPipelineVertexInputStateCreateInfo vertex_input_info = {0};
vertex_input_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description;
vertex_input_info.vertexAttributeDescriptionCount =
kitty->vertex_buffer.format.count;
vertex_input_info.pVertexAttributeDescriptions =
vertex_attribute_descriptions;
if (kitty->instance_buffer.count == 0) {
meow("single instance kitty");
VkVertexInputBindingDescription vertex_binding_description = {0};
vertex_binding_description.binding = 0;
vertex_binding_description.stride = kitty->vertex_buffer.vertex_size;
vertex_binding_description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkVertexInputAttributeDescription *vertex_attribute_descriptions =
alloca(sizeof(VkVertexInputAttributeDescription) *
kitty->vertex_buffer.format.count);
int offset = 0;
for (int i = 0; i < kitty->vertex_buffer.format.count; i++) {
vertex_attribute_descriptions[i].binding = 0;
vertex_attribute_descriptions[i].location = i;
vertex_attribute_descriptions[i].format =
kitty->vertex_buffer.format.items[i];
vertex_attribute_descriptions[i].offset = offset;
offset += get_size_of_format(kitty->vertex_buffer.format.items[i]);
}
vertex_input_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description;
vertex_input_info.vertexAttributeDescriptionCount =
kitty->vertex_buffer.format.count;
vertex_input_info.pVertexAttributeDescriptions =
vertex_attribute_descriptions;
} else {
meow("multi instance kitty");
VkVertexInputBindingDescription binding_descriptions[2] = {0};
binding_descriptions[0].binding = 0;
binding_descriptions[0].stride = kitty->vertex_buffer.vertex_size;
binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
binding_descriptions[1].binding = 1;
binding_descriptions[1].stride = kitty->instance_buffer.element_size;
binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
VkVertexInputAttributeDescription *attribute_descriptions =
alloca(sizeof(VkVertexInputAttributeDescription) *
kitty->vertex_buffer.format.count +
sizeof(VkVertexInputAttributeDescription) *
kitty->instance_buffer.format.count);
int offset = 0;
for (int i = 0; i < kitty->vertex_buffer.format.count; i++) {
attribute_descriptions[i].binding = 0;
attribute_descriptions[i].location = i;
attribute_descriptions[i].format = kitty->vertex_buffer.format.items[i];
attribute_descriptions[i].offset = offset;
offset += get_size_of_format(kitty->vertex_buffer.format.items[i]);
}
offset = 0;
for (int i = 0; i < kitty->instance_buffer.format.count; i++) {
attribute_descriptions[i + kitty->vertex_buffer.format.count].binding = 1;
attribute_descriptions[i + kitty->vertex_buffer.format.count].location =
i + kitty->vertex_buffer.format.count;
attribute_descriptions[i + kitty->vertex_buffer.format.count].format =
kitty->instance_buffer.format.items[i];
attribute_descriptions[i + kitty->vertex_buffer.format.count].offset =
offset;
offset += get_size_of_format(kitty->instance_buffer.format.items[i]);
}
vertex_input_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 2;
vertex_input_info.pVertexBindingDescriptions = binding_descriptions;
vertex_input_info.vertexAttributeDescriptionCount =
kitty->vertex_buffer.format.count + kitty->instance_buffer.format.count;
vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions;
}
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {0};
input_assembly_info.sType =
@ -543,3 +617,36 @@ void kitty_create_vertex_buffer(struct Kitty *kitty, struct Vk *state) {
vkFreeMemory(state->device, staging_buffer_memory, NULL);
kitty->vertex_buffer.data = NULL;
}
void kitty_create_instance_buffer(struct Kitty *kitty, struct Vk *state) {
if (kitty->instance_buffer.count == 0) {
crash("trying to create an instance buffer for a kitty that is not "
"instanced :o");
}
VkDeviceSize size =
kitty->instance_buffer.count * kitty->instance_buffer.element_size;
VkBuffer staging_buffer;
VkDeviceMemory staging_buffer_memory;
create_buffer(state, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&staging_buffer, &staging_buffer_memory);
void *data;
vkMapMemory(state->device, staging_buffer_memory, 0, size, 0, &data);
memcpy(data, kitty->instance_buffer.data, size);
vkUnmapMemory(state->device, staging_buffer_memory);
create_buffer(state, size,
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&kitty->instance_buffer.buffer, &kitty->instance_buffer.memory);
copy_buffer(state, staging_buffer, kitty->instance_buffer.buffer, size);
vkDestroyBuffer(state->device, staging_buffer, NULL);
vkFreeMemory(state->device, staging_buffer_memory, NULL);
kitty->instance_buffer.data = NULL;
}

View file

@ -42,6 +42,7 @@ struct Kitty {
const char *fragment_path;
struct VertexBuffer vertex_buffer;
struct InstanceBuffer instance_buffer;
struct IndexBuffer index_buffer;
struct da_Attatchment attatchments;
@ -68,6 +69,13 @@ void kitty_add_vertex_buffer_format(struct Kitty *thingy, enum VkFormat format);
// transferred
void kitty_add_index_buffer(struct Kitty *kitty, void *data, uint32_t count);
// 'data' can be freed after 'kitty_finalise' is called, ownership is not
// transferred
void kitty_add_instance_buffer(struct Kitty *kitty, void *data, uint32_t count,
int element_size);
void kitty_add_instance_buffer_format(struct Kitty *kitty,
enum VkFormat format);
void kitty_set_push_constant_size(struct Kitty *thingy, uint32_t size);
// the returned number can be used in 'kitty_set_next_ubo' to update the content
@ -92,5 +100,6 @@ void kitty_create_image_attatchments(struct Kitty *kitty, struct Vk *state);
void kitty_create_ubo_attatchments(struct Kitty *kitty, struct Vk *state);
void kitty_create_descriptor_sets(struct Kitty *kitty, struct Vk *state);
void kitty_create_vertex_buffer(struct Kitty *kitty, struct Vk *state);
void kitty_create_instance_buffer(struct Kitty *kitty, struct Vk *state);
#endif // INCLUDE_KITTY

View file

@ -28,7 +28,15 @@ struct VertexBuffer {
VkDeviceMemory memory;
uint32_t count;
int vertex_size;
int binding;
struct da_VK_FORMAT format;
};
struct InstanceBuffer {
void *data;
VkBuffer buffer;
VkDeviceMemory memory;
uint32_t count;
int element_size;
struct da_VK_FORMAT format;
};