#include #include #include #include #include "io.h" #include "kitty.h" #include "paw_allocator.h" #include "paw_da.h" #include "vulkan_helpers.h" struct Kitty *kitty_make(struct PawMem *mem) { struct Kitty *kitty; if (mem == NULL) { kitty = malloc(sizeof(struct Kitty)); } else { kitty = paw_memmalloc(mem, sizeof(struct Kitty)); } memset(kitty, 0, sizeof(struct Kitty)); kitty->mem = mem; if (kitty->mem == NULL) { paw_da_make_inplace(&kitty->attatchments); paw_da_make_inplace(&kitty->vertex_buffer.format); paw_da_make_inplace(&kitty->instance_buffer.format); } else { paw_da_make_inplace_mem(&kitty->attatchments, kitty->mem); paw_da_make_inplace_mem(&kitty->vertex_buffer.format, kitty->mem); paw_da_make_inplace_mem(&kitty->instance_buffer.format, kitty->mem); } meow("alloced a kitty at %p", kitty); return kitty; } void kitty_set_push_constant_size(struct Kitty *kitty, uint32_t size) { kitty->push_constant_size = size; } void kitty_set_vertex_shader(struct Kitty *kitty, const char *path) { kitty->vertex_path = path; meow("vertex path is %s", path); } void kitty_set_fragment_shader(struct Kitty *kitty, const char *path) { kitty->fragment_path = path; meow("fragment path is %s", path); } void kitty_set_vertex_buffer(struct Kitty *kitty, void *data, uint32_t count, int vertex_size) { kitty->vertex_buffer.data = data; kitty->vertex_buffer.count = count; kitty->vertex_buffer.vertex_size = vertex_size; } void kitty_add_index_buffer(struct Kitty *kitty, void *data, uint32_t count) { kitty->index_buffer.data = data; 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) { paw_da_append(&kitty->instance_buffer.format, format); } void kitty_add_vertex_buffer_format(struct Kitty *kitty, enum VkFormat format) { paw_da_append(&kitty->vertex_buffer.format, format); } void kitty_attatch_image(struct Kitty *kitty, const char *path) { struct KittyAttatchment attatchment = {0}; attatchment.type = CAT_ATTATCH_IMAGE; attatchment.image.path = path; paw_da_append(&kitty->attatchments, attatchment); meow("image was attatched"); } int kitty_attatch_ubo(struct Kitty *kitty, uint32_t size) { struct KittyAttatchment attatchment = {0}; attatchment.type = CAT_ATTATCH_UBO; attatchment.ubo.size = size; paw_da_append(&kitty->attatchments, attatchment); meow("ubo of size %d was attatched", size); return kitty->attatchments.count - 1; } int kitty_attatch_ubo_array(struct Kitty *kitty, uint32_t size, uint32_t count) { struct KittyAttatchment attatchment = {0}; attatchment.type = CAT_ATTATCH_UBO_ARRAY; attatchment.ubo_array.size = size; attatchment.ubo_array.count = count; paw_da_append(&kitty->attatchments, attatchment); return kitty->attatchments.count - 1; } void kitty_finalise(struct Vk *state, struct Kitty *kitty) { kitty_create_layout_bindings(kitty, state); kitty_create_pipeline(kitty, state); kitty_create_descriptor_pool(kitty, state); kitty_create_image_attatchments(kitty, state); kitty_create_ubo_attatchments(kitty, state); kitty_create_ubo_array_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); } paw_da_append(&state->kitties, kitty); } void kitty_free(struct Vk *state, struct Kitty *kitty) { vkDeviceWaitIdle(state->device); vkDestroyBuffer(state->device, kitty->vertex_buffer.buffer, NULL); gpu_mem_free(state, state->mem, kitty->vertex_buffer.memory); if (kitty->instance_buffer.count != 0) { vkDestroyBuffer(state->device, kitty->instance_buffer.buffer, NULL); gpu_mem_free(state, state->mem, kitty->instance_buffer.memory); } vkDestroyDescriptorPool(state->device, kitty->descriptor_pool, NULL); vkDestroyDescriptorSetLayout(state->device, kitty->descriptor_set_layout, NULL); vkDestroyPipelineLayout(state->device, kitty->pipeline_layout, NULL); vkDestroyPipeline(state->device, kitty->pipeline, NULL); for (int i = 0; i < kitty->attatchments.count; i++) { switch (kitty->attatchments.items[i].type) { case CAT_ATTATCH_UBO: for (int j = 0; j < MAX_FRAMES_IN_FLIGHT; j++) { vkDestroyBuffer(state->device, kitty->attatchments.items[i].ubo.buffer[j], NULL); gpu_mem_free(state, state->mem, kitty->attatchments.items[i].ubo.memory[j]); } break; case CAT_ATTATCH_UBO_ARRAY: for (int j = 0; j < MAX_FRAMES_IN_FLIGHT; j++) { vkDestroyBuffer(state->device, kitty->attatchments.items[i].ubo_array.buffer[j], NULL); gpu_mem_free(state, state->mem, kitty->attatchments.items[i].ubo_array.memory[j]); } break; case CAT_ATTATCH_IMAGE: vkDestroyImage(state->device, kitty->attatchments.items[i].image.image, NULL); gpu_mem_free(state, state->mem, kitty->attatchments.items[i].image.memory); vkDestroyImageView(state->device, kitty->attatchments.items[i].image.view, NULL); vkDestroySampler(state->device, kitty->attatchments.items[i].image.sampler, NULL); break; } } paw_da_free(&kitty->vertex_buffer.format); paw_da_free(&kitty->attatchments); if (kitty->mem == NULL) { memset(kitty, 0, sizeof(struct Kitty)); free(kitty); } else { paw_memfree(kitty->mem, kitty); } } void kitty_set_next_push_constant(struct Kitty *kitty, void *data) { kitty->next_push_constant = data; } void kitty_set_next_ubo(struct Vk *state, struct Kitty *kitty, int index, void *data) { switch (kitty->attatchments.items[index].type) { case CAT_ATTATCH_IMAGE: meow("trying to update the contents of an image, not supported"); break; case CAT_ATTATCH_UBO:; void *dst = kitty->attatchments.items[index] .ubo.memory[state->current_frame] .mapped; void *src = data; int size = kitty->attatchments.items[index].ubo.size; memcpy(dst, src, size); break; case CAT_ATTATCH_UBO_ARRAY:; void *dst_array = kitty->attatchments.items[index] .ubo_array.memory[state->current_frame] .mapped; void *src_array = data; int size_array = kitty->attatchments.items[index].ubo_array.size * kitty->attatchments.items[index].ubo_array.count; memcpy(dst_array, src_array, size_array); break; } } void *kitty_get_next_ubo_pointer(struct Vk *state, struct Kitty *kitty, int index) { switch (kitty->attatchments.items[index].type) { case CAT_ATTATCH_IMAGE: meow("trying to update the contents of an image, not supported"); break; case CAT_ATTATCH_UBO:; return kitty->attatchments.items[index] .ubo.memory[state->current_frame] .mapped; break; case CAT_ATTATCH_UBO_ARRAY:; return kitty->attatchments.items[index] .ubo_array.memory[state->current_frame] .mapped; break; } } void kitty_draw(struct Vk *state, uint32_t image_index, struct Kitty *kitty) { struct InFlightObjects flight = state->flights[state->current_frame]; vkCmdBindPipeline(flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, kitty->pipeline); VkViewport viewport = {0}; viewport.x = 0.0f; viewport.y = 0.0f; viewport.width = state->width; viewport.height = state->heigh; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; vkCmdSetViewport(flight.command_buffer, 0, 1, &viewport); VkRect2D scissor = {0}; scissor.offset = (VkOffset2D){0, 0}; scissor.extent = (VkExtent2D){state->width, state->heigh}; vkCmdSetScissor(flight.command_buffer, 0, 1, &scissor); 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); 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) { VkDescriptorSetLayoutBinding descriptor_set_layout_binding[kitty->attatchments.count]; memset(descriptor_set_layout_binding, 0, sizeof(VkDescriptorSetLayoutBinding) * kitty->attatchments.count); meow("count is %d", kitty->attatchments.items[1].ubo_array.count); for (int index = 0; index < kitty->attatchments.count; index++) { switch (kitty->attatchments.items[index].type) { case CAT_ATTATCH_UBO: descriptor_set_layout_binding[index].binding = index; descriptor_set_layout_binding[index].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_set_layout_binding[index].descriptorCount = 1; descriptor_set_layout_binding[index].stageFlags = VK_SHADER_STAGE_ALL; descriptor_set_layout_binding[index].pImmutableSamplers = NULL; break; case CAT_ATTATCH_UBO_ARRAY: meow("count is %d", kitty->attatchments.items[index].ubo_array.count); descriptor_set_layout_binding[index].binding = index; descriptor_set_layout_binding[index].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_set_layout_binding[index].descriptorCount = kitty->attatchments.items[index].ubo_array.count; descriptor_set_layout_binding[index].stageFlags = VK_SHADER_STAGE_ALL; descriptor_set_layout_binding[index].pImmutableSamplers = NULL; break; case CAT_ATTATCH_IMAGE: descriptor_set_layout_binding[index].binding = index; descriptor_set_layout_binding[index].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_set_layout_binding[index].descriptorCount = 1; descriptor_set_layout_binding[index].stageFlags = VK_SHADER_STAGE_ALL; descriptor_set_layout_binding[index].pImmutableSamplers = NULL; break; } } VkDescriptorSetLayoutCreateInfo layout_info = {0}; layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layout_info.bindingCount = kitty->attatchments.count; layout_info.pBindings = descriptor_set_layout_binding; CHECK_VK_RESULT(vkCreateDescriptorSetLayout(state->device, &layout_info, NULL, &kitty->descriptor_set_layout)); } void kitty_create_pipeline(struct Kitty *kitty, struct Vk *state) { int vert_size, frag_size; uint32_t *vert_shader = read_binary_file((char *)kitty->vertex_path, &vert_size); uint32_t *frag_shader = read_binary_file((char *)kitty->fragment_path, &frag_size); VkShaderModule vert_module = create_shader_module(state, vert_shader, vert_size); VkShaderModule frag_module = create_shader_module(state, frag_shader, frag_size); VkPipelineShaderStageCreateInfo vert_stage_info = {0}; vert_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vert_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; vert_stage_info.module = vert_module; vert_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo frag_stage_info = {0}; frag_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; frag_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; frag_stage_info.module = frag_module; frag_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo shader_stage_info[] = {vert_stage_info, frag_stage_info}; VkPipelineVertexInputStateCreateInfo vertex_input_info = {0}; 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 = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; input_assembly_info.primitiveRestartEnable = VK_FALSE; VkPipelineViewportStateCreateInfo viewport_state_info = {0}; viewport_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_state_info.viewportCount = 1; viewport_state_info.scissorCount = 1; VkPipelineRasterizationStateCreateInfo rasterizer_info = {0}; rasterizer_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; rasterizer_info.depthClampEnable = VK_FALSE; rasterizer_info.rasterizerDiscardEnable = VK_FALSE; rasterizer_info.polygonMode = VK_POLYGON_MODE_FILL; rasterizer_info.lineWidth = 1.0f; rasterizer_info.cullMode = VK_CULL_MODE_BACK_BIT; rasterizer_info.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer_info.depthBiasEnable = VK_FALSE; VkPipelineMultisampleStateCreateInfo multisampling_info = {0}; multisampling_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling_info.sampleShadingEnable = VK_FALSE; multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_blend_attachment = {0}; color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; color_blend_attachment.blendEnable = VK_TRUE; color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; VkPipelineColorBlendStateCreateInfo color_blend_info = {0}; color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; color_blend_info.logicOpEnable = VK_FALSE; color_blend_info.logicOp = VK_LOGIC_OP_COPY; color_blend_info.attachmentCount = 1; color_blend_info.pAttachments = &color_blend_attachment; /* VkPushConstantRange push_constant_range = {0}; */ /* push_constant_range.offset = 0; */ /* push_constant_range.size = kitty->push_constant_size; */ /* push_constant_range.stageFlags = VK_SHADER_STAGE_ALL; */ VkPipelineLayoutCreateInfo pipeline_layout_info = {0}; pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_info.setLayoutCount = 1; pipeline_layout_info.pSetLayouts = &kitty->descriptor_set_layout; pipeline_layout_info.pushConstantRangeCount = 0; // TODO pipeline_layout_info.pPushConstantRanges = NULL; CHECK_VK_RESULT(vkCreatePipelineLayout(state->device, &pipeline_layout_info, NULL, &kitty->pipeline_layout)); VkDynamicState dynamic_states[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo dynamic_state_info = {0}; dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state_info.pDynamicStates = dynamic_states; dynamic_state_info.dynamicStateCount = sizeof(dynamic_states) / sizeof(dynamic_states[0]); VkGraphicsPipelineCreateInfo pipeline_info = {0}; pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipeline_info.stageCount = 2; pipeline_info.pStages = shader_stage_info; pipeline_info.pVertexInputState = &vertex_input_info; pipeline_info.pInputAssemblyState = &input_assembly_info; pipeline_info.pViewportState = &viewport_state_info; pipeline_info.pRasterizationState = &rasterizer_info; pipeline_info.pMultisampleState = &multisampling_info; pipeline_info.pDepthStencilState = NULL; pipeline_info.pColorBlendState = &color_blend_info; pipeline_info.pDynamicState = &dynamic_state_info; pipeline_info.layout = kitty->pipeline_layout; pipeline_info.renderPass = state->render_pass; pipeline_info.subpass = 0; pipeline_info.basePipelineHandle = NULL; pipeline_info.basePipelineIndex = -1; CHECK_VK_RESULT(vkCreateGraphicsPipelines( state->device, NULL, 1, &pipeline_info, NULL, &kitty->pipeline)); vkDestroyShaderModule(state->device, vert_module, NULL); vkDestroyShaderModule(state->device, frag_module, NULL); free(vert_shader); free(frag_shader); } void kitty_create_descriptor_pool(struct Kitty *kitty, struct Vk *state) { int ubo_count = 0; int image_count = 0; for (int i = 0; i < kitty->attatchments.count; i++) { switch (kitty->attatchments.items[i].type) { case CAT_ATTATCH_UBO: case CAT_ATTATCH_UBO_ARRAY: ubo_count++; break; case CAT_ATTATCH_IMAGE: image_count++; break; } } VkDescriptorPoolSize pool_sizes[2] = {0}; pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pool_sizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; pool_sizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT; VkDescriptorPoolCreateInfo pool_info = {0}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.poolSizeCount = 2; pool_info.pPoolSizes = pool_sizes; pool_info.maxSets = 10; CHECK_VK_RESULT(vkCreateDescriptorPool(state->device, &pool_info, NULL, &kitty->descriptor_pool)); } void kitty_create_image_attatchments(struct Kitty *kitty, struct Vk *state) { for (int index = 0; index < kitty->attatchments.count; index++) { if (kitty->attatchments.items[index].type != CAT_ATTATCH_IMAGE) { continue; } struct KittyAttatchment *atch = &kitty->attatchments.items[index]; atch->image.pixels = load_image(atch->image.path, &atch->image.dims); atch->image.size = atch->image.dims.x * atch->image.dims.y * 4; VkBuffer staging_buffer; struct GpuPointer staging_buffer_memory; create_buffer(state, atch->image.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer, &staging_buffer_memory); memcpy(staging_buffer_memory.mapped, atch->image.pixels, atch->image.size); create_image(state, atch->image.dims, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &atch->image.image, &atch->image.memory); transition_image_layout(state, atch->image.image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); copy_buffer_to_image(state, staging_buffer, atch->image.image, atch->image.dims); transition_image_layout(state, atch->image.image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); vkDestroyBuffer(state->device, staging_buffer, NULL); gpu_mem_free(state, state->mem, staging_buffer_memory); VkImageViewCreateInfo view_info = {0}; view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_info.image = atch->image.image; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = VK_FORMAT_R8G8B8A8_SRGB; view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view_info.subresourceRange.baseMipLevel = 0; view_info.subresourceRange.levelCount = 1; view_info.subresourceRange.baseArrayLayer = 0; view_info.subresourceRange.layerCount = 1; CHECK_VK_RESULT( vkCreateImageView(state->device, &view_info, NULL, &atch->image.view)); VkSamplerCreateInfo sampler_info = {0}; sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_info.magFilter = VK_FILTER_NEAREST; sampler_info.minFilter = VK_FILTER_NEAREST; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.anisotropyEnable = VK_FALSE; sampler_info.maxAnisotropy = 1.0f; sampler_info.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; sampler_info.unnormalizedCoordinates = VK_FALSE; sampler_info.compareEnable = VK_FALSE; sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; sampler_info.mipLodBias = 0.0f; sampler_info.minLod = 0.0; sampler_info.maxLod = 0.0; CHECK_VK_RESULT(vkCreateSampler(state->device, &sampler_info, NULL, &atch->image.sampler)); free(atch->image.pixels); } } void kitty_create_ubo_attatchments(struct Kitty *kitty, struct Vk *state) { for (int index = 0; index < kitty->attatchments.count; index++) { if (kitty->attatchments.items[index].type != CAT_ATTATCH_UBO) { continue; } for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { create_buffer(state, kitty->attatchments.items[index].ubo.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &kitty->attatchments.items[index].ubo.buffer[i], &kitty->attatchments.items[index].ubo.memory[i]); } } } void kitty_create_ubo_array_attatchments(struct Kitty *kitty, struct Vk *state) { for (int index = 0; index < kitty->attatchments.count; index++) { if (kitty->attatchments.items[index].type != CAT_ATTATCH_UBO_ARRAY) { continue; } for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { create_buffer(state, kitty->attatchments.items[index].ubo_array.size * kitty->attatchments.items[index].ubo_array.count, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &kitty->attatchments.items[index].ubo_array.buffer[i], &kitty->attatchments.items[index].ubo_array.memory[i]); } } } void kitty_create_descriptor_sets(struct Kitty *kitty, struct Vk *state) { VkDescriptorSetLayout set_layouts[MAX_FRAMES_IN_FLIGHT]; for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { set_layouts[i] = kitty->descriptor_set_layout; } VkDescriptorSetAllocateInfo alloc_info = {0}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = kitty->descriptor_pool; alloc_info.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; alloc_info.pSetLayouts = set_layouts; CHECK_VK_RESULT(vkAllocateDescriptorSets(state->device, &alloc_info, kitty->descriptor_sets)); for (int index = 0; index < kitty->attatchments.count; index++) { for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { switch (kitty->attatchments.items[index].type) { case CAT_ATTATCH_UBO:; VkDescriptorBufferInfo buffer_info = {0}; buffer_info.buffer = kitty->attatchments.items[index].ubo.buffer[i]; buffer_info.offset = 0; buffer_info.range = kitty->attatchments.items[index].ubo.size; VkWriteDescriptorSet write_buffer = {0}; write_buffer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_buffer.dstSet = kitty->descriptor_sets[i]; write_buffer.dstBinding = index; write_buffer.dstArrayElement = 0; write_buffer.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; write_buffer.descriptorCount = 1; write_buffer.pBufferInfo = &buffer_info; vkUpdateDescriptorSets(state->device, 1, &write_buffer, 0, NULL); break; case CAT_ATTATCH_UBO_ARRAY:; for (int j = 0; j < kitty->attatchments.items[index].ubo_array.count; j++) { VkDescriptorBufferInfo array_buffer_info = {0}; array_buffer_info.buffer = kitty->attatchments.items[index].ubo_array.buffer[i]; array_buffer_info.offset = 0; array_buffer_info.range = kitty->attatchments.items[index].ubo_array.size * kitty->attatchments.items[index].ubo_array.count; VkWriteDescriptorSet write_array_buffer = {0}; write_array_buffer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_array_buffer.dstSet = kitty->descriptor_sets[i]; write_array_buffer.dstBinding = index; write_array_buffer.dstArrayElement = j; write_array_buffer.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; write_array_buffer.descriptorCount = 1; write_array_buffer.pBufferInfo = &array_buffer_info; vkUpdateDescriptorSets(state->device, 1, &write_array_buffer, 0, NULL); } break; case CAT_ATTATCH_IMAGE:; VkDescriptorImageInfo image_info = {0}; image_info.imageLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; image_info.imageView = kitty->attatchments.items[index].image.view; image_info.sampler = kitty->attatchments.items[index].image.sampler; VkWriteDescriptorSet write_image = {0}; write_image.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_image.dstSet = kitty->descriptor_sets[i]; write_image.dstBinding = index; write_image.dstArrayElement = 0; write_image.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write_image.descriptorCount = 1; write_image.pImageInfo = &image_info; vkUpdateDescriptorSets(state->device, 1, &write_image, 0, NULL); break; } } } } void kitty_create_vertex_buffer(struct Kitty *kitty, struct Vk *state) { VkDeviceSize size = kitty->vertex_buffer.count * kitty->vertex_buffer.vertex_size; VkBuffer staging_buffer; struct GpuPointer 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); memcpy(staging_buffer_memory.mapped, kitty->vertex_buffer.data, size); create_buffer(state, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &kitty->vertex_buffer.buffer, &kitty->vertex_buffer.memory); copy_buffer(state, staging_buffer, kitty->vertex_buffer.buffer, size); vkDestroyBuffer(state->device, staging_buffer, NULL); gpu_mem_free(state, state->mem, staging_buffer_memory); 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; struct GpuPointer 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); memcpy(staging_buffer_memory.mapped, kitty->instance_buffer.data, size); 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); gpu_mem_free(state, state->mem, staging_buffer_memory); kitty->instance_buffer.data = NULL; }