diff --git a/src/l2/margaret/margaret.h b/src/l2/margaret/margaret.h index 2069a1c..d8305cb 100644 --- a/src/l2/margaret/margaret.h +++ b/src/l2/margaret/margaret.h @@ -994,8 +994,24 @@ typedef struct { VkBuffer buffer; } MargaretBufferInMemoryInfo; -SpanT_struct_Definition(MargaretBufferInMemoryInfo) -SpanT_method_Definition(MargaretBufferInMemoryInfo) +#define MargaretBufferInMemoryInfo_drop(self) {} +#define MargaretBufferInMemoryInfo_clone(self) (*(self)) + +VecT_trivmove_struct_Definition(MargaretBufferInMemoryInfo); +VecT_trivmove_method_Definition(MargaretBufferInMemoryInfo); +VecT_primitive_zeroinit_method_Definition(MargaretBufferInMemoryInfo); + +typedef MargaretBufferInMemoryInfo* MargaretBufferInMemoryInfo_Ptr; + +#define MargaretBufferInMemoryInfo_Ptr_drop(self) {} +#define MargaretBufferInMemoryInfo_Ptr_clone(self) (*(self)) + +VecT_trivmove_struct_Definition(MargaretBufferInMemoryInfo_Ptr); +VecT_trivmove_method_Definition(MargaretBufferInMemoryInfo_Ptr); +VecT_primitive_zeroinit_method_Definition(MargaretBufferInMemoryInfo_Ptr); +SpanT_struct_Definition(MargaretBufferInMemoryInfo_Ptr) +SpanT_method_Definition(MargaretBufferInMemoryInfo_Ptr) +SpanT_VecT_method_Definition(MargaretBufferInMemoryInfo_Ptr) // Used in autogenerated code typedef struct { @@ -1009,19 +1025,35 @@ typedef struct { VkImage image; } MargaretImageInMemoryInfo; -SpanT_struct_Definition(MargaretImageInMemoryInfo) -SpanT_method_Definition(MargaretImageInMemoryInfo) +#define MargaretImageInMemoryInfo_drop(self) {} +#define MargaretImageInMemoryInfo_clone(self) (*(self)) + +VecT_trivmove_struct_Definition(MargaretImageInMemoryInfo); +VecT_trivmove_method_Definition(MargaretImageInMemoryInfo); +VecT_primitive_zeroinit_method_Definition(MargaretImageInMemoryInfo); + +typedef MargaretImageInMemoryInfo* MargaretImageInMemoryInfo_Ptr; + +#define MargaretImageInMemoryInfo_Ptr_drop(self) {} +#define MargaretImageInMemoryInfo_Ptr_clone(self) (*(self)) + +VecT_trivmove_struct_Definition(MargaretImageInMemoryInfo_Ptr); +VecT_trivmove_method_Definition(MargaretImageInMemoryInfo_Ptr); +VecT_primitive_zeroinit_method_Definition(MargaretImageInMemoryInfo_Ptr); +SpanT_struct_Definition(MargaretImageInMemoryInfo_Ptr) +SpanT_method_Definition(MargaretImageInMemoryInfo_Ptr) +SpanT_VecT_method_Definition(MargaretImageInMemoryInfo_Ptr) // A handy function to initialize buffers and images (attaching them to allocated memory) VkDeviceMemory margaret_initialize_buffers_and_images( VkPhysicalDevice physical_device, VkDevice device, - SpanMargaretBufferInMemoryInfo buffer_hands, SpanMargaretImageInMemoryInfo image_hands, + SpanMargaretBufferInMemoryInfo_Ptr buffer_hands, SpanMargaretImageInMemoryInfo_Ptr image_hands, VkMemoryPropertyFlags properties ) { uint32_t memory_types_allowed = -1; VkDeviceSize offset = 0; for (size_t i = 0; i < buffer_hands.len; i++) { - MargaretBufferInMemoryInfo* buf_hand = SpanMargaretBufferInMemoryInfo_at(buffer_hands, i); + MargaretBufferInMemoryInfo* buf_hand = *SpanMargaretBufferInMemoryInfo_Ptr_at(buffer_hands, i); VkBufferCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .size = buf_hand->sz, @@ -1041,7 +1073,7 @@ VkDeviceMemory margaret_initialize_buffers_and_images( } for (size_t i = 0; i < image_hands.len; i++) { - MargaretImageInMemoryInfo* img_hand = SpanMargaretImageInMemoryInfo_at(image_hands, i); + MargaretImageInMemoryInfo* img_hand = *SpanMargaretImageInMemoryInfo_Ptr_at(image_hands, i); VkImageCreateInfo crinfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .imageType = VK_IMAGE_TYPE_2D, @@ -1082,13 +1114,13 @@ VkDeviceMemory margaret_initialize_buffers_and_images( } for (size_t i = 0; i < buffer_hands.len; i++) { - MargaretBufferInMemoryInfo* buf_hand = SpanMargaretBufferInMemoryInfo_at(buffer_hands, i); + MargaretBufferInMemoryInfo* buf_hand = *SpanMargaretBufferInMemoryInfo_Ptr_at(buffer_hands, i); if (vkBindBufferMemory(device, buf_hand->buffer, memory, buf_hand->offset) != VK_SUCCESS) abortf("vkBindBufferMemory"); } for (size_t i = 0; i < image_hands.len; i++) { - MargaretImageInMemoryInfo* img_hand = SpanMargaretImageInMemoryInfo_at(image_hands, i); + MargaretImageInMemoryInfo* img_hand = *SpanMargaretImageInMemoryInfo_Ptr_at(image_hands, i); if (vkBindImageMemory(device, img_hand->image, memory, img_hand->offset) != VK_SUCCESS) abortf("vkBindImageMemory"); } @@ -1371,18 +1403,18 @@ VkDescriptorPool margaret_create_descriptor_set_pool(VkDevice device, return descriptor_pool; } -void margaret_record_buf_copying_command_buf( - VkDevice device, VkCommandBuffer command_buffer, - VkBuffer dest_buffer, VkBuffer src_buffer, VkDeviceSize buffer_size - ) { - VkCommandBufferBeginInfo beginfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; - if (vkBeginCommandBuffer(command_buffer, &beginfo) != VK_SUCCESS) - abortf("vkBeginCommandBuffer"); - VkBufferCopy regions_to_copy[1] = {(VkBufferCopy){.srcOffset = 0, .dstOffset = 0, .size = buffer_size}}; - vkCmdCopyBuffer(command_buffer, src_buffer, dest_buffer, ARRAY_SIZE(regions_to_copy), regions_to_copy); - if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) - abortf("vkEndCommandBuffer"); -} +/* Won't actually use this function, it's too underpowered */ +// void margaret_record_buf_copying_command_buf(VkCommandBuffer command_buffer, +// VkBuffer dest_buffer, VkBuffer src_buffer, VkDeviceSize buffer_size +// ) { +// VkCommandBufferBeginInfo beginfo = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, }; +// if (vkBeginCommandBuffer(command_buffer, &beginfo) != VK_SUCCESS) +// abortf("vkBeginCommandBuffer"); +// VkBufferCopy regions_to_copy[1] = {(VkBufferCopy){.srcOffset = 0, .dstOffset = 0, .size = buffer_size}}; +// vkCmdCopyBuffer(command_buffer, src_buffer, dest_buffer, ARRAY_SIZE(regions_to_copy), regions_to_copy); +// if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) +// abortf("vkEndCommandBuffer"); +// } VkDescriptorSet margaret_allocate_descriptor_set(VkDevice device, VkDescriptorPool descriptor_pool, VkDescriptorSetLayout layout) { VkDescriptorSetAllocateInfo alloc_info = { @@ -1397,4 +1429,11 @@ VkDescriptorSet margaret_allocate_descriptor_set(VkDevice device, VkDescriptorPo return descriptor_set; } +#define VkBufferCopy_drop(x) {} +#define VkBufferCopy_clone(xp) (*(xp)) + +VecT_trivmove_struct_Definition(VkBufferCopy) +VecT_trivmove_method_Definition(VkBufferCopy) +VecT_primitive_zeroinit_method_Definition(VkBufferCopy) + #endif diff --git a/src/l2/tests/r0.c b/src/l2/tests/r0.c index 4c867bb..b9fb937 100644 --- a/src/l2/tests/r0.c +++ b/src/l2/tests/r0.c @@ -90,7 +90,7 @@ VkRenderPass create_render_pass_0(VkDevice logical_device, VkFormat colorbuffer_ return render_pass; } -margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(Vertex) +margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(GenericMeshVertex) PipelineHands create_graphics_pipeline_0( VkDevice device, VkRenderPass render_pass, uint32_t subpass @@ -107,23 +107,56 @@ PipelineHands create_graphics_pipeline_0( margaret_shader_stage_fragment_crinfo(frag_module) }; - VkVertexInputBindingDescription vertex_bindings[1] = { { - .binding = 0, - .stride = sizeof(Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, - } }; - VkVertexInputAttributeDescription vertex_attributes[2] = { + VkVertexInputBindingDescription vertex_bindings[2] = { + { + .binding = 0, + .stride = sizeof(GenericMeshVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }, + { + .binding = 1, + .stride = sizeof(GenericMeshInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE, + } + }; + VkVertexInputAttributeDescription vertex_attributes[2 + 4] = { { .location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, - .offset = offsetof(Vertex, pos), + .offset = offsetof(GenericMeshVertex, pos), }, { .location = 1, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, - .offset = offsetof(Vertex, tex), + .offset = offsetof(GenericMeshVertex, tex), + }, + + /* This is a mat4 datatype, so it will take 4 entire 'locations' */ + { + .location = 2, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = offsetof(GenericMeshInstance, model_trans) + offsetof(mat4, x) + }, + { + .location = 3, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = offsetof(GenericMeshInstance, model_trans) + offsetof(mat4, y) + }, + { + .location = 4, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = offsetof(GenericMeshInstance, model_trans) + offsetof(mat4, z) + }, + { + .location = 5, + .binding = 1, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = offsetof(GenericMeshInstance, model_trans) + offsetof(mat4, w) }, }; @@ -153,8 +186,8 @@ PipelineHands create_graphics_pipeline_0( .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, .depthClampEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_BACK_BIT, - // .cullMode = VK_CULL_MODE_NONE, + // .cullMode = VK_CULL_MODE_BACK_BIT, + .cullMode = VK_CULL_MODE_NONE, .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .depthBiasConstantFactor = 0.0f, @@ -237,7 +270,13 @@ PipelineHands create_graphics_pipeline_0( { .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = sizeof(mat4) - }}; + }, + { + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = sizeof(mat4), .size = sizeof(vec3) + }, + + }; VkPipelineLayoutCreateInfo layout_crinfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, @@ -498,8 +537,8 @@ VkFramebuffer create_IT1_framebuffer(VkDevice device, VkImageView IT1_view, VkIm void reset_and_record_command_buffer_0( VkCommandBuffer command_buffer, VkRenderPass render_pass_0, const PipelineHands* pipeline_and_layout, - VkFramebuffer swapchain_image_framebuffer, VkExtent2D image_extent, - const Scene* scene, VkDescriptorSet my_descriptor_set, mat4 t_mat + VkFramebuffer swapchain_image_framebuffer, VkImage IT1_image, VkExtent2D image_extent, + const Scene* scene, VkDescriptorSet my_descriptor_set, mat4 proj_cam_t, vec3 camera_pos ) { if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) abortf("vkResetCommandBuffer"); @@ -537,23 +576,50 @@ void reset_and_record_command_buffer_0( .extent = image_extent, }; vkCmdSetScissor(command_buffer, 0, 1, &scissor); + vkCmdPushConstants(command_buffer, pipeline_and_layout->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, + 0, sizeof(mat4), &proj_cam_t); + vkCmdPushConstants(command_buffer, pipeline_and_layout->pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, + sizeof(mat4), sizeof(vec3), &camera_pos); for (size_t i = 0; i < scene->models.len; i++) { const UsedModelOnScene* model = VecUsedModelOnScene_cat(&scene->models, i); - VkBuffer attached_buffers[1] = { model->model.vbo }; + VkBuffer attached_buffers[2] = { model->model.vbo, model->instance_attr_buf }; // We use our whole buffer, no need for offset - VkDeviceSize offsets_in_buffers[1] = {0}; - vkCmdBindVertexBuffers(command_buffer, 0, 1, attached_buffers, offsets_in_buffers); + VkDeviceSize offsets_in_buffers[2] = {0, model->instance_attr_buf_offset}; + assert(ARRAY_SIZE(attached_buffers) == 2 && ARRAY_SIZE(offsets_in_buffers) == 2); + vkCmdBindVertexBuffers(command_buffer, 0, 2, attached_buffers, offsets_in_buffers); vkCmdBindIndexBuffer(command_buffer, model->model.ebo, 0, VK_INDEX_TYPE_UINT32); - mat4 tt = mat4_mul_mat4(t_mat, model->model_t); - vkCmdPushConstants(command_buffer, pipeline_and_layout->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, - 0, sizeof(mat4), &tt); vkCmdBindDescriptorSets( command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout->pipeline_layout, 0, 1, &my_descriptor_set, 0, NULL); - vkCmdDrawIndexed(command_buffer, model->model.indexes, 1, 0, 0, 0); + vkCmdDrawIndexed(command_buffer, model->model.indexes, model->instances.len, 0, 0, 0); } vkCmdEndRenderPass(command_buffer); + + // VkImageMemoryBarrier barrier = { + // .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + // .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + // .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, + // .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + // .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + // .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + // .image = IT1_image, + // .subresourceRange = (VkImageSubresourceRange){ + // .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + // .baseMipLevel = 0, + // .levelCount = 1, + // .baseArrayLayer = 0, + // .layerCount = 1, + // }, + // }; + // vkCmdPipelineBarrier(command_buffer, + // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + // VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + // 0, + // 0, NULL, + // 0, NULL, + // 1, &barrier); if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) abortf("vkEndCommandBuffer"); } @@ -621,6 +687,74 @@ void reset_and_record_command_buffer_1( abortf("vkEndCommandBuffer"); } +/* First, we copy our scene information to void* host_mem_buffer_mem. + * Then, we record a command buffer that would copy these specific regions to corresponding device buffers + * It's up to you to submit command_buffer + * */ +void copy_scene_info_to_buffer_and_rerecord_full_copy_command_buffer( + VkCommandBuffer command_buffer, VkBuffer host_memory_buffer, char* host_mem_buffer_mem, const Scene* scene, + VkBuffer device_lighting_ubo, VkBuffer device_instance_attrs_for_all_generic_meshes + ) { + + if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) + abortf("vkResetCommandBuffer"); + VkCommandBufferBeginInfo info_begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS) + abortf("vkBeginCommandBuffer"); + + size_t offset_here = 0; + { + size_t offset_in_mesh_instance_buf = 0; + VecVkBufferCopy regions_to_copy_A = VecVkBufferCopy_new(); + for (size_t mi = 0; mi < scene->models.len; mi++) { + const UsedModelOnScene* model = VecUsedModelOnScene_cat(&scene->models, mi); + assert(model->instances.len <= model->limit_max_instance_count); + size_t all = model->instances.len * sizeof(GenericMeshInstance); + memcpy(host_mem_buffer_mem + offset_here, model->instances.buf, all); + /* Right now we don't combine multiple vkCmdCopyBuffer commands with same src and dst buffers into one, but later we should do it */ + VecVkBufferCopy_append(®ions_to_copy_A, (VkBufferCopy){.srcOffset = offset_here, .dstOffset = offset_in_mesh_instance_buf, .size = all}); + offset_here += all; + offset_in_mesh_instance_buf += model->limit_max_instance_count * sizeof(GenericMeshInstance); + } + vkCmdCopyBuffer(command_buffer, host_memory_buffer, device_instance_attrs_for_all_generic_meshes, regions_to_copy_A.len, regions_to_copy_A.buf); + VecVkBufferCopy_drop(regions_to_copy_A); + } + { + assert(scene->point_lights.len <= pipeline_0_ubo_point_light_max_count); + assert(scene->spotlights.len <= pipeline_0_ubo_spotlight_max_count); + int point_lights = (int)scene->point_lights.len; + int spotlights = (int)scene->spotlights.len; + memcpy(host_mem_buffer_mem + offset_here, &point_lights, sizeof(int)); + memcpy(host_mem_buffer_mem + offset_here + sizeof(int), &spotlights, sizeof(int)); + memcpy(host_mem_buffer_mem + offset_here + sizeof(int) * 2, scene->point_lights.buf, sizeof(Pipeline0PointLight) * point_lights); + memcpy(host_mem_buffer_mem + offset_here + sizeof(int) * 2 + sizeof(Pipeline0PointLight) * point_lights, + scene->spotlights.buf, sizeof(Pipeline0Spotlight) * spotlights); + VkBufferCopy regions_to_copy_B[] = { + { + .srcOffset = offset_here, .dstOffset = offsetof(Pipeline0UBO, point_light_count), + .size = sizeof(int), + }, + { + .srcOffset = offset_here + sizeof(int), .dstOffset = offsetof(Pipeline0UBO, spotlight_count), + .size = sizeof(int), + }, + { + .srcOffset = offset_here + 2 * sizeof(int), .dstOffset = offsetof(Pipeline0UBO, point_light_arr), + .size = sizeof(Pipeline0PointLight) * point_lights, + }, + { + .srcOffset = offset_here + 2 * sizeof(int) + sizeof(Pipeline0PointLight) * point_lights, + .dstOffset = offsetof(Pipeline0UBO, spotlight_arr), + .size = sizeof(Pipeline0Spotlight) * spotlights, + }, + }; + vkCmdCopyBuffer(command_buffer, host_memory_buffer, device_lighting_ubo, ARRAY_SIZE(regions_to_copy_B), regions_to_copy_B); + } + + if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) + abortf("vkEndCommandBuffer"); +} + // todo: add here deletion and recreation of several synchronization primitives void recreate_swapchain( @@ -660,11 +794,11 @@ typedef struct { int main() { prepare_shaders(); - ConstSpanU8 GPU = cstr("amd"); - ConstSpanU8 bugged_GPU = cstr("nvidia"); + ConstSpanU8 GPU = cstr("nvidia"); + ConstSpanU8 bugged_GPU = cstr("nothere"); bool ENABLE_VALIDATION_LAYERS = true; - U32 MAX_WIN_WIDTH = 1920; - U32 MAX_WIN_HEIGHT = 1080; + const U32 MAX_WIN_WIDTH = 1920; + const U32 MAX_WIN_HEIGHT = 1080; MargaretSingleWindowSetup x = MargaretSingleWindowSetup_new(); Margaret_WEP wep = Margaret_WEP_new(x.dpy, x.win); @@ -716,9 +850,14 @@ int main() { MargaretSwapchainBundle swfb = MargaretSwapchainBundle_new(device, queue_fam, swapchain_details, surface, render_pass_1, NULL); - // Filling scene info - ModelTopology cylinder_1 = generate_one_fourth_of_a_cylinder(10, 2, 6); - ModelTopology cylinder_2 = generate_one_fourth_of_a_cylinder(5, 5, 10); + SceneTemplate scene_template = {.models = VecModelInSceneTemplate_new(), + .point_lights_max_count = pipeline_0_ubo_point_light_max_count, + .spotlights_max_count = pipeline_0_ubo_spotlight_max_count}; + VecModelInSceneTemplate_append(&scene_template.models, + (ModelInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder(10, 2, 6), .max_instance_count = 100}); + VecModelInSceneTemplate_append(&scene_template.models, + (ModelInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder(5, 5, 10), .max_instance_count = 1}); + // TextureDataR8G8B8A8 wood_texture_data = generate_texture_for_one_fourth_of_a_cylinder(20, 10, 2, 6); // todo: learn how to use libpng TextureDataR8G8B8A8 cyl_1_diffuse_tex = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6.r8g8b8a8"); @@ -726,95 +865,130 @@ int main() { // todo: and at the same time I need to add methods to convert between these formats TextureDataR8G8B8A8 cyl_1_normal_tex = TextureDataR8G8B8A8_read_from_file("test_textures/log_10_2_6_NORMAL.r8g8b8a8"); + + // todo: kill myself // We have only one staging buffer in host memory (because we don't really need more) MargaretBufferInMemoryInfo host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz = - MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_1), - MAX_U64(ModelTopology_get_space_needed_for_staging_buffer(&cylinder_2), - MAX_U64(sizeof(Pipeline0UBO), + MAX_U64(SceneTemplate_get_space_for_initial_model_topology_transfer(&scene_template), + MAX_U64(SceneTemplate_get_space_needed_for_widest_state_transfer(&scene_template), MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_diffuse_tex), - MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_normal_tex), 0))))) + MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_normal_tex), 0)))) , .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT }; + MargaretBufferInMemoryInfo_Ptr host_mem_buffer_SPAN[1] = {&host_mem_buffer}; VkDeviceMemory host_mem = margaret_initialize_buffers_and_images(physical_device, device, - (SpanMargaretBufferInMemoryInfo){.data = &host_mem_buffer, .len = 1}, (SpanMargaretImageInMemoryInfo){ 0 }, + (SpanMargaretBufferInMemoryInfo_Ptr){.data = host_mem_buffer_SPAN, .len = 1}, + (SpanMargaretImageInMemoryInfo_Ptr){ 0 }, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - MargaretBufferInMemoryInfo device_mem_buffers[] = { - Vertex_buffer_crinfo_of_gpu_vbo(cylinder_1.vertices.len), - margaret_prep_buffer_mem_info_of_gpu_ebo(cylinder_1.indexes.len), - Vertex_buffer_crinfo_of_gpu_vbo(cylinder_2.vertices.len), - margaret_prep_buffer_mem_info_of_gpu_ebo(cylinder_2.indexes.len), - margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)), + // todo: split this in two (or maybe even better: merge it all into one/two buffer and use offsets + VecMargaretBufferInMemoryInfo device_ebo_and_vbo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); + for (size_t mi = 0; mi < scene_template.models.len; mi++) { + const ModelInSceneTemplate* M = VecModelInSceneTemplate_cat(&scene_template.models, mi); + VecMargaretBufferInMemoryInfo_append(&device_ebo_and_vbo_buffers_for_generic_meshes, + GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len)); + VecMargaretBufferInMemoryInfo_append(&device_ebo_and_vbo_buffers_for_generic_meshes, + margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len)); + } + MargaretBufferInMemoryInfo device_lighting_ubo = margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)); + MargaretBufferInMemoryInfo device_instance_attrs_for_all_generic_meshes = (MargaretBufferInMemoryInfo){ + .sz = SceneTemplate_get_space_needed_for_all_instance_attributes(&scene_template), + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT }; - MargaretImageInMemoryInfo device_mem_images[] = { - margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some), - margaret_prep_image_mem_info_of_zbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some), - margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_diffuse_tex.width, - TextureDataR8G8B8A8_get_height(&cyl_1_diffuse_tex)), - margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_normal_tex.width, - TextureDataR8G8B8A8_get_height(&cyl_1_normal_tex)), + + VecMargaretBufferInMemoryInfo_Ptr device_mem_buffers_SPAN = VecMargaretBufferInMemoryInfo_Ptr_new(); + for (size_t i = 0; i < device_ebo_and_vbo_buffers_for_generic_meshes.len; i++) { + VecMargaretBufferInMemoryInfo_Ptr_append(&device_mem_buffers_SPAN, + VecMargaretBufferInMemoryInfo_at(&device_ebo_and_vbo_buffers_for_generic_meshes, i)); + } + VecMargaretBufferInMemoryInfo_Ptr_append(&device_mem_buffers_SPAN, &device_lighting_ubo); + VecMargaretBufferInMemoryInfo_Ptr_append(&device_mem_buffers_SPAN, &device_instance_attrs_for_all_generic_meshes); + printf("Buffers: %lu\n", device_mem_buffers_SPAN.len); + + MargaretImageInMemoryInfo device_IT1_image = margaret_prep_image_mem_info_of_colorbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some); + MargaretImageInMemoryInfo device_zbuffer_image = margaret_prep_image_mem_info_of_zbuffer(MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some); + MargaretImageInMemoryInfo device_cyl_1_diffuse_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_diffuse_tex.width, + TextureDataR8G8B8A8_get_height(&cyl_1_diffuse_tex)); + MargaretImageInMemoryInfo device_cyl_1_normal_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba(cyl_1_normal_tex.width, + TextureDataR8G8B8A8_get_height(&cyl_1_normal_tex)); + + MargaretImageInMemoryInfo_Ptr device_mem_images_SPAN[] = { + &device_IT1_image, &device_zbuffer_image, &device_cyl_1_diffuse_texture, &device_cyl_1_normal_texture }; - // todo: replace this ugly garbage with pointer spans. Seriously, this is fucking digusting VkDeviceMemory device_mem = margaret_initialize_buffers_and_images(physical_device, device, - (SpanMargaretBufferInMemoryInfo){ .data = device_mem_buffers, .len = ARRAY_SIZE(device_mem_buffers)}, - (SpanMargaretImageInMemoryInfo){ .data = device_mem_images, .len = ARRAY_SIZE(device_mem_images) }, + VecMargaretBufferInMemoryInfo_Ptr_to_SpanMargaretBufferInMemoryInfo_Ptr(&device_mem_buffers_SPAN), + (SpanMargaretImageInMemoryInfo_Ptr){ .data = device_mem_images_SPAN, .len = ARRAY_SIZE(device_mem_images_SPAN) }, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - MargaretBufferInMemoryInfo device_vbo_1_buffer = device_mem_buffers[0]; - MargaretBufferInMemoryInfo device_ebo_1_buffer = device_mem_buffers[1]; - MargaretBufferInMemoryInfo device_vbo_2_buffer = device_mem_buffers[2]; - MargaretBufferInMemoryInfo device_ebo_2_buffer = device_mem_buffers[3]; - MargaretBufferInMemoryInfo device_ubo_my_buffer = device_mem_buffers[4]; - MargaretImageInMemoryInfo device_IT1_image = device_mem_images[0]; - MargaretImageInMemoryInfo device_zbuffer_image = device_mem_images[1]; - MargaretImageInMemoryInfo device_cyl_1_diffuse_texture = device_mem_images[2]; - MargaretImageInMemoryInfo device_cyl_1_normal_texture = device_mem_images[3]; VkCommandPool command_pool = margaret_create_resettable_command_pool(device, queue_fam.for_graphics); VkCommandBuffer rendering_command_buffer_0 = margaret_allocate_command_buffer(device, command_pool); VkCommandBuffer rendering_command_buffer_1 = margaret_allocate_command_buffer(device, command_pool); + VkCommandBuffer transfer_command_buffer = margaret_allocate_command_buffer(device, command_pool); - VkCommandBuffer uniform_transfer_command_buffer = margaret_allocate_command_buffer(device, command_pool); - margaret_record_buf_copying_command_buf(device, uniform_transfer_command_buffer, - device_ubo_my_buffer.buffer, host_mem_buffer.buffer, sizeof(Pipeline0UBO)); + Scene scene = Scene_new(); + { + size_t offset_in_attr_buffer = 0; + for (size_t mi = 0; mi < scene_template.models.len; mi++) { + // UsedModelOnScene* ptb = VecUsedModelOnScene_cat() + const ModelInSceneTemplate* M = VecModelInSceneTemplate_cat(&scene_template.models, mi); + VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){ + .model = (ModelOnScene){ + .vbo = VecMargaretBufferInMemoryInfo_cat(&device_ebo_and_vbo_buffers_for_generic_meshes, + 2 * mi + 0)->buffer, + .ebo = VecMargaretBufferInMemoryInfo_cat(&device_ebo_and_vbo_buffers_for_generic_meshes, + 2 * mi + 1)->buffer, + .indexes = M->topology.indexes.len, + }, + .instances = VecGenericMeshInstance_new(), + .instance_attr_buf = device_instance_attrs_for_all_generic_meshes.buffer, + .instance_attr_buf_offset = offset_in_attr_buffer, + .limit_max_instance_count = M->max_instance_count + }); + offset_in_attr_buffer += M->max_instance_count * sizeof(GenericMeshInstance); + } + } + + for (int X = 0; X < 10; X++) { + for (int Z = 0; Z < 10; Z++) { + VecGenericMeshInstance_append(&VecUsedModelOnScene_at(&scene.models, 0)->instances, + (GenericMeshInstance){ .model_trans = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}) }); + } + } + VecGenericMeshInstance_append(&VecUsedModelOnScene_at(&scene.models, 1)->instances, (GenericMeshInstance){ + .model_trans = mat4_E + }); void* host_mem_buffer_mem; if (vkMapMemory(device, host_mem, 0, VK_WHOLE_SIZE, 0, &host_mem_buffer_mem) != VK_SUCCESS) abortf("vkMapMemory"); - // Now this is what we will do for each buffer: we first memcpy it into mapped region, then we submit a copying command + + SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd(&scene_template, &scene, host_mem_buffer_mem, transfer_command_buffer, host_mem_buffer.buffer); { - size_t size = cylinder_1.vertices.len * sizeof(Vertex); - memcpy(host_mem_buffer_mem, cylinder_1.vertices.buf, size); - margaret_copy_buffer_imm(device, command_pool, graphics_queue, - device_vbo_1_buffer.buffer, host_mem_buffer.buffer, size); - } - { - size_t size = cylinder_1.indexes.len * sizeof(U32); - memcpy(host_mem_buffer_mem, cylinder_1.indexes.buf, size); - margaret_copy_buffer_imm(device, command_pool, graphics_queue, - device_ebo_1_buffer.buffer, host_mem_buffer.buffer, size); - } - { - size_t size = cylinder_2.vertices.len * sizeof(Vertex); - memcpy(host_mem_buffer_mem, cylinder_2.vertices.buf, size); - margaret_copy_buffer_imm(device, command_pool, graphics_queue, - device_vbo_2_buffer.buffer, host_mem_buffer.buffer, size); - } - { - size_t size = cylinder_2.indexes.len * sizeof(U32); - memcpy(host_mem_buffer_mem, cylinder_2.indexes.buf, size); - margaret_copy_buffer_imm(device, command_pool, graphics_queue, - device_ebo_2_buffer.buffer, host_mem_buffer.buffer, size); + VkCommandBuffer command_buffers[1] = { transfer_command_buffer }; + // VkSemaphore signaling_semaphores[1] = { swfb.in_frame_transfer_complete }; + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = ARRAY_SIZE(command_buffers), + .pCommandBuffers = command_buffers, + // .signalSemaphoreCount = ARRAY_SIZE(signaling_semaphores), + // .pSignalSemaphores = signaling_semaphores, + }; + if (vkQueueSubmit(graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) + abortf("vkQueueSubmit\n"); } + vkDeviceWaitIdle(device); { memcpy(host_mem_buffer_mem, cyl_1_diffuse_tex.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_diffuse_tex)); margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue, &device_cyl_1_diffuse_texture, host_mem_buffer.buffer); } + vkDeviceWaitIdle(device); { memcpy(host_mem_buffer_mem, cyl_1_normal_tex.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&cyl_1_normal_tex)); margaret_copy_buffer_to_texture_for_frag_shader_imm(device, command_pool, graphics_queue, &device_cyl_1_normal_texture, host_mem_buffer.buffer); } + vkDeviceWaitIdle(device); // We sent everything we needed. but host_mem_buffer_mem may be used later @@ -830,25 +1004,21 @@ int main() { // My cylinder 1 normal texture also needs NkImageView VkImageView cyl_1_normal_texture_view = margaret_create_view_for_image(device, &device_cyl_1_normal_texture, VK_IMAGE_ASPECT_COLOR_BIT); - Scene scene = Scene_new(); - VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = { - .vbo = device_vbo_1_buffer.buffer, .ebo = device_ebo_1_buffer.buffer, .indexes = cylinder_1.indexes.len - }, .model_t = marie_translation_mat4((vec3){1, -1, 5}) }); - VecUsedModelOnScene_append(&scene.models, (UsedModelOnScene){.model = { - .vbo = device_vbo_2_buffer.buffer, .ebo = device_ebo_2_buffer.buffer, .indexes = cylinder_2.indexes.len - }, .model_t = marie_translation_mat4((vec3){6, -3, 16}) }); + // Right now I only have one light source + VecPipeline0PointLight_append(&scene.point_lights, (Pipeline0PointLight){.pos = {0}, .color = {100, 100, 100}}); + // These samplers are global for a lot of my future textures VkSampler linear_sampler = margaret_create_sampler(physical_device, device, true); VkSampler nearest_sampler = margaret_create_sampler(physical_device, device, false); - VkDescriptorPool descriptor_pool = margaret_create_descriptor_set_pool(device, 1, 3, 2); + VkDescriptorPool descriptor_pool = margaret_create_descriptor_set_pool(device, 1, 3, 2); VkDescriptorSet descriptor_set_for_pipeline_0 = margaret_allocate_descriptor_set(device, descriptor_pool, pipeline_hands_0.descriptor_set_layout); VkDescriptorSet descriptor_set_for_pipeline_1 = margaret_allocate_descriptor_set(device, descriptor_pool, pipeline_hands_1.descriptor_set_layout); // Configuring my descriptor sets, that I just allocated VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0 = { - .buffer = device_ubo_my_buffer.buffer, + .buffer = device_lighting_ubo.buffer, .offset = 0, .range = sizeof(Pipeline0UBO), }; @@ -909,6 +1079,7 @@ int main() { vkUpdateDescriptorSets(device, ARRAY_SIZE(writes_in_descriptor_sets), writes_in_descriptor_sets, 0, NULL); CamControlInfo my_cam_control_info = CamControlInfo_new(); + vec3 Buba_control_info = {0}; // Mainloop margaret_ns_time start = margaret_clock_gettime_monotonic_raw(); @@ -916,6 +1087,9 @@ int main() { int frame_count_since_key = 0; margaret_ns_time prev_frame_timestamp = start; + /* Will happen mid-frame */ + bool dt_transfer_required = true; + bool pressed_first_0x80[0x80] = {0}; while (true) { margaret_ns_time frame_A0 = margaret_clock_gettime_monotonic_raw(); @@ -942,6 +1116,18 @@ int main() { KeySym keysym = XLookupKeysym(&ev->xkey, 0); if (keysym < 0x80) pressed_first_0x80[keysym] = false; + if (keysym == XK_1) { + vec3 p = my_cam_control_info.pos; + VecPipeline0PointLight_at(&scene.point_lights, 0)->pos = p; + printf("Point light source pos set to %f %f %f\n", p.x, p.y, p.z); + dt_transfer_required = true; + } else if (keysym == XK_2) { + scene.hdr_factor /= 1.05f; + printf("hdr factor decreased to %f\n", scene.hdr_factor); + } else if (keysym == XK_3) { + scene.hdr_factor *= 1.05f; + printf("hdr factor increased to %f\n", scene.hdr_factor); + } } } if (pressed_first_0x80[XK_w]) @@ -957,6 +1143,33 @@ int main() { if (pressed_first_0x80[XK_e]) CamControlInfo_up(&my_cam_control_info, fl); + if (pressed_first_0x80[XK_j]) {\ + Buba_control_info.x -= fl; + VecGenericMeshInstance_at(&VecUsedModelOnScene_at(&scene.models, 1)->instances, 0)->model_trans = + marie_translation_mat4(Buba_control_info); + dt_transfer_required = true; + } + if (pressed_first_0x80[XK_k]) {\ + Buba_control_info.z -= fl; + VecGenericMeshInstance_at(&VecUsedModelOnScene_at(&scene.models, 1)->instances, 0)->model_trans = + marie_translation_mat4(Buba_control_info); + dt_transfer_required = true; + } + if (pressed_first_0x80[XK_l]) {\ + Buba_control_info.z += fl; + VecGenericMeshInstance_at(&VecUsedModelOnScene_at(&scene.models, 1)->instances, 0)->model_trans = + marie_translation_mat4(Buba_control_info); + dt_transfer_required = true; + } + if (pressed_first_0x80[XK_semicolon]) {\ + Buba_control_info.x += fl; + VecGenericMeshInstance_at(&VecUsedModelOnScene_at(&scene.models, 1)->instances, 0)->model_trans = + marie_translation_mat4(Buba_control_info); + dt_transfer_required = true; + } + + + // Rendering vkWaitForFences(device, 1, &swfb.in_flight_fence, VK_TRUE, UINT64_MAX); uint32_t ij; @@ -980,62 +1193,63 @@ int main() { float ae = margaret_ns_time_sec_diff(start, frame_A0); scene.anim_time = ae; - scene.color = (VkClearColorValue){{0.5f, fabsf(sinf(ae)), .3f, 1.0f}}; + scene.color = (VkClearColorValue){{0, 0, 0, 1}}; mat4 projection_matrix = marie_perspective_projection_fov_mat4((float)wep.width, (float)wep.height, my_cam_control_info.fov, 0.01f, 1000); mat4 camera_rotation_matrix = marie_mat3_to_mat4_transposed(my_cam_control_info.cam_basis); mat4 camera_translation_matrix = marie_translation_mat4(vec3_minus(my_cam_control_info.pos)); mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix)); - { + if (dt_transfer_required){ assert(scene.spotlights.len < pipeline_0_ubo_spotlight_max_count); assert(scene.point_lights.len < pipeline_0_ubo_point_light_max_count); - Pipeline0UBO* subo = (Pipeline0UBO*)host_mem_buffer_mem; - // todo: speed it up a little - subo->spotlight_count = (int)scene.spotlights.len; - memcpy(&subo->spotlight_arr, scene.spotlights.buf, scene.spotlights.len * sizeof(Pipeline0Spotlight)); - subo->point_light_count = (int)scene.point_lights.len; - memcpy(&subo->point_light_arr, scene.point_lights.buf, scene.point_lights.len * sizeof(Pipeline0PointLight)); - VkCommandBuffer command_buffers[1] = { uniform_transfer_command_buffer }; + copy_scene_info_to_buffer_and_rerecord_full_copy_command_buffer( + transfer_command_buffer, host_mem_buffer.buffer, host_mem_buffer_mem, &scene, device_lighting_ubo.buffer, + device_instance_attrs_for_all_generic_meshes.buffer); + VkCommandBuffer command_buffers[1] = { transfer_command_buffer }; VkSemaphore signaling_semaphores[1] = { swfb.in_frame_transfer_complete }; - VkSubmitInfo ubo_copying_cmd_buffer_submit = { + VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .commandBufferCount = ARRAY_SIZE(command_buffers), .pCommandBuffers = command_buffers, .signalSemaphoreCount = ARRAY_SIZE(signaling_semaphores), .pSignalSemaphores = signaling_semaphores, }; - vkQueueSubmit(graphics_queue, 1, &ubo_copying_cmd_buffer_submit, NULL); + if (vkQueueSubmit(graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) + abortf("vkQueueSubmit\n"); } - reset_and_record_command_buffer_0(rendering_command_buffer_0, render_pass_0, &pipeline_hands_0, - IT1_framebuffer, swfb.extent, &scene, descriptor_set_for_pipeline_0, t_mat); + reset_and_record_command_buffer_0( + rendering_command_buffer_0, render_pass_0, &pipeline_hands_0, + IT1_framebuffer, device_IT1_image.image, swfb.extent, &scene, + descriptor_set_for_pipeline_0, t_mat, my_cam_control_info.pos); reset_and_record_command_buffer_1(rendering_command_buffer_1, render_pass_1, &pipeline_hands_1, *VecVkFramebuffer_cat(&swfb.framebuffers, ij), swfb.extent, (VkExtent2D){.width = MAX_WIN_WIDTH, .height = MAX_WIN_HEIGHT}, &scene, descriptor_set_for_pipeline_1); { - VkSemaphore waiting_for_semaphores[2] = { - swfb.image_available_semaphore, swfb.in_frame_transfer_complete + VkSemaphore waiting_for_semaphores_if_dt_transfer_required[1] = { + swfb.in_frame_transfer_complete }; - VkPipelineStageFlags waiting_stages[2] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + VkPipelineStageFlags waiting_stages_if_dt_transfer_required[1] = { + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }; - assert(ARRAY_SIZE(waiting_for_semaphores) == ARRAY_SIZE(waiting_stages)); - // VkCommandBuffer command_buffers[1] = {*VecVkCommandBuffer_cat(&rendering_command_buffers, ij)}; + assert(ARRAY_SIZE(waiting_for_semaphores_if_dt_transfer_required) == + ARRAY_SIZE(waiting_stages_if_dt_transfer_required)); VkCommandBuffer command_buffers[1] = {rendering_command_buffer_0}; VkSemaphore signaling_semaphores[1] = { swfb.rendered_to_IT1_semaphore }; - - VkSubmitInfo cmd_submit_info = { + VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, // We wait for `waiting_for_semaphores` before THESE stages // waitSemaphoreCount specifies size for both pWaitSemaphores and pWaitDstStageMask - .waitSemaphoreCount = ARRAY_SIZE(waiting_for_semaphores), - .pWaitSemaphores = waiting_for_semaphores, - .pWaitDstStageMask = waiting_stages, + .waitSemaphoreCount = dt_transfer_required ? + ARRAY_SIZE(waiting_for_semaphores_if_dt_transfer_required) : 0, + .pWaitSemaphores = dt_transfer_required ? + waiting_for_semaphores_if_dt_transfer_required : NULL, + .pWaitDstStageMask = dt_transfer_required ? + waiting_stages_if_dt_transfer_required : NULL, .commandBufferCount = ARRAY_SIZE(command_buffers), .pCommandBuffers = command_buffers, @@ -1043,13 +1257,18 @@ int main() { .signalSemaphoreCount = ARRAY_SIZE(signaling_semaphores), .pSignalSemaphores = signaling_semaphores, }; - if (vkQueueSubmit(graphics_queue, 1, &cmd_submit_info, NULL) != VK_SUCCESS) + if (vkQueueSubmit(graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) abortf("vkQueueSubmit"); } - { - VkSemaphore waiting_for_semaphores[1] = { swfb.rendered_to_IT1_semaphore }; - VkPipelineStageFlags waiting_stages[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + VkSemaphore waiting_for_semaphores[2] = { + swfb.image_available_semaphore, + swfb.rendered_to_IT1_semaphore }; + VkPipelineStageFlags waiting_stages[2] = { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + // VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT + }; assert(ARRAY_SIZE(waiting_for_semaphores) == ARRAY_SIZE(waiting_stages)); VkCommandBuffer command_buffers[1] = { rendering_command_buffer_1 }; VkSemaphore signaling_semaphores[1] = { swfb.render_finished_semaphore }; @@ -1102,6 +1321,7 @@ int main() { abortf("vkQueuePresentKHR"); } } + dt_transfer_required = false; margaret_ns_time frame_B0 = margaret_clock_gettime_monotonic_raw(); if (margaret_ns_time_sec_diff(frame_A0, frame_B0) > 0.3) { fprintf(stderr, "]]] Profiling frame scheduling:\n" @@ -1118,11 +1338,11 @@ int main() { } } vkDeviceWaitIdle(device); + // The End // dropping scene Scene_drop(scene); - ModelTopology_drop(cylinder_1); - ModelTopology_drop(cylinder_2); + // todo: destroy objects that hold scene and model topology // destroying vulkan objects vkDestroyDescriptorPool(device, descriptor_pool, NULL); vkDestroySampler(device, linear_sampler, NULL); @@ -1130,11 +1350,8 @@ int main() { vkDestroyImageView(device, cyl_1_diffuse_texture_view, NULL); vkDestroyImageView(device, cyl_1_normal_texture_view, NULL); - vkDestroyBuffer(device, device_vbo_1_buffer.buffer, NULL); - vkDestroyBuffer(device, device_ebo_1_buffer.buffer, NULL); - vkDestroyBuffer(device, device_vbo_2_buffer.buffer, NULL); - vkDestroyBuffer(device, device_ebo_2_buffer.buffer, NULL); - vkDestroyBuffer(device, device_ubo_my_buffer.buffer, NULL); + // todo: destroy buffers for model topology + vkDestroyBuffer(device, device_lighting_ubo.buffer, NULL); vkDestroyImage(device, device_cyl_1_diffuse_texture.image, NULL); vkDestroyImage(device, device_cyl_1_normal_texture.image, NULL); vkDestroyImage(device, device_IT1_image.image, NULL); diff --git a/src/l2/tests/r0_assets.h b/src/l2/tests/r0_assets.h index 14995c3..dcd1bfc 100644 --- a/src/l2/tests/r0_assets.h +++ b/src/l2/tests/r0_assets.h @@ -12,28 +12,49 @@ typedef struct { vec3 pos; vec2 tex; -} Vertex; +} GenericMeshVertex; -#define Vertex_drop(vp) {} -#define Vertex_clone(vp) (*(vp)) +#define GenericMeshVertex_drop(vp) {} +#define GenericMeshVertex_clone(vp) (*(vp)) -VecT_trivmove_struct_Definition(Vertex) -VecT_trivmove_method_Definition(Vertex) -VecT_primitive_zeroinit_method_Definition(Vertex) -SpanT_struct_Definition(Vertex) -SpanT_method_Definition(Vertex) -SpanT_VecT_method_Definition(Vertex) +VecT_trivmove_struct_Definition(GenericMeshVertex) +VecT_trivmove_method_Definition(GenericMeshVertex) +VecT_primitive_zeroinit_method_Definition(GenericMeshVertex) +SpanT_struct_Definition(GenericMeshVertex) +SpanT_method_Definition(GenericMeshVertex) +SpanT_VecT_method_Definition(GenericMeshVertex) typedef struct { - VecVertex vertices; + VecGenericMeshVertex vertices; VecU32 indexes; } ModelTopology; void ModelTopology_drop(ModelTopology self) { - VecVertex_drop(self.vertices); + VecGenericMeshVertex_drop(self.vertices); VecU32_drop(self.indexes); } +ModelTopology ModelTopology_clone(const ModelTopology* self) { + return (ModelTopology){.vertices = VecGenericMeshVertex_new(&self->vertices), .indexes = VecU32_clone(&self->indexes)}; +} + +typedef struct { + ModelTopology topology; + U32 max_instance_count; +} ModelInSceneTemplate; + +void ModelInSceneTemplate_drop(ModelInSceneTemplate self) { + ModelTopology_drop(self.topology); +} + +ModelInSceneTemplate ModelInSceneTemplate_clone(const ModelInSceneTemplate* self) { + return (ModelInSceneTemplate){.topology = ModelTopology_clone(&self->topology), .max_instance_count = self->max_instance_count}; +} + +VecT_trivmove_struct_Definition(ModelInSceneTemplate) +VecT_trivmove_method_Definition(ModelInSceneTemplate) +VecT_primitive_zeroinit_method_Definition(ModelInSceneTemplate) + typedef struct { vec2 win_scale; } Pipeline1PushRangeVertex; @@ -77,19 +98,62 @@ VecT_trivmove_struct_Definition(Pipeline0PointLight) VecT_trivmove_method_Definition(Pipeline0PointLight) VecT_primitive_zeroinit_method_Definition(Pipeline0PointLight) +typedef struct { + mat4 model_trans; +} GenericMeshInstance; + +#define GenericMeshInstance_drop(vp) {} +#define GenericMeshInstance_clone(vp) (*(vp)) + +VecT_trivmove_struct_Definition(GenericMeshInstance) +VecT_trivmove_method_Definition(GenericMeshInstance) +VecT_primitive_zeroinit_method_Definition(GenericMeshInstance) + + +typedef struct { + VecModelInSceneTemplate models; + size_t point_lights_max_count; + size_t spotlights_max_count; +} SceneTemplate; + +size_t SceneTemplate_get_space_needed_for_all_instance_attributes(const SceneTemplate* self) { + size_t s = 0; + for (size_t mi = 0; mi < self->models.len; mi++) { + const ModelInSceneTemplate* M = VecModelInSceneTemplate_cat(&self->models, mi); + s += M->max_instance_count * sizeof(GenericMeshInstance); + } + return s; +} + +size_t SceneTemplate_get_space_needed_for_widest_state_transfer(const SceneTemplate* self) { + return self->point_lights_max_count * sizeof(Pipeline0PointLight) + + self->spotlights_max_count * sizeof(Pipeline0Spotlight) + + SceneTemplate_get_space_needed_for_all_instance_attributes(self); + +} + +size_t SceneTemplate_get_space_for_initial_model_topology_transfer(const SceneTemplate* self) { + size_t s = 0; + for (size_t mi = 0; mi < self->models.len; mi++) { + const ModelInSceneTemplate* M = VecModelInSceneTemplate_cat(&self->models, mi); + s += M->topology.vertices.len * sizeof(GenericMeshVertex) + M->topology.indexes.len * sizeof(U32); + } + return s; +} + #define pipeline_0_ubo_point_light_max_count 20 #define pipeline_0_ubo_spotlight_max_count 120 typedef struct { - int spotlight_count; int point_light_count; + int spotlight_count; char _padding_1[8]; Pipeline0PointLight point_light_arr[pipeline_0_ubo_point_light_max_count]; Pipeline0Spotlight spotlight_arr[pipeline_0_ubo_spotlight_max_count]; } Pipeline0UBO; size_t ModelTopology_get_space_needed_for_staging_buffer(const ModelTopology* self) { - return MAX_U64(self->vertices.len * sizeof(Vertex), self->indexes.len * sizeof(U32)); + return MAX_U64(self->vertices.len * sizeof(GenericMeshVertex), self->indexes.len * sizeof(U32)); } void TextureDataR8_pixel_maxing(TextureDataR8* self, S32 x, S32 y, U8 val) { @@ -205,33 +269,6 @@ void TextureDataR8_draw_one_segment_maxing(TextureDataR8* self, TextureDataR8_draw_inner_line_maxing(self, v1, v2, r_cut, r_decay); } -// TextureDataR8G8B8A8 generate_wood_texture() { -// const U32 width = 100; -// const U32 height = 100; -// TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height); -// for (U32 y = 0; y < width; y++) { -// for (U32 col = 0; col < height; col++) { -// *TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){150, 30, 50, 255}; -// } -// } -// for (U32 i = 0; i < 10; i++) { -// for (U32 y = 0; y < height; y++) { -// U32 col = 3 + i * 10 + ((30 < y + 3 * i && y - i < 60) ? 1 : 0); -// -// *TextureDataR8G8B8A8_at(&res, col, y) = (cvec4){130, 25, 40, 255}; -// *TextureDataR8G8B8A8_at(&res, col + 1, y) = (cvec4){80, 10, 15, 255}; -// *TextureDataR8G8B8A8_at(&res, col + 2, y) = (cvec4){70, 11, 12, 255}; -// *TextureDataR8G8B8A8_at(&res, col + 3, y) = (cvec4){125, 20, 20, 255}; -// } -// } -// for (U32 y = 0; y < 10; y++) { -// for (U32 col = 0; col < 10; col++) { -// *TextureDataR8G8B8A8_at(&res, col + 4, y + 13) = (cvec4){60, 8, 6, 255}; -// } -// } -// return res; -// } - ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { assert(k >= 1); const float a = M_PI_2f / (float)k; @@ -240,33 +277,33 @@ ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { const vec2 v1tex = {(r + w) / (2 * r + w), r / (2 * r + k * l)}; const vec2 v2tex = {r / (2 * r + w), 2 * r / (2 * r + k * l)}; const vec2 v3tex = {(r + w) / (2 * r + w), 2 * r / (2 * r + k * l)}; - VecVertex vertices = VecVertex_new(); // todo: reserve 4 * k + 6 - VecVertex_append(&vertices, (Vertex){.pos = {0, 0, 0}, .tex = v0tex}); - VecVertex_append(&vertices, (Vertex){.pos = {w, 0, 0}, .tex = v1tex}); - VecVertex_append(&vertices, (Vertex){.pos = {0, r, 0}, .tex = v2tex}); - VecVertex_append(&vertices, (Vertex){.pos = {w, r, 0}, .tex = v3tex}); - VecVertex_append(&vertices, (Vertex){.pos = {0, 0, -r}, .tex = {r / (2 * r + w), 0}}); - VecVertex_append(&vertices, (Vertex){.pos = {w, 0, -r}, .tex = {(r + w) / (2 * r + w), 0}}); + VecGenericMeshVertex vertices = VecGenericMeshVertex_new(); // todo: reserve 4 * k + 6 + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, 0, 0}, .tex = v0tex}); + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, 0, 0}, .tex = v1tex}); + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, r, 0}, .tex = v2tex}); + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, r, 0}, .tex = v3tex}); + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, 0, -r}, .tex = {r / (2 * r + w), 0}}); + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, 0, -r}, .tex = {(r + w) / (2 * r + w), 0}}); for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){ .pos = {0, cosf(a * i) * r, -sinf(a * i) * r}, .tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * i), r / (2 * r + k * l) * cos(a * i)}) }); } for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){ .pos = {w, cosf(a * i) * r, -sinf(a * i) * r}, .tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * i), r / (2*r + k * l) * cos(a * i)}) }); } for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){ .pos = {0, cosf(a * i) * r, -sinf(a * i) * r}, .tex = {v2tex.x, v2tex.y + i * l / (2*r + k * l)} }); } for (U32 i = 1; i <= k; i++) { - VecVertex_append(&vertices, (Vertex){ + VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){ .pos = {w, cosf(a * i) * r, -sinf(a * i) * r}, .tex = {v3tex.x, v3tex.y + i * l / (2*r + k * l)} }); diff --git a/src/l2/tests/r0_scene.h b/src/l2/tests/r0_scene.h index 5a0651b..7c4cabd 100644 --- a/src/l2/tests/r0_scene.h +++ b/src/l2/tests/r0_scene.h @@ -3,7 +3,8 @@ #include "r0_assets.h" -/* No offset yet */ +/* No offset yet. + * Contains references to vulkan handlers for buffers */ typedef struct { VkBuffer vbo; VkBuffer ebo; @@ -17,13 +18,25 @@ VecT_trivmove_struct_Definition(ModelOnScene) VecT_trivmove_method_Definition(ModelOnScene) VecT_primitive_zeroinit_method_Definition(ModelOnScene) +/* Contains both data for model instances attributes and buffer (+offset) where it is stored */ typedef struct { ModelOnScene model; - mat4 model_t; + VecGenericMeshInstance instances; + VkBuffer instance_attr_buf; + VkDeviceSize instance_attr_buf_offset; + U32 limit_max_instance_count; } UsedModelOnScene; -#define UsedModelOnScene_drop(vp) {} -#define UsedModelOnScene_clone(vp) (*(vp)) +void UsedModelOnScene_drop(UsedModelOnScene self) { + VecGenericMeshInstance_drop(self.instances); +} + +UsedModelOnScene UsedModelOnScene_clone(const UsedModelOnScene* self) { + return (UsedModelOnScene){.model = self->model, .instances = VecGenericMeshInstance_clone(&self->instances), + .instance_attr_buf = self->instance_attr_buf, .instance_attr_buf_offset = self->instance_attr_buf_offset, + .limit_max_instance_count = self->limit_max_instance_count + }; +} VecT_trivmove_struct_Definition(UsedModelOnScene) VecT_trivmove_method_Definition(UsedModelOnScene) @@ -96,7 +109,7 @@ typedef struct { } Scene; Scene Scene_new() { - return (Scene){.models = VecUsedModelOnScene_new(), .color = {.float32 = {1, 0.5, 0.7}}, + return (Scene){.models = VecUsedModelOnScene_new(), .color = {.float32 = {0, 0, 0, 1}}, .gamma_correction_factor = 2.2, .hdr_factor = 1, .lsd_factor = 0, .anim_time = 0, .spotlights = VecPipeline0Spotlight_new(), .point_lights = VecPipeline0PointLight_new()}; } @@ -105,5 +118,39 @@ void Scene_drop(Scene self) { VecUsedModelOnScene_drop(self.models); } +void SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( + const SceneTemplate* scene_template, const Scene* scene, char* host_mem_buffer_mem, + VkCommandBuffer command_buffer, VkBuffer host_memory_buffer + ) { + assert(scene_template->models.len == scene->models.len); + + if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) + abortf("vkResetCommandBuffer"); + VkCommandBufferBeginInfo info_begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS) + abortf("vkBeginCommandBuffer"); + + size_t offset = 0; + // todo: use BufferCopyCmd 2 (to perform all the copying in one command) + // todo: ot use one buffer per all the data + // VecVkBufferCopy regions_to_copy = VecVkBufferCopy_new_zeroinit(scene_template->models.len * 2); + for (size_t mi = 0; mi < scene_template->models.len; mi++) { + const ModelInSceneTemplate* mt = VecModelInSceneTemplate_cat(&scene_template->models, mi); + const UsedModelOnScene* m_buf = VecUsedModelOnScene_cat(&scene->models, mi); + size_t vbo_len = mt->topology.vertices.len * sizeof(GenericMeshVertex); + memcpy(host_mem_buffer_mem + offset, mt->topology.vertices.buf, vbo_len); + VkBufferCopy ra = {.srcOffset = offset, .dstOffset = 0, .size = vbo_len}; + vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->model.vbo, 1, &ra); + offset += vbo_len; + size_t ebo_len = mt->topology.indexes.len * sizeof(U32); + memcpy(host_mem_buffer_mem + offset, mt->topology.indexes.buf, ebo_len); + VkBufferCopy rb = {.srcOffset = offset, .dstOffset = 0, .size = ebo_len}; + vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->model.ebo, 1, &rb); + offset += ebo_len; + } + + if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) + abortf("vkEndCommandBuffer"); +} #endif diff --git a/src/l2/tests/test_shaders/glsl/0/0.frag b/src/l2/tests/test_shaders/glsl/0/0.frag index 3bd7fd2..e533b42 100644 --- a/src/l2/tests/test_shaders/glsl/0/0.frag +++ b/src/l2/tests/test_shaders/glsl/0/0.frag @@ -1,6 +1,7 @@ #version 450 layout(location = 0) in vec2 fsin_tex; +layout(location = 1) in vec3 fsin_pos; layout(location = 0) out vec4 fin_color; @@ -8,29 +9,54 @@ layout(binding = 1) uniform sampler2D color_tex; layout(binding = 2) uniform sampler2D normal_map; -struct Pipeline0Spotlight -{ - vec3 pos; - vec3 dir; - vec3 colour; +layout(push_constant, std430) uniform pc { + layout(offset = 64) vec3 camera_pos; +}; + +struct Pipeline0Spotlight { + vec3 pos; + vec3 dir; + vec3 color; float range; }; -struct Pipeline0PointLight -{ +struct Pipeline0PointLight { vec3 pos; - vec3 colour; + vec3 color; }; -layout(std140, binding = 0) uniform Pipeline0UBO -{ - int spotlight_count; - int point_light_count; - +layout(std140, binding = 0) uniform Pipeline0UBO { + int point_light_count; + int spotlight_count; Pipeline0PointLight point_light_arr[20]; - Pipeline0Spotlight spotlight_arr [120]; + Pipeline0Spotlight spotlight_arr [120]; }; +float get_intensity(float dist){ + return 1 / pow(dist + 1, 2); +} + void main(){ - fin_color = texture(normal_map, fsin_tex); + vec3 compressed_normal = texture(normal_map, fsin_tex).xyz; + vec3 norm = compressed_normal * 2 - 1; + vec3 diffuse_illumination = vec3(0); + vec3 specular_illumination = vec3(0); + for (int i = 0; i < point_light_count; i++) { + Pipeline0PointLight lamp = point_light_arr[i]; + vec3 to_light = -fsin_pos + lamp.pos; + float dist = length(to_light); + vec3 U = to_light / dist; + diffuse_illumination += get_intensity(dist) * max(0.02, dot(U, norm)) * lamp.color; + vec3 A = reflect(-U, norm); + vec3 B = normalize(-fsin_pos+camera_pos); + specular_illumination += get_intensity(dist) * pow(max(0, dot(A, B)), 32) * lamp.color; + } + for (int i = 0; i < spotlight_count; i++) { + Pipeline0Spotlight lamp = spotlight_arr[i]; + } + vec3 natural_color = texture(color_tex, fsin_tex).xyz; + // todo: add specular texture +// vec3 color = natural_color * (diffuse_illumination + specular_illumination); + vec3 color = natural_color * ( specular_illumination); + fin_color = vec4(color, 1); } diff --git a/src/l2/tests/test_shaders/glsl/0/0.vert b/src/l2/tests/test_shaders/glsl/0/0.vert index d28b556..d00b8bf 100644 --- a/src/l2/tests/test_shaders/glsl/0/0.vert +++ b/src/l2/tests/test_shaders/glsl/0/0.vert @@ -2,18 +2,19 @@ layout(location = 0) in vec3 pos; layout(location = 1) in vec2 tex; +layout(location = 2) in mat4 model_t; +/* 2 <- 3, 4, 5 */ layout(location = 0) out vec2 vsout_tex; +layout(location = 1) out vec3 vsout_pos; layout(push_constant, std430) uniform pc { - /* Individual transformation for a model. Fits in push constant range - Includes global perspective matrix and camera matrix, but for each model there is a distinct - transformation matrix. Right now I only have one instance for each model, - otherwise I would use per-instance vertex attribute */ - mat4 t; + mat4 proj_cam_t; }; void main(){ vsout_tex = tex; - gl_Position = t * vec4(pos, 1); + vec4 real_pos = model_t * vec4(pos, 1); + vsout_pos = real_pos.xyz; + gl_Position = proj_cam_t * real_pos; } \ No newline at end of file diff --git a/src/l2/tests/test_shaders/glsl/1/1.frag b/src/l2/tests/test_shaders/glsl/1/1.frag index 410676e..627749c 100644 --- a/src/l2/tests/test_shaders/glsl/1/1.frag +++ b/src/l2/tests/test_shaders/glsl/1/1.frag @@ -14,5 +14,6 @@ layout(push_constant, std430) uniform pc { void main() { vec2 tex_offset = 1.0 / textureSize(prev, 0); - fin_color = texture(prev, gl_FragCoord.xy * tex_offset); + vec4 hdr_color = texture(prev, gl_FragCoord.xy * tex_offset); + fin_color = vec4(vec3(1) - exp(-hdr_factor * hdr_color.xyz), 1); }