Made pipelines create a second pipeline for offscreen rener of g_buffers

main
noah metz 2024-01-13 23:50:39 -07:00
parent 87141577f9
commit bda7eae355
4 changed files with 335 additions and 49 deletions

1
env

@ -0,0 +1 @@
MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=1

@ -0,0 +1,4 @@
#version 450
void main() {
}

@ -0,0 +1,4 @@
#version 450
void main() {
}

@ -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,
};
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, &info, 0, &out->pipeline);
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;