diff --git a/Shaders/shader.vert b/Shaders/shader.vert index c87c266..fd52797 100644 --- a/Shaders/shader.vert +++ b/Shaders/shader.vert @@ -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; } diff --git a/kitty.c b/kitty.c index f6f36eb..db687c0 100644 --- a/kitty.c +++ b/kitty.c @@ -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; +} diff --git a/kitty.h b/kitty.h index e635e45..8d17280 100644 --- a/kitty.h +++ b/kitty.h @@ -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 diff --git a/vulkan.h b/vulkan.h index b9dd1f4..71ce01e 100644 --- a/vulkan.h +++ b/vulkan.h @@ -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; };