You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vulkan第二个渲染通道附件被误判为输入附件问题求助

问题描述

我配置了两个各包含1个子通道的Render Pass:

  • 第一个Render Pass包含depthAttachment、colorAttachment、colorResolveAttachment三个附件;
  • 第二个Render Pass仅包含finalColorAttachment,其片段着色器会读取第一个Render Pass的colorResolveAttachment。

创建第二个Render Pass时,Vulkan验证层输出警告,称pSubpasses[0].pColorAttachments[0](即colorAttachmentPP)同时是输入附件,其布局VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL不符合要求,但该附件实际并非输入附件,我无法理解报错原因。

警告信息

vkCreateRenderPass(): pSubpasses[0].pColorAttachments[0] is also an input attachment so the layout (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) must not be VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL or VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR.
The Vulkan spec states: Each attachment must follow the image layout requirements specified for its attachment type

相关代码

// First render pass -------------------------

// Final color attachment
VkAttachmentDescription colorAttachmentResolve{};
colorAttachmentResolve.format = swapChainImageFormat;
colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;  

VkAttachmentReference colorAttachmentResolveRef{};
colorAttachmentResolveRef.attachment = 0;
colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

// Depth attachment
VkAttachmentDescription depthAttachment{};
depthAttachment.format = findDepthFormat(); 
depthAttachment.samples = msaaSamples;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;  
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

VkAttachmentReference depthAttachmentRef{};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

// Color attachment
VkAttachmentDescription colorAttachment{};
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = msaaSamples;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;  
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;  
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 2;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

std::vector<VkAttachmentDescription> attachments  = std::vector<VkAttachmentDescription>{ colorAttachmentResolve, depthAttachment, colorAttachment };

// Subpass 1:

VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
subpass.pResolveAttachments = &colorAttachmentResolveRef;
subpass.inputAttachmentCount;
subpass.pInputAttachments;
subpass.preserveAttachmentCount;
subpass.pPreserveAttachments;

VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;   
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

// Create Render Pass 1:
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;   
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency; 

vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass[0]);

// Second render pass (Post processing) -------------------------

// Final color attachment (from previous render pass)
colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

// Final color Post-Processed attachment
VkAttachmentDescription colorAttachmentPP{};
colorAttachmentPP.format = swapChainImageFormat;
colorAttachmentPP.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentPP.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentPP.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentPP.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentPP.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentPP.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachmentPP.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

VkAttachmentReference colorAttachmentPPRef{};
colorAttachmentPPRef.attachment = 0;
colorAttachmentPPRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

// Subpass 2
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentPPRef;
subpass.pDepthStencilAttachment = nullptr;
subpass.pResolveAttachments = nullptr;
VkAttachmentReference inputAttachments[1] = { colorAttachmentResolveRef };
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = inputAttachments;   // <<< Set input attachments
subpass.preserveAttachmentCount;
subpass.pPreserveAttachments;

dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
dependency.srcAccessMask = 0;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;

// Create Render Pass 2:
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(1);
renderPassInfo.pAttachments = &colorAttachmentPP;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;   
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency; 

vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass[1]);
解决方案

问题出在第二个Render Pass的附件引用逻辑:你给子通道指定的输入附件colorAttachmentResolveRef,其attachment值为0,但第二个Render Pass只声明了1个附件(colorAttachmentPP),索引正好是0。Vulkan会把这个输入附件解析为引用当前Render Pass的第0个附件,也就是colorAttachmentPP,导致它同时被标记为颜色附件和输入附件,触发验证层警告。

修复步骤如下:

  1. 将第一个Render Pass的colorAttachmentResolve加入第二个Render Pass的附件列表,调整其布局参数(初始布局对应第一个Render Pass的最终布局,最终布局设为着色器可读);
  2. 修改输入附件的attachment值为1(因为colorAttachmentPP是第0个附件,colorAttachmentResolve是第1个);
  3. 不要复用第一个Render Pass的subpass和dependency变量,避免残留旧数据;
  4. 修正依赖关系,确保第一个Render Pass的输出能被第二个Render Pass的片段着色器正确读取。

修复后的第二个Render Pass代码示例:

// Second render pass (Post processing) -------------------------

// 复制并调整第一个Render Pass的colorAttachmentResolve描述
VkAttachmentDescription colorAttachmentResolvePP = colorAttachmentResolve;
colorAttachmentResolvePP.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // 对应第一个Render Pass的finalLayout
colorAttachmentResolvePP.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

VkAttachmentReference colorAttachmentResolveRefPP{};
colorAttachmentResolveRefPP.attachment = 1; // 现在是第二个附件
colorAttachmentResolveRefPP.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

// Final color Post-Processed attachment
VkAttachmentDescription colorAttachmentPP{};
colorAttachmentPP.format = swapChainImageFormat;
colorAttachmentPP.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentPP.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentPP.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentPP.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentPP.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentPP.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachmentPP.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

VkAttachmentReference colorAttachmentPPRef{};
colorAttachmentPPRef.attachment = 0;
colorAttachmentPPRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

// 新建子通道描述,不复用旧变量
VkSubpassDescription subpass2{};
subpass2.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass2.colorAttachmentCount = 1;
subpass2.pColorAttachments = &colorAttachmentPPRef;
subpass2.pDepthStencilAttachment = nullptr;
subpass2.pResolveAttachments = nullptr;
VkAttachmentReference inputAttachments[1] = { colorAttachmentResolveRefPP };
subpass2.inputAttachmentCount = 1;
subpass2.pInputAttachments = inputAttachments;
subpass2.preserveAttachmentCount = 0;
subpass2.pPreserveAttachments = nullptr;

// 修正依赖关系,确保读取权限正确
VkSubpassDependency dependency2{};
dependency2.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency2.dstSubpass = 0;
dependency2.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency2.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependency2.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency2.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependency2.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

// 附件列表包含两个附件
std::vector<VkAttachmentDescription> attachments2 = { colorAttachmentPP, colorAttachmentResolvePP };

// 创建Render Pass 2
VkRenderPassCreateInfo renderPassInfo2{};
renderPassInfo2.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo2.attachmentCount = static_cast<uint32_t>(attachments2.size());
renderPassInfo2.pAttachments = attachments2.data();
renderPassInfo2.subpassCount = 1;
renderPassInfo2.pSubpasses = &subpass2;   
renderPassInfo2.dependencyCount = 1;
renderPassInfo2.pDependencies = &dependency2; 

vkCreateRenderPass(device, &renderPassInfo2, nullptr, &renderPass[1]);

内容的提问来源于stack exchange,提问作者Anselmo GPP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 22:25:22