|  |  |  | @ -111,11 +111,7 @@ typedef struct GraphicsPipelineInfoStruct { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkDescriptorSetLayoutCreateInfo descriptor_info; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t                         input_bindings_count; | 
		
	
		
			
				|  |  |  |  |   VkVertexInputBindingDescription* input_bindings; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t                           input_attributes_count; | 
		
	
		
			
				|  |  |  |  |   VkVertexInputAttributeDescription* input_attributes; | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo input_info; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32_t shader_stages_count; | 
		
	
		
			
				|  |  |  |  |   VkPipelineShaderStageCreateInfo* shader_stages; | 
		
	
	
		
			
				
					|  |  |  | @ -131,6 +127,7 @@ typedef struct GraphicsPipelineStruct { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineLayout      layout; | 
		
	
		
			
				|  |  |  |  |   VkPipeline            pipeline; | 
		
	
		
			
				|  |  |  |  |   VkPipeline            offscreen_pipeline; | 
		
	
		
			
				|  |  |  |  | } GraphicsPipeline; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | typedef struct VulkanContextStruct { | 
		
	
	
		
			
				
					|  |  |  | @ -184,9 +181,11 @@ typedef struct VulkanContextStruct { | 
		
	
		
			
				|  |  |  |  |   uint32_t max_frames_in_flight; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Per frame objects
 | 
		
	
		
			
				|  |  |  |  |   VkCommandBuffer* offscreen_command_buffers; | 
		
	
		
			
				|  |  |  |  |   VkCommandBuffer* swapchain_command_buffers; | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* image_available_semaphores; | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* render_finished_semaphores; | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* offscreen_complete_semaphores; | 
		
	
		
			
				|  |  |  |  |   VkFence* in_flight_fences; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkRenderPass render_pass; | 
		
	
	
		
			
				
					|  |  |  | @ -220,10 +219,6 @@ struct Vertex { | 
		
	
		
			
				|  |  |  |  |   vec3 color; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct ModelUBO { | 
		
	
		
			
				|  |  |  |  |   mat4 model; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | struct SceneUBO { | 
		
	
		
			
				|  |  |  |  |   mat4 test; | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
	
		
			
				
					|  |  |  | @ -1397,13 +1392,12 @@ void command_draw_object(Object object, VkCommandBuffer command_buffer) { | 
		
	
		
			
				|  |  |  |  |   vkCmdDrawIndexed(command_buffer, mesh->index_count, 1, 0, 0, 0); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | void command_draw_pipeline(GraphicsPipeline pipeline, uint32_t object_count, Object* objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, struct ScenePC* scene_constants, VkDeviceAddress object_buffer_addr, VkCommandBuffer command_buffer) { | 
		
	
		
			
				|  |  |  |  |   vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); | 
		
	
		
			
				|  |  |  |  |   vkCmdPushConstants(command_buffer, pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(struct ScenePC), scene_constants); | 
		
	
		
			
				|  |  |  |  |   vkCmdPushConstants(command_buffer, pipeline.layout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(struct ScenePC), sizeof(VkDeviceAddress), &object_buffer_addr); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Bind the scene descriptor
 | 
		
	
		
			
				|  |  |  |  |   vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, &scene_descriptors[frame_num], 0, 0); | 
		
	
		
			
				|  |  |  |  | void command_draw_pipeline(GraphicsPipeline pipeline, uint32_t object_count, Object* objects, uint32_t frame_num, VkCommandBuffer command_buffer, int offscreen) { | 
		
	
		
			
				|  |  |  |  |   if(offscreen) { | 
		
	
		
			
				|  |  |  |  |     vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.offscreen_pipeline); | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(pipeline.descriptors != NULL) { | 
		
	
		
			
				|  |  |  |  |     vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 1, 1, &pipeline.descriptors[frame_num], 0, 0); | 
		
	
	
		
			
				
					|  |  |  | @ -1414,7 +1408,39 @@ void command_draw_pipeline(GraphicsPipeline pipeline, uint32_t object_count, Obj | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult command_draw_scene(uint32_t pipelines_count, GraphicsPipeline* pipelines, uint32_t* object_counts, Object** objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, struct ScenePC* scene_constants, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent, VkDeviceAddress object_buffer_addr) { | 
		
	
		
			
				|  |  |  |  | // Setup a scene for vkCmdDrawIndexedIndirect
 | 
		
	
		
			
				|  |  |  |  | // Before the call is made the following needs to be ready:
 | 
		
	
		
			
				|  |  |  |  | // 1) Vertex data for entire scene in one vertex buffer
 | 
		
	
		
			
				|  |  |  |  | // 2) Index data for entire scene in one index buffer
 | 
		
	
		
			
				|  |  |  |  | // 3) Descriptor data in single descriptor set
 | 
		
	
		
			
				|  |  |  |  | //   a) e.x. all textures for the draw call need to be in the bound pipeline descriptor set
 | 
		
	
		
			
				|  |  |  |  | // 4) Object Data populated per-instance into buffer which will be pushed by VkDeviceAddress
 | 
		
	
		
			
				|  |  |  |  | // 5) Buffer of draw command ordered by instance id(first is 0, increase by 1 every 'stride')
 | 
		
	
		
			
				|  |  |  |  | //
 | 
		
	
		
			
				|  |  |  |  | // Once that is setup, the call to vkCmdDrawIndexed will happen and then:
 | 
		
	
		
			
				|  |  |  |  | // 1) For each draw command read from the command buffer
 | 
		
	
		
			
				|  |  |  |  | //   a) Consume the indices/vertices to run the vertex shaders
 | 
		
	
		
			
				|  |  |  |  | //     i) Vertex shaders access the per-instance object data indexed by gl_instanceID
 | 
		
	
		
			
				|  |  |  |  | //     ii) This object data can have indices for other descriptors
 | 
		
	
		
			
				|  |  |  |  | //       x) e.x. a shader can read object data with int Z that tell it to use a sampler at binding Z
 | 
		
	
		
			
				|  |  |  |  | //
 | 
		
	
		
			
				|  |  |  |  | // If I want to start by not worrying about dynamic object load/unload then I can create the above buffers
 | 
		
	
		
			
				|  |  |  |  | // when loading the scene, and free them all at once
 | 
		
	
		
			
				|  |  |  |  | //
 | 
		
	
		
			
				|  |  |  |  | // If I want to start worrying about loading/unloading then I need to find a way to efficiently reconstruct
 | 
		
	
		
			
				|  |  |  |  | // these buffers on changes
 | 
		
	
		
			
				|  |  |  |  | // Ideas:
 | 
		
	
		
			
				|  |  |  |  | //  - Mark objects as 'deleted' to cheaply cull during a compute cull/vertex shader
 | 
		
	
		
			
				|  |  |  |  | //    - Would require only a 1-bit change per deletion
 | 
		
	
		
			
				|  |  |  |  | //    - Would require defragmentation periodically(or whenever trying to add without space)
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult create_scene(){ | 
		
	
		
			
				|  |  |  |  |    | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult command_draw_scene(uint32_t pipelines_count, GraphicsPipeline* pipelines, uint32_t* object_counts, Object** objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, struct ScenePC* scene_constants, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent, VkDeviceAddress object_buffer_addr, int offscreen) { | 
		
	
		
			
				|  |  |  |  |   VkCommandBufferBeginInfo begin_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, | 
		
	
		
			
				|  |  |  |  |     .flags = 0, | 
		
	
	
		
			
				
					|  |  |  | @ -1473,8 +1499,14 @@ VkResult command_draw_scene(uint32_t pipelines_count, GraphicsPipeline* pipeline | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   vkCmdSetScissor(command_buffer, 0, 1, &scissor); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vkCmdPushConstants(command_buffer, pipelines[0].layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(struct ScenePC), scene_constants); | 
		
	
		
			
				|  |  |  |  |   vkCmdPushConstants(command_buffer, pipelines[0].layout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(struct ScenePC), sizeof(VkDeviceAddress), &object_buffer_addr); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Bind the scene descriptor
 | 
		
	
		
			
				|  |  |  |  |   vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines[0].layout, 0, 1, &scene_descriptors[frame_num], 0, 0); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for(uint i = 0; i < pipelines_count; i++) { | 
		
	
		
			
				|  |  |  |  |     command_draw_pipeline(pipelines[i], object_counts[i], objects[i], frame_num, scene_descriptors, scene_constants, object_buffer_addr, command_buffer); | 
		
	
		
			
				|  |  |  |  |     command_draw_pipeline(pipelines[i], object_counts[i], objects[i], frame_num, command_buffer, offscreen); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vkCmdEndRenderPass(command_buffer); | 
		
	
	
		
			
				
					|  |  |  | @ -1575,7 +1607,8 @@ Object create_renderable(Mesh* mesh, GraphicsPipeline* pipeline) { | 
		
	
		
			
				|  |  |  |  | VkResult create_graphics_pipeline( | 
		
	
		
			
				|  |  |  |  |     VkDevice device, | 
		
	
		
			
				|  |  |  |  |     VkExtent2D extent, | 
		
	
		
			
				|  |  |  |  |     VkRenderPass render_pass, | 
		
	
		
			
				|  |  |  |  |     VkRenderPass draw_render_pass, | 
		
	
		
			
				|  |  |  |  |     VkRenderPass offscreen_render_pass, | 
		
	
		
			
				|  |  |  |  |     GraphicsPipelineInfo pipeline_info, | 
		
	
		
			
				|  |  |  |  |     uint32_t max_frames_in_flight, | 
		
	
		
			
				|  |  |  |  |     GraphicsPipeline* out | 
		
	
	
		
			
				
					|  |  |  | @ -1685,14 +1718,6 @@ VkResult create_graphics_pipeline( | 
		
	
		
			
				|  |  |  |  |     .pDynamicStates = dynamic_states, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo vertex_input_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .vertexBindingDescriptionCount = pipeline_info.input_bindings_count, | 
		
	
		
			
				|  |  |  |  |     .pVertexBindingDescriptions = pipeline_info.input_bindings, | 
		
	
		
			
				|  |  |  |  |     .vertexAttributeDescriptionCount = pipeline_info.input_attributes_count, | 
		
	
		
			
				|  |  |  |  |     .pVertexAttributeDescriptions = pipeline_info.input_attributes, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineInputAssemblyStateCreateInfo input_assembly_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, | 
		
	
	
		
			
				
					|  |  |  | @ -1784,11 +1809,11 @@ VkResult create_graphics_pipeline( | 
		
	
		
			
				|  |  |  |  |     .blendConstants[3] = 0.0f, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkGraphicsPipelineCreateInfo info = { | 
		
	
		
			
				|  |  |  |  |   VkGraphicsPipelineCreateInfo draw_pipeline_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .stageCount = pipeline_info.shader_stages_count, | 
		
	
		
			
				|  |  |  |  |     .pStages = pipeline_info.shader_stages, | 
		
	
		
			
				|  |  |  |  |     .pVertexInputState = &vertex_input_info, | 
		
	
		
			
				|  |  |  |  |     .pVertexInputState = &pipeline_info.input_info, | 
		
	
		
			
				|  |  |  |  |     .pInputAssemblyState = &input_assembly_info, | 
		
	
		
			
				|  |  |  |  |     .pViewportState = &viewport_state, | 
		
	
		
			
				|  |  |  |  |     .pRasterizationState = &raster_info, | 
		
	
	
		
			
				
					|  |  |  | @ -1797,13 +1822,56 @@ VkResult create_graphics_pipeline( | 
		
	
		
			
				|  |  |  |  |     .pDepthStencilState = &depth_info, | 
		
	
		
			
				|  |  |  |  |     .pMultisampleState = &multisample_info, | 
		
	
		
			
				|  |  |  |  |     .layout = out->layout, | 
		
	
		
			
				|  |  |  |  |     .renderPass = render_pass, | 
		
	
		
			
				|  |  |  |  |     .renderPass = draw_render_pass, | 
		
	
		
			
				|  |  |  |  |     .subpass = 0, | 
		
	
		
			
				|  |  |  |  |     .basePipelineHandle = VK_NULL_HANDLE, | 
		
	
		
			
				|  |  |  |  |     .basePipelineIndex = -1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &info, 0, &out->pipeline); | 
		
	
		
			
				|  |  |  |  |   VkPipelineColorBlendAttachmentState offscreen_attachment_states[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, | 
		
	
		
			
				|  |  |  |  |       .blendEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineColorBlendStateCreateInfo offscreen_blend_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .logicOpEnable = VK_FALSE, | 
		
	
		
			
				|  |  |  |  |     .logicOp = VK_LOGIC_OP_COPY, | 
		
	
		
			
				|  |  |  |  |     .attachmentCount = sizeof(offscreen_attachment_states)/sizeof(VkPipelineColorBlendAttachmentState), | 
		
	
		
			
				|  |  |  |  |     .pAttachments = offscreen_attachment_states, | 
		
	
		
			
				|  |  |  |  |     .blendConstants[0] = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .blendConstants[1] = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .blendConstants[2] = 0.0f, | 
		
	
		
			
				|  |  |  |  |     .blendConstants[3] = 0.0f, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkGraphicsPipelineCreateInfo offscreen_pipeline_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .stageCount = pipeline_info.shader_stages_count, | 
		
	
		
			
				|  |  |  |  |     .pStages = pipeline_info.shader_stages, // TODO: offscreen stages
 | 
		
	
		
			
				|  |  |  |  |     .pVertexInputState = &pipeline_info.input_info, | 
		
	
		
			
				|  |  |  |  |     .pInputAssemblyState = &input_assembly_info, | 
		
	
		
			
				|  |  |  |  |     .pViewportState = &viewport_state, | 
		
	
		
			
				|  |  |  |  |     .pRasterizationState = &raster_info, | 
		
	
		
			
				|  |  |  |  |     .pColorBlendState = &offscreen_blend_info, | 
		
	
		
			
				|  |  |  |  |     .pDynamicState = &dynamic_info, | 
		
	
		
			
				|  |  |  |  |     .pDepthStencilState = &depth_info, | 
		
	
		
			
				|  |  |  |  |     .pMultisampleState = &multisample_info, | 
		
	
		
			
				|  |  |  |  |     .layout = out->layout, | 
		
	
		
			
				|  |  |  |  |     .renderPass = offscreen_render_pass, | 
		
	
		
			
				|  |  |  |  |     .subpass = 0, | 
		
	
		
			
				|  |  |  |  |     .basePipelineHandle = VK_NULL_HANDLE, | 
		
	
		
			
				|  |  |  |  |     .basePipelineIndex = -1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &draw_pipeline_info, 0, &out->pipeline); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &offscreen_pipeline_info, 0, &out->offscreen_pipeline); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -1811,7 +1879,7 @@ VkResult create_graphics_pipeline( | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult create_simple_mesh_pipeline(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, GraphicsPipeline* out) { | 
		
	
		
			
				|  |  |  |  | VkResult create_simple_mesh_pipeline(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkRenderPass offscreen_render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, GraphicsPipeline* out) { | 
		
	
		
			
				|  |  |  |  |   if(out == NULL) { | 
		
	
		
			
				|  |  |  |  |     return VK_ERROR_VALIDATION_FAILED_EXT; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -1873,21 +1941,26 @@ VkResult create_simple_mesh_pipeline(VkDevice device, VkExtent2D extent, VkRende | 
		
	
		
			
				|  |  |  |  |     .pNext = NULL, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo input_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .pVertexBindingDescriptions = bindings, | 
		
	
		
			
				|  |  |  |  |     .vertexBindingDescriptionCount = sizeof(bindings)/sizeof(VkVertexInputBindingDescription), | 
		
	
		
			
				|  |  |  |  |     .pVertexAttributeDescriptions = attributes, | 
		
	
		
			
				|  |  |  |  |     .vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GraphicsPipelineInfo pipeline_info = { | 
		
	
		
			
				|  |  |  |  |     .descriptor_info = set_info, | 
		
	
		
			
				|  |  |  |  |     .shader_stages_count = sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), | 
		
	
		
			
				|  |  |  |  |     .shader_stages = shader_stages, | 
		
	
		
			
				|  |  |  |  |     .scene_layout = scene_layout, | 
		
	
		
			
				|  |  |  |  |     .input_bindings = bindings, | 
		
	
		
			
				|  |  |  |  |     .input_bindings_count = sizeof(bindings)/sizeof(VkVertexInputBindingDescription), | 
		
	
		
			
				|  |  |  |  |     .input_attributes = attributes, | 
		
	
		
			
				|  |  |  |  |     .input_attributes_count = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), | 
		
	
		
			
				|  |  |  |  |     .input_info = input_info, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return create_graphics_pipeline(device, extent, render_pass, pipeline_info, max_frames_in_flight, out); | 
		
	
		
			
				|  |  |  |  |   return create_graphics_pipeline(device, extent, render_pass, offscreen_render_pass, pipeline_info, max_frames_in_flight, out); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, VkCommandPool transfer_pool, VkQueue transfer_queue, VkQueue graphics_queue, VkCommandPool graphics_pool, uint32_t transfer_family, uint32_t graphics_family, GraphicsPipeline* out) { | 
		
	
		
			
				|  |  |  |  | VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryProperties memories, VkExtent2D extent, VkRenderPass render_pass, VkRenderPass offscreen_render_pass, VkDescriptorSetLayout scene_layout, uint32_t max_frames_in_flight, VkCommandPool transfer_pool, VkQueue transfer_queue, VkQueue graphics_queue, VkCommandPool graphics_pool, uint32_t transfer_family, uint32_t graphics_family, GraphicsPipeline* out) { | 
		
	
		
			
				|  |  |  |  |   if(out == NULL) { | 
		
	
		
			
				|  |  |  |  |     return VK_ERROR_VALIDATION_FAILED_EXT; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -1968,15 +2041,20 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro | 
		
	
		
			
				|  |  |  |  |     .pNext = &set_flags_info, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineVertexInputStateCreateInfo input_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .pVertexBindingDescriptions = bindings, | 
		
	
		
			
				|  |  |  |  |     .vertexBindingDescriptionCount = sizeof(bindings)/sizeof(VkVertexInputBindingDescription), | 
		
	
		
			
				|  |  |  |  |     .pVertexAttributeDescriptions = attributes, | 
		
	
		
			
				|  |  |  |  |     .vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GraphicsPipelineInfo pipeline_info = { | 
		
	
		
			
				|  |  |  |  |     .descriptor_info = set_info, | 
		
	
		
			
				|  |  |  |  |     .shader_stages_count = sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo), | 
		
	
		
			
				|  |  |  |  |     .shader_stages = shader_stages, | 
		
	
		
			
				|  |  |  |  |     .scene_layout = scene_layout, | 
		
	
		
			
				|  |  |  |  |     .input_bindings = bindings, | 
		
	
		
			
				|  |  |  |  |     .input_bindings_count = sizeof(bindings)/sizeof(VkVertexInputBindingDescription), | 
		
	
		
			
				|  |  |  |  |     .input_attributes = attributes, | 
		
	
		
			
				|  |  |  |  |     .input_attributes_count = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription), | 
		
	
		
			
				|  |  |  |  |     .input_info = input_info, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GPUPage* memory = NULL; | 
		
	
	
		
			
				
					|  |  |  | @ -1985,7 +2063,7 @@ VkResult create_texture_mesh_pipeline(VkDevice device, VkPhysicalDeviceMemoryPro | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = create_graphics_pipeline(device, extent, render_pass, pipeline_info, max_frames_in_flight, out); | 
		
	
		
			
				|  |  |  |  |   result = create_graphics_pipeline(device, extent, render_pass, offscreen_render_pass, pipeline_info, max_frames_in_flight, out); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					|  |  |  | @ -2297,6 +2375,12 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     context->swapchain_command_buffers = swapchain_command_buffers; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   context->offscreen_command_buffers = create_command_buffers(context->device, context->graphics_command_pool, context->max_frames_in_flight); | 
		
	
		
			
				|  |  |  |  |   if(swapchain_command_buffers == VK_NULL_HANDLE) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create vulkan swapchain command buffer\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* ia_semaphores = create_semaphores(context->device, 0, max_frames_in_flight); | 
		
	
		
			
				|  |  |  |  |   if(ia_semaphores == 0) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create vulkan image available semaphores\n"); | 
		
	
	
		
			
				
					|  |  |  | @ -2313,6 +2397,11 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     context->render_finished_semaphores = rf_semaphores; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   context->offscreen_complete_semaphores = create_semaphores(context->device, 0, 1); | 
		
	
		
			
				|  |  |  |  |   if(context->offscreen_complete_semaphores == NULL) { | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkFence* if_fences = create_fences(context->device, VK_FENCE_CREATE_SIGNALED_BIT, max_frames_in_flight); | 
		
	
		
			
				|  |  |  |  |   if(if_fences == 0) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create vulkan in flight fence\n"); | 
		
	
	
		
			
				
					|  |  |  | @ -2328,7 +2417,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkImageCreateInfo g_pos_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, | 
		
	
		
			
				|  |  |  |  |     .imageType = VK_IMAGE_TYPE_2D, | 
		
	
		
			
				|  |  |  |  |     .extent = { | 
		
	
		
			
				|  |  |  |  |       .width = context->swapchain_extent.width, | 
		
	
	
		
			
				
					|  |  |  | @ -2368,6 +2457,168 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkExtent3D offscreen_extent = { | 
		
	
		
			
				|  |  |  |  |     .width = context->swapchain_extent.width, | 
		
	
		
			
				|  |  |  |  |     .height = context->swapchain_extent.height, | 
		
	
		
			
				|  |  |  |  |     .depth = 1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkImageCreateInfo offscreen_depth_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .imageType = VK_IMAGE_TYPE_2D, | 
		
	
		
			
				|  |  |  |  |     .pNext = NULL, | 
		
	
		
			
				|  |  |  |  |     .extent = offscreen_extent, | 
		
	
		
			
				|  |  |  |  |     .mipLevels = 1, | 
		
	
		
			
				|  |  |  |  |     .arrayLayers = 1, | 
		
	
		
			
				|  |  |  |  |     .format = context->depth_format, | 
		
	
		
			
				|  |  |  |  |     .tiling = VK_IMAGE_TILING_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |     .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |     .samples = VK_SAMPLE_COUNT_1_BIT, | 
		
	
		
			
				|  |  |  |  |     .flags = 0, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = gpu_image_malloc(context->device, context->g_buffer_page, &offscreen_depth_info, &context->g_image_depth); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to allocate g_image_depth\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkImageViewCreateInfo g_depth_view_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .image = context->g_image_depth.handle, | 
		
	
		
			
				|  |  |  |  |     .viewType = VK_IMAGE_VIEW_TYPE_2D, | 
		
	
		
			
				|  |  |  |  |     .format = context->depth_format, | 
		
	
		
			
				|  |  |  |  |     .components = { | 
		
	
		
			
				|  |  |  |  |       .r = VK_COMPONENT_SWIZZLE_IDENTITY, | 
		
	
		
			
				|  |  |  |  |       .g = VK_COMPONENT_SWIZZLE_IDENTITY, | 
		
	
		
			
				|  |  |  |  |       .b = VK_COMPONENT_SWIZZLE_IDENTITY, | 
		
	
		
			
				|  |  |  |  |       .a = VK_COMPONENT_SWIZZLE_IDENTITY, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     .subresourceRange = { | 
		
	
		
			
				|  |  |  |  |       .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT, | 
		
	
		
			
				|  |  |  |  |       .baseMipLevel = 0, | 
		
	
		
			
				|  |  |  |  |       .levelCount = 1, | 
		
	
		
			
				|  |  |  |  |       .baseArrayLayer = 0, | 
		
	
		
			
				|  |  |  |  |       .layerCount = 1, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateImageView(context->device, &g_depth_view_info, 0, &context->g_image_view_depth); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "Failed to allocate g_image_view_depth\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(context->device, context->extra_graphics_pool, context->queues.graphics, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, context->g_image_depth.handle, 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_IMAGE_ASPECT_DEPTH_BIT); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "Failed to transition g_image_depth to VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkAttachmentDescription offscreen_attachments[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .format = VK_FORMAT_R16G16B16A16_SFLOAT, | 
		
	
		
			
				|  |  |  |  |       .samples = VK_SAMPLE_COUNT_1_BIT, | 
		
	
		
			
				|  |  |  |  |       .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | 
		
	
		
			
				|  |  |  |  |       .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | 
		
	
		
			
				|  |  |  |  |       .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | 
		
	
		
			
				|  |  |  |  |       .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, | 
		
	
		
			
				|  |  |  |  |       .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | 
		
	
		
			
				|  |  |  |  |       .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .format = context->depth_format, | 
		
	
		
			
				|  |  |  |  |       .samples = VK_SAMPLE_COUNT_1_BIT, | 
		
	
		
			
				|  |  |  |  |       .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, | 
		
	
		
			
				|  |  |  |  |       .storeOp = VK_ATTACHMENT_STORE_OP_STORE, | 
		
	
		
			
				|  |  |  |  |       .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, | 
		
	
		
			
				|  |  |  |  |       .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, | 
		
	
		
			
				|  |  |  |  |       .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |       .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkAttachmentReference offscreen_attachment_refs[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .attachment = 0, | 
		
	
		
			
				|  |  |  |  |       .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkAttachmentReference offscreen_depth_reference = { | 
		
	
		
			
				|  |  |  |  |     .attachment = 1, | 
		
	
		
			
				|  |  |  |  |     .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSubpassDescription offscreen_pass_descs[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, | 
		
	
		
			
				|  |  |  |  |       .colorAttachmentCount = sizeof(offscreen_attachment_refs)/sizeof(VkAttachmentReference), | 
		
	
		
			
				|  |  |  |  |       .pColorAttachments = offscreen_attachment_refs, | 
		
	
		
			
				|  |  |  |  |       .pDepthStencilAttachment = &offscreen_depth_reference, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSubpassDependency offscreen_pass_dependencies[] = { | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .srcSubpass = VK_SUBPASS_EXTERNAL, | 
		
	
		
			
				|  |  |  |  |       .dstSubpass = 0, | 
		
	
		
			
				|  |  |  |  |       .srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, | 
		
	
		
			
				|  |  |  |  |       .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, | 
		
	
		
			
				|  |  |  |  |       .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT, | 
		
	
		
			
				|  |  |  |  |       .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, | 
		
	
		
			
				|  |  |  |  |       .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       .srcSubpass = 0, | 
		
	
		
			
				|  |  |  |  |       .dstSubpass = VK_SUBPASS_EXTERNAL, | 
		
	
		
			
				|  |  |  |  |       .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, | 
		
	
		
			
				|  |  |  |  |       .dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, | 
		
	
		
			
				|  |  |  |  |       .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, | 
		
	
		
			
				|  |  |  |  |       .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, | 
		
	
		
			
				|  |  |  |  |       .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, | 
		
	
		
			
				|  |  |  |  |     }, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkRenderPassCreateInfo offscreen_pass_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .attachmentCount = sizeof(offscreen_attachments)/sizeof(VkAttachmentDescription), | 
		
	
		
			
				|  |  |  |  |     .pAttachments = offscreen_attachments, | 
		
	
		
			
				|  |  |  |  |     .subpassCount = sizeof(offscreen_pass_descs)/sizeof(VkSubpassDescription), | 
		
	
		
			
				|  |  |  |  |     .pSubpasses = offscreen_pass_descs, | 
		
	
		
			
				|  |  |  |  |     .dependencyCount = sizeof(offscreen_pass_dependencies)/sizeof(VkSubpassDependency), | 
		
	
		
			
				|  |  |  |  |     .pDependencies = offscreen_pass_dependencies, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateRenderPass(context->device, &offscreen_pass_info, 0, &context->g_renderpass); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "Failed to create offscreen renderpass\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkImageView offscreen_fb_attachments[2] = { | 
		
	
		
			
				|  |  |  |  |     context->g_image_view_position, | 
		
	
		
			
				|  |  |  |  |     context->g_image_view_depth, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkFramebufferCreateInfo offscreen_framebuffer_info = { | 
		
	
		
			
				|  |  |  |  |       .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |       .renderPass = context->g_renderpass, | 
		
	
		
			
				|  |  |  |  |       .attachmentCount = sizeof(offscreen_fb_attachments)/sizeof(VkImageView), | 
		
	
		
			
				|  |  |  |  |       .pAttachments = offscreen_fb_attachments, | 
		
	
		
			
				|  |  |  |  |       .width = context->swapchain_extent.width, | 
		
	
		
			
				|  |  |  |  |       .height = context->swapchain_extent.height, | 
		
	
		
			
				|  |  |  |  |       .layers = 1, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateFramebuffer(context->device, &offscreen_framebuffer_info, 0, &context->g_framebuffer); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to allocate offscreen framebuffer\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return context; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -2740,7 +2991,7 @@ struct ScenePC get_scene_constants(vec3 world_position, versor world_rotation, f | 
		
	
		
			
				|  |  |  |  |   return constants; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult draw_frame(VulkanContext* context, SceneContext* scene, uint32_t materials_count, GraphicsPipeline* pipelines, uint32_t* objects_counts, Object** objects, VkDeviceAddress object_buffer_addr) { | 
		
	
		
			
				|  |  |  |  | VkResult draw_frame(VulkanContext* context, SceneContext* scene, uint32_t pipelines_count, GraphicsPipeline* pipelines, uint32_t* objects_counts, Object** objects, VkDeviceAddress object_buffer_addr) { | 
		
	
		
			
				|  |  |  |  |   struct ScenePC scene_constants = get_scene_constants(world_position, world_rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
	
		
			
				
					|  |  |  | @ -2765,23 +3016,49 @@ VkResult draw_frame(VulkanContext* context, SceneContext* scene, uint32_t materi | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_draw_scene(materials_count, pipelines, objects_counts, objects, context->current_frame, scene->descriptors, &scene_constants, context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent, object_buffer_addr); | 
		
	
		
			
				|  |  |  |  |   result = command_draw_scene(pipelines_count, pipelines, objects_counts, objects, context->current_frame, scene->descriptors, &scene_constants, context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent, object_buffer_addr, 0); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkResetCommandBuffer(context->offscreen_command_buffers[context->current_frame], 0); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_draw_scene(pipelines_count, pipelines, objects_counts, objects, context->current_frame, scene->descriptors, &scene_constants, context->offscreen_command_buffers[context->current_frame], context->g_renderpass, context->g_framebuffer, context->swapchain_extent, object_buffer_addr, 1); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; | 
		
	
		
			
				|  |  |  |  |   VkSubmitInfo submit_info = { | 
		
	
		
			
				|  |  |  |  |   VkSubmitInfo offscreen_submit_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | 
		
	
		
			
				|  |  |  |  |     .waitSemaphoreCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pWaitSemaphores = &context->image_available_semaphores[context->current_frame], | 
		
	
		
			
				|  |  |  |  |     .pWaitDstStageMask = wait_stages, | 
		
	
		
			
				|  |  |  |  |     .commandBufferCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pCommandBuffers = &context->offscreen_command_buffers[context->current_frame], | 
		
	
		
			
				|  |  |  |  |     .signalSemaphoreCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pSignalSemaphores = &context->offscreen_complete_semaphores[0], | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSubmitInfo submit_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | 
		
	
		
			
				|  |  |  |  |     .waitSemaphoreCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pWaitSemaphores = &context->offscreen_complete_semaphores[0], | 
		
	
		
			
				|  |  |  |  |     .pWaitDstStageMask = wait_stages, | 
		
	
		
			
				|  |  |  |  |     .commandBufferCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pCommandBuffers = &context->swapchain_command_buffers[context->current_frame], | 
		
	
		
			
				|  |  |  |  |     .signalSemaphoreCount = 1, | 
		
	
		
			
				|  |  |  |  |     .pSignalSemaphores = &context->render_finished_semaphores[context->current_frame], | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkQueueSubmit(context->queues.graphics, 1, &offscreen_submit_info, 0); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkQueueSubmit(context->queues.graphics, 1, &submit_info, context->in_flight_fences[context->current_frame]); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
	
		
			
				
					|  |  |  | @ -2918,7 +3195,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   GraphicsPipeline simple_mesh_pipeline = {0}; | 
		
	
		
			
				|  |  |  |  |   GraphicsPipeline texture_mesh_pipeline = {0}; | 
		
	
		
			
				|  |  |  |  |   VkResult result = create_simple_mesh_pipeline(context->device, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, &simple_mesh_pipeline); | 
		
	
		
			
				|  |  |  |  |   VkResult result = create_simple_mesh_pipeline(context->device, context->swapchain_extent, context->render_pass, context->g_renderpass, scene.descriptor_layout, context->max_frames_in_flight, &simple_mesh_pipeline); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create simple mesh material: %s\n", string_VkResult(result)); | 
		
	
		
			
				|  |  |  |  |     return; | 
		
	
	
		
			
				
					|  |  |  | @ -2930,7 +3207,7 @@ void main_loop(PlyMesh ply_mesh, GLFWwindow* window, VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  |     return; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = create_texture_mesh_pipeline(context->device, context->memories, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight, context->transfer_command_pool, context->queues.transfer, context->queues.graphics, context->extra_graphics_pool, context->queue_indices.transfer_family, context->queue_indices.graphics_index, &texture_mesh_pipeline); | 
		
	
		
			
				|  |  |  |  |   result = create_texture_mesh_pipeline(context->device, context->memories, context->swapchain_extent, context->render_pass, context->g_renderpass, scene.descriptor_layout, context->max_frames_in_flight, context->transfer_command_pool, context->queues.transfer, context->queues.graphics, context->extra_graphics_pool, context->queue_indices.transfer_family, context->queue_indices.graphics_index, &texture_mesh_pipeline); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create texture mesh material\n"); | 
		
	
		
			
				|  |  |  |  |     return; | 
		
	
	
		
			
				
					|  |  |  | 
 |