#include #include #include #include #include "dynarray.h" #include "image.h" #include "io.h" #include "vulkan.h" #include "vulkan_helpers.c" enum AttatchType { CAT_ATTATCH_IMAGE, CAT_ATTATCH_UBO, }; struct Attatchment { enum AttatchType type; union { struct { const char *path; uchar *pixels; struct IVec2 dims; VkDeviceSize size; VkImage image; VkImageView view; VkSampler sampler; VkDeviceMemory memory; } image; struct { uint32_t size; void *mapped[MAX_FRAMES_IN_FLIGHT]; VkBuffer buffer[MAX_FRAMES_IN_FLIGHT]; VkDeviceMemory memory[MAX_FRAMES_IN_FLIGHT]; } ubo; }; }; dyn_array_define(da_Attatchment, struct Attatchment); struct Kitty { VkPipeline pipeline; VkPipelineLayout pipeline_layout; const char *vertex_path; const char *fragment_path; struct VertexBuffer vertex_buffer; struct da_Attatchment attatchments; uint32_t push_constant_size; void *next_push_constant; VkDescriptorPool descriptor_pool; VkDescriptorSetLayout descriptor_set_layout; VkDescriptorSet descriptor_sets[MAX_FRAMES_IN_FLIGHT]; }; struct Kitty *kitty_make() { struct Kitty *thingy = malloc(sizeof(struct Kitty)); memset(thingy, 0, sizeof(struct Kitty)); dyn_array_create_inplace(&thingy->attatchments); dyn_array_create_inplace(&thingy->vertex_buffer.format); meow("alloced a thingy at %p", thingy); return thingy; } void kitty_set_push_constant_size(struct Kitty *thingy, uint32_t size) { thingy->push_constant_size = size; } void kitty_set_vertex_shader(struct Kitty *thingy, const char *path) { thingy->vertex_path = path; meow("vertex path is %s", path); } void kitty_set_fragment_shader(struct Kitty *thingy, const char *path) { thingy->fragment_path = path; meow("fragment path is %s", path); } void kitty_set_vertex_buffer(struct Kitty *thingy, void *data, uint32_t count, int vertex_size) { thingy->vertex_buffer.data = data; thingy->vertex_buffer.count = count; thingy->vertex_buffer.vertex_size = vertex_size; } void kitty_add_vertex_buffer_format(struct Kitty *thingy, enum VkFormat format) { meow("attatched %d to the buffer", format); dyn_array_append(&thingy->vertex_buffer.format, format); } void kitty_attatch_image(struct Kitty *thingy, const char *path) { struct Attatchment attatchment = {0}; attatchment.type = CAT_ATTATCH_IMAGE; attatchment.image.path = path; dyn_array_append(&thingy->attatchments, attatchment); meow("image was attatched"); } int kitty_attatch_ubo(struct Kitty *thingy, uint32_t size) { struct Attatchment attatchment = {0}; attatchment.type = CAT_ATTATCH_UBO; attatchment.ubo.size = size; dyn_array_append(&thingy->attatchments, attatchment); meow("ubo of size %d was attatched", size); return thingy->attatchments.count - 1; } void kitty_finalise(struct Vk *state, struct Kitty *kitty) { meow("this thingy has %d ubos", kitty->attatchments.count); if (kitty->vertex_path == NULL) { meow("a kitty has no vertex shader :c"); return; } if (kitty->fragment_path == NULL) { meow("a kitty has no fragment shader :c"); return; } VkDescriptorSetLayoutBinding descriptor_set_layout_binding[kitty->attatchments.count]; memset(descriptor_set_layout_binding, 0, sizeof(VkDescriptorSetLayoutBinding) * kitty->attatchments.count); for (int index = 0; index < kitty->attatchments.count; index++) { if (kitty->attatchments.items[index].type == 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; } else { 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; } } 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)); 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}; 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; 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_FALSE; 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 = thingy->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)); 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: 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)); for (int index = 0; index < kitty->attatchments.count; index++) { if (kitty->attatchments.items[index].type != CAT_ATTATCH_IMAGE) { continue; } struct Attatchment *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; VkDeviceMemory 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); void *data; vkMapMemory(state->device, staging_buffer_memory, 0, atch->image.size, 0, &data); memcpy(data, atch->image.pixels, atch->image.size); vkUnmapMemory(state->device, staging_buffer_memory); 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); vkFreeMemory(state->device, staging_buffer_memory, NULL); 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)); } 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 *pointer_to_mapped; vkMapMemory(state->device, kitty->attatchments.items[index].ubo.memory[i], 0, kitty->attatchments.items[index].ubo.size, 0, &pointer_to_mapped); kitty->attatchments.items[index].ubo.mapped[i] = pointer_to_mapped; } } 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; meow("allocing %d desc sets", 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_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; } } } VkDeviceSize size = kitty->vertex_buffer.count * kitty->vertex_buffer.vertex_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->vertex_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->vertex_buffer.buffer, &kitty->vertex_buffer.memory); copy_buffer(state, staging_buffer, kitty->vertex_buffer.buffer, size); vkDestroyBuffer(state->device, staging_buffer, NULL); vkFreeMemory(state->device, staging_buffer_memory, NULL); vkDestroyShaderModule(state->device, vert_module, NULL); vkDestroyShaderModule(state->device, frag_module, NULL); free(vert_shader); free(frag_shader); dyn_array_append(&state->kitties, kitty); meow("appended a kitty, len is now %d", state->kitties.count); } 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); 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); vkFreeMemory(state->device, kitty->attatchments.items[i].ubo.memory[j], NULL); } break; case CAT_ATTATCH_IMAGE: vkDestroyImage(state->device, kitty->attatchments.items[i].image.image, NULL); vkFreeMemory(state->device, kitty->attatchments.items[i].image.memory, NULL); vkDestroyImageView(state->device, kitty->attatchments.items[i].image.view, NULL); vkDestroySampler(state->device, kitty->attatchments.items[i].image.sampler, NULL); break; } } dyn_array_destroy(&kitty->vertex_buffer.format); dyn_array_destroy(&kitty->attatchments); memset(kitty, 0, sizeof(struct Kitty)); free(kitty); } void kitty_set_next_push_constant(struct Kitty *thingy, void *data) { thingy->next_push_constant = data; } void kitty_set_next_ubo(struct Vk *state, struct Kitty *thingy, int index, void *data) { void *dst = thingy->attatchments.items[index].ubo.mapped[state->current_frame]; void *src = data; int size = thingy->attatchments.items[index].ubo.size; /* meow("index %d, number %f", index, *(float *)data); */ memcpy(dst, src, size); } void kitty_draw(struct Vk *state, uint32_t image_index, struct Kitty *thingy) { struct InFlightObjects flight = state->flights[state->current_frame]; vkCmdBindPipeline(flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, thingy->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); VkBuffer vertex_buffer[] = {thingy->vertex_buffer.buffer}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(flight.command_buffer, 0, 1, vertex_buffer, offsets); vkCmdBindDescriptorSets( flight.command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, thingy->pipeline_layout, 0, 1, &thingy->descriptor_sets[state->current_frame], 0, NULL); vkCmdDraw(flight.command_buffer, thingy->vertex_buffer.count, 1, 0, 0); }