在Vulkan中并排绘制颜色和深度图像

问题描述

我目前正在学习Vulkan,并且试图编写一个可以并排绘制场景和场景深度缓冲区的应用程序。

起初,我考虑过使用单个子通道渲染范围为Object.keys(selectedFilters).forEach(k=> { // properties[k] if exists -> will give you required data }) 的框架,然后使用(width/2) x height两次将生成的框架及其深度图像复制到交换链,但是我很快发现了交换链图片不一定支持vkCmdBlitimage

我当前的策略是在单个渲染过程中使用两个子过程。 第一个子通道使用视口将结果帧渲染到屏幕的左侧,第二个子通道将第一个子通道的深度附件作为输入附件,并将其渲染到屏幕的右侧。

我的第一个问题是,该策略似乎非常浪费,因为我必须使用深度为VK_IMAEG_USAGE_TRANSFER_DST_BIT(而不是width x height)的深度图像,因此如果由您自己决定,您将如何实施这个应用程序?

我的第二个问题是深度图像根本没有显示

颜色附件在左边显示得很好(如果在视口之间切换,它也可以在右边显示得很好),但是在右边(应该是深度图像),我得到了(width/2) x height-彩色的屏幕。 深度缓冲区本身工作正常(屏幕上的对象以正确的顺序呈现),并且看起来片段着色器工作正常(我尝试在不使用输入附件的情况下编写不同的颜色,并且工作正常)。>

我用尽了所有可能出现问题的想法,我认为这与subpass依赖关系有关,因为看起来深度值未写入缓冲区(或在写入之前已被访问)。

相关代码

clearValue

我试图尽可能地削减代码,因此/***************/ /* Render pass */ /***************/ { const VkAttachmentDescription attachments[] = { // Color attachment { .flags = 0,.format = swapchain->format,.samples = VK_SAMPLE_COUNT_1_BIT,.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,.storeOp = VK_ATTACHMENT_STORE_OP_STORE,//.stencilLoadOp = <uninitialized>,//.stencilstoreOp = <uninitialized>,.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,},// Depth attachment / Input attachment { .flags = 0,.format = VK_FORMAT_D32_SFLOAT,.samples = VK_SAMPLE_COUNT_1_BIT,.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,.stencilstoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,}; const VkSubpassDescription subpasses[] = { // First subpass - Render "regular" frame { .flags = 0,.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,.inputAttachmentCount = 0,//.pInputAttachments = <uninitialized>,.colorAttachmentCount = 1,.pColorAttachments = (VkAttachmentReference[]) { { 0,VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL },.pResolveAttachments = NULL,.pDepthStencilAttachment = (VkAttachmentReference[]) { { 1,VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL },.preserveAttachmentCount = 0,//.pPreserveAttachments = <uninitialized>,// Second subpass - Render depth image { .flags = 0,.inputAttachmentCount = 1,.pInputAttachments = (VkAttachmentReference[]) { { 1,VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL },.pDepthStencilAttachment = NULL,}; const VkSubpassDependency dependencies[] = { { .srcSubpass = VK_SUBPASS_EXTERNAL,.dstSubpass = 0,.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,.srcAccessMask = 0,.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,{ .srcSubpass = 0,.dstSubpass = 1,.srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,}; const VkRenderPassCreateInfo create_info = { .flags = 0,.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),.pAttachments = attachments,.subpassCount = sizeof(subpasses) / sizeof(subpasses[0]),.pSubpasses = subpasses,.dependencyCount = sizeof(dependencies) / sizeof(dependencies[0]),.pDependencies = dependencies,}; vulkan_result = vkCreateRenderPass(device,&create_info,NULL,&swapchain->renderPass); assert(vulkan_result == VK_SUCCESS); } /**************************/ /* Descriptor set layouts */ /**************************/ { // MVP matrices VkDescriptorSetLayoutCreateInfo create_info = { .flags = 0,.bindingCount = 1,.pBindings = (VkDescriptorSetLayoutBinding[]) { { .binding = 0,.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,.descriptorCount = 1,.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,.pImmutableSamplers = NULL,} },}; vulkan_result = vkCreateDescriptorSetLayout(device,&renderer->setLayouts.color); assert(vulkan_result == VK_SUCCESS); // Input attachment for depth image create_info.pBindings = (VkDescriptorSetLayoutBinding[]) { { .binding = 0,.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,} }; vulkan_result = vkCreateDescriptorSetLayout(device,&renderer->setLayouts.depth); assert(vulkan_result == VK_SUCCESS); } /********************/ /* Pipeline layouts */ /********************/ { VkPipelineLayoutCreateInfo create_info = { .flags = 0,.setLayoutCount = 1,.pSetLayouts = &renderer->setLayouts.color,.pushConstantRangeCount = 0,//.pPushConstantRanges = <uninitialized>,}; vulkan_result = vkCreatePipelineLayout(device,&renderer->pipelineLayouts.color); assert(vulkan_result == VK_SUCCESS); create_info.pSetLayouts = &renderer->setLayouts.depth; vulkan_result = vkCreatePipelineLayout(device,&renderer->pipelineLayouts.depth); assert(vulkan_result == VK_SUCCESS); } /*************/ /* Pipelines */ /*************/ { size_t code_size; uint32_t *code; code = read_file("shaders/color_vert.spv",&code_size); VkShaderModuleCreateInfo shader_module_create_info = { .flags = 0,.codeSize = code_size,.pCode = code,}; VkShaderModule vertex_module; vulkan_result = vkCreateShaderModule(device,&shader_module_create_info,&vertex_module); free(code); assert(vulkan_result == VK_SUCCESS); code = read_file("shaders/color_frag.spv",&code_size); if (code == NULL) { vkDestroyShaderModule(device,vertex_module,NULL); } shader_module_create_info.codeSize = code_size; shader_module_create_info.pCode = code; VkShaderModule fragment_module; vulkan_result = vkCreateShaderModule(device,&fragment_module); assert(vulkan_result == VK_SUCCESS); free(code); VkPipelineshaderStageCreateInfo stages[] = { { .flags = 0,.stage = VK_SHADER_STAGE_VERTEX_BIT,.module = vertex_module,.pName = "main",.pSpecializationInfo = NULL,{ .flags = 0,.stage = VK_SHADER_STAGE_FRAGMENT_BIT,.module = fragment_module,} }; const VkVertexInputBindingDescription vertex_binding_description = { .binding = 0,.stride = sizeof(struct Vertex),.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,}; const VkVertexInputAttributeDescription vertex_attribute_description[] = { // Position { .location = 0,.binding = 0,.format = VK_FORMAT_R32G32B32_SFLOAT,.offset = offsetof(struct Vertex,position),// Color { .location = 1,color),} }; VkPipelineVertexInputStateCreateInfo vertex_input_state = { .flags = 0,.vertexBindingDescriptionCount = 1,.pVertexBindingDescriptions = &vertex_binding_description,.vertexAttributeDescriptionCount = sizeof(vertex_attribute_description) / sizeof(vertex_attribute_description[0]),.pVertexAttributeDescriptions = vertex_attribute_description,}; VkPipelineInputAssemblyStateCreateInfo input_assembly_state = { .flags = 0,.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,.primitiveRestartEnable = VK_FALSE,}; VkPipelineViewportStateCreateInfo viewport_state = { .flags = 0,.viewportCount = 1,.pViewports = (VkViewport[]) { { .x = 0.0f,.y = 0.0f,.width = (float) extent.width / 2,.height = (float) extent.height,.minDepth = 0.0f,.maxDepth = 1.0f,.scissorCount = 1,.pScissors = (VkRect2D[]) { { .offset = { 0,0 },.extent = { extent.width / 2,extent.height },}; VkPipelineRasterizationStateCreateInfo rasterization_state = { .flags = 0,.depthClampEnable = VK_FALSE,.rasterizerdiscardEnable = VK_FALSE,.polygonMode = VK_polyGON_MODE_FILL,.cullMode = VK_CULL_MODE_BACK_BIT,.frontFace = VK_FRONT_FACE_COUNTER_Clockwise,.depthBiasEnable = VK_FALSE,//.depthBiasConstantFactor =,//.depthBiasClamp =,//.depthBiasSlopeFactor =,.linewidth = 1.0f,}; const VkPipelineMultisampleStateCreateInfo multisample_state = { .flags = 0,.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,.sampleShadingEnable = VK_FALSE,.minSampleShading = 1.0f,.pSampleMask = NULL,.alphaToCoverageEnable = VK_FALSE,.alphaToOneEnable = VK_FALSE,}; VkPipelineDepthstencilstateCreateInfo depth_stencil_state = { .flags = 0,.depthTestEnable = VK_TRUE,.depthWriteEnable = VK_TRUE,.depthCompareOp = VK_COMPARE_OP_LESS,.depthBoundsTestEnable = VK_FALSE,.stencilTestEnable = VK_FALSE,//.front = <uninitialized>,//.back = <uninitialized>,//.minDepthBounds = <uninitialized>,//.maxDepthBounds = <uninitialized>,}; const VkPipelineColorBlendAttachmentState attachments[] = { { .blendEnable = VK_FALSE,//.srcColorBlendFactor = <uninitialized>,//.dstColorBlendFactor = <uninitialized>,//.colorBlendOp = <uninitialized>,//.srcAlphaBlendFactor = <uninitialized>,//.dstAlphaBlendFactor = <uninitialized>,//.alphaBlendOp = <uninitialized>,.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,} }; const VkPipelineColorBlendStateCreateInfo color_blend_state = { .flags = 0,.logicopEnable = VK_FALSE,//.logicop = <uninitialized>,.attachmentCount = sizeof(attachments) / sizeof(attachments[0]),.pAttachments = attachments,//.blendConstants[4] = <uninitialized>,}; VkGraphicsPipelineCreateInfo create_info = { .flags = 0,.stageCount = sizeof(stages) / sizeof(stages[0]),.pStages = stages,.pVertexInputState = &vertex_input_state,.pInputAssemblyState = &input_assembly_state,.ptessellationState = NULL,.pViewportState = &viewport_state,.pRasterizationState = &rasterization_state,.pMultisampleState = &multisample_state,.pDepthstencilstate = &depth_stencil_state,.pColorBlendState = &color_blend_state,.pDynamicState = NULL,.layout = renderer->pipelineLayouts.color,.renderPass = render_pass,.subpass = 0,//.basePipelineHandle =,//.basePipelineIndex =,}; vulkan_result = vkCreateGraphicsPipelines(device,1,&renderer->pipelines.color); assert(vulkan_result == VK_SUCCESS); vkDestroyShaderModule(device,fragment_module,NULL); vkDestroyShaderModule(device,NULL); code = read_file("shaders/depth_vert.spv",&code_size); assert(code != NULL); shader_module_create_info.codeSize = code_size; shader_module_create_info.pCode = code; vulkan_result = vkCreateShaderModule(device,&vertex_module); assert(vulkan_result == VK_SUCCESS); free(code); code = read_file("shaders/depth_frag.spv",&fragment_module); assert(vulkan_result == VK_SUCCESS); free(code); stages[0].module = vertex_module; stages[1].module = fragment_module; vertex_input_state.vertexBindingDescriptionCount = 0; vertex_input_state.vertexAttributeDescriptionCount = 0; viewport_state.pViewports = (VkViewport[]) { { .x = (float) extent.width / 2,}; viewport_state.pScissors = (VkRect2D[]) { { .offset = { extent.width / 2,} }; rasterization_state.cullMode = VK_CULL_MODE_NONE; create_info.pDepthstencilstate = NULL; create_info.layout = renderer->pipelineLayouts.depth; create_info.subpass = 1; vulkan_result = vkCreateGraphicsPipelines(device,&renderer->pipelines.depth); vkDestroyShaderModule(device,NULL); assert(vulkan_result == VK_SUCCESS); } /****************/ /* Depth images */ /****************/ { // renderer->depthImages is a wrapper around VkImage and VkImageView // renderer->depthImages.images is a VkImage array with image_count elements // renderer->depthImages.imagesViews are the views of the respective images wn_images_init(renderer->device /* also includes physical device for memory allocation */,image_count,VK_FORMAT_D32_SFLOAT,VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,extent,&renderer->depthImages); } /****************/ /* Framebuffers */ /****************/ { renderer->framebuffers = calloc(sizeof(VkFramebuffer),renderer->imageCount); assert(renderer->framebuffers != NULL); if (renderer->framebuffers == NULL) { return VK_ERROR_OUT_OF_HOST_MEMORY; } for (uint32_t i = 0; i < renderer->imageCount; i++) { const VkImageView attachments[] = { render_targets[i],renderer->depthImages.imagesViews[i],}; const VkFramebufferCreateInfo create_info = { .flags = 0,.renderPass = render_pass,.pAttachments = attachments,.width = extent.width,.height = extent.height,.layers = 1,}; vulkan_result = vkCreateFramebuffer(device,renderer->framebuffers + i); assert(vulkan_result == VK_SUCCESS); } } /******************/ /* Uniform buffers */ /******************/ { wn_buffer_init(renderer->device,sizeof(struct UniformBufferObject) * renderer->imageCount,VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,&renderer->uniformBuffer.buffers); } /*******************/ /* Descriptor pool */ /*******************/ { const VkDescriptorPoolSize pool_sizes[] = { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,renderer->imageCount },{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,}; const VkDescriptorPoolCreateInfo create_info = { .flags = 0,.maxSets = renderer->imageCount * 2,.poolSizeCount = sizeof(pool_sizes) / sizeof(pool_sizes[0]),.pPoolSizes = pool_sizes,}; assert(vkCreateDescriptorPool(device,&renderer->descriptorPool) == VK_SUCCESS); } /*******************/ /* Descriptor sets */ /*******************/ { VkDescriptorSetLayout layouts[renderer->imageCount]; for (uint32_t i = 0; i < renderer->imageCount; i++) { layouts[i] = renderer->setLayouts.color; } VkDescriptorSetAllocateInfo allocate_info = { .descriptorPool = renderer->descriptorPool,.descriptorSetCount = renderer->imageCount,.pSetLayouts = layouts,}; renderer->sets.color = calloc(renderer->imageCount,sizeof(VkDescriptorSet)); assert(renderer->sets.color != NULL); vulkan_result = vkAllocateDescriptorSets(device,&allocate_info,renderer->sets.color); assert(vulkan_result == VK_SUCCESS); for (uint32_t i = 0; i < renderer->imageCount; i++) { layouts[i] = renderer->setLayouts.depth; } renderer->sets.depth = calloc(renderer->imageCount,sizeof(VkDescriptorSet)); assert(renderer->sets.depth != NULL); vulkan_result = vkAllocateDescriptorSets(device,renderer->sets.depth); assert(vulkan_result == VK_SUCCESS); for (uint32_t i = 0; i < renderer->imageCount; i++) { const VkDescriptorBufferInfo buffer_info = { .buffer = renderer->uniformBuffer.buffers.buffer,.offset = sizeof(struct UniformBufferObject) * i,.range = sizeof(struct UniformBufferObject),}; const VkDescriptorImageInfo image_info = { .sampler = VK_NULL_HANDLE,.imageView = renderer->depthImages.imagesViews[i],.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,}; const VkWriteDescriptorSet writes[] = { { .dstSet = renderer->sets.color[i],.dstBinding = 0,//.dstArrayElement = <uninitialized>,//.pImageInfo = <uninitialized>,.pBufferInfo = &buffer_info,//.pTexelBufferView = <uninitialized>,{ .dstSet = renderer->sets.depth[i],.pImageInfo = &image_info,//.pBufferInfo = <uninitialized>,}; vkUpdateDescriptorSets(device,sizeof(writes) / sizeof(writes[0]),writes,NULL); } } /*******************/ /* Command buffers */ /*******************/ { renderer->commandBuffers = calloc(renderer->imageCount,sizeof(VkCommandBuffer)); if (renderer->commandBuffers == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; const VkCommandBufferAllocateInfo allocate_info = { .commandPool = renderer->graphicsCommandPool,.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,.commandBufferCount = renderer->imageCount,}; vkAllocateCommandBuffers(device,renderer->commandBuffers); const VkCommandBufferBeginInfo begin_info = { .flags = 0 //.pInheritanceInfo = <uninitialized>,}; for (uint32_t i = 0; i < renderer->imageCount; i++) { vkBeginCommandBuffer(renderer->commandBuffers[i],&begin_info); const VkRenderPassBeginInfo render_pass_begin_info = { .renderPass = render_pass,.framebuffer = renderer->framebuffers[i],.renderArea = { .offset = { 0,.extent = { extent.width,.clearValueCount = 2,.pClearValues = (VkClearValue[]) { { { { 0.2f,0.2f,1.0f } } },// Grey background { { { 1.0f,/*<uninitialized>*/ } } },}; vkCmdBeginRenderPass(renderer->commandBuffers[i],&render_pass_begin_info,VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(renderer->commandBuffers[i],VK_PIPELINE_BIND_POINT_GRAPHICS,renderer->pipelines.color); // Vertex and index buffers are in one VkBuffer. First the vertices and then the indices vkCmdBindVertexBuffers(renderer->commandBuffers[i],&renderer->vertexIndexBuffer.buffer,(VkDeviceSize[]) { 0 }); vkCmdBindindexBuffer(renderer->commandBuffers[i],renderer->vertexIndexBuffer.buffer,sizeof(vertices),VK_INDEX_TYPE_UINT16); vkCmdBindDescriptorSets(renderer->commandBuffers[i],renderer->pipelineLayouts.color,renderer->sets.color + i,NULL); vkCmdDrawIndexed(renderer->commandBuffers[i],sizeof(indices) / sizeof(indices[0]),0); vkCmdNextSubpass(renderer->commandBuffers[i],renderer->pipelines.depth); vkCmdBindDescriptorSets(renderer->commandBuffers[i],renderer->pipelineLayouts.depth,renderer->sets.depth + i,NULL); vkCmdDraw(renderer->commandBuffers[i],3,0); vkCmdEndRenderPass(renderer->commandBuffers[i]); vkEndCommandBuffer(renderer->commandBuffers[i]); } } sType应该都被认为是正确的。

depth_vert.spv:

pNext

depth_frag.spv:

#version 450

void main()
{
    gl_Position = vec4(vec2((gl_VertexIndex << 1) & 2,gl_VertexIndex & 2) * 2.0f - 1.0f,0.0f,1.0f);
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)