脱离时的 ImGui Vulkan 验证层错误
Posted
技术标签:
【中文标题】脱离时的 ImGui Vulkan 验证层错误【英文标题】:ImGui Vulkan Validation Layer Error when undocking 【发布时间】:2020-04-15 14:54:35 【问题描述】:将 ImGui for Vulkan 与 imgui_impl_vulkan.cpp
、imgui_impl_glfw.cpp
及其各自的标头一起使用时,我没有收到验证层错误,但是当我使用 docking
分支并取消停靠时,或者换句话说,当我将 ImGui 窗口从Vulkan 主窗口(您可能猜到是用 GLFW 创建的),我收到此错误:
validation layer: vkCmdDrawIndexed(): RenderPasses incompatible between active render pass w/ VkRenderPass 0x243b910000000054[] and pipeline state object w/ VkRenderPass 0x731f0f000000000a[] Attachment 0 is not compatible with 0: They have different formats.. The Vulkan spec states: The current render pass must be compatible with the renderPass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS.
我的命令缓冲区是这样创建的:
void createCommandBuffers()
commandBuffers.resize(swapChainFramebuffers.size());
VkCommandBufferAllocateInfo allocInfo = ;
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS)
throw std::runtime_error("failed to allocate command buffers!");
for (size_t i = 0; i < commandBuffers.size(); i++)
VkCommandBufferBeginInfo beginInfo = ;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS)
throw std::runtime_error("failed to begin recording command buffer!");
VkRenderPassBeginInfo renderPassInfo = ;
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = renderPass;
renderPassInfo.framebuffer = swapChainFramebuffers[i];
renderPassInfo.renderArea.offset = 0, 0 ;
renderPassInfo.renderArea.extent = swapChainExtent;
VkClearValue clearColor = 0.0f, 0.0f, 0.0f, 1.0f ;
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor;
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkBuffer vertexBuffers[] = vertexBuffer ;
VkDeviceSize offsets[] = 0 ;
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
// Bind Dear Imgui pipeline to draw UI elements inside UI box
if (isImGuiWindowCreated)
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffers[i]);
vkCmdEndRenderPass(commandBuffers[i]);
if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS)
throw std::runtime_error("failed to record command buffer!");
isImGuiWindowCreated = false;
我这样初始化 ImGui:
void initImGui(float width, float height)
QueueFamilyIndices Indices = findQueueFamilies(physicalDevice);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
//io.Fonts->AddFontFromFileTTF("../../Assets/Fonts/Roboto-Medium.ttf", 16.0f);
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
io.DisplaySize = ImVec2(width, height);
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForVulkan(window, true);
ImGui_ImplVulkan_InitInfo init_info = ;
init_info.Instance = instance;
init_info.PhysicalDevice = physicalDevice;
init_info.Device = device;
init_info.QueueFamily = Indices.graphicsFamily.value();
init_info.Queue = presentQueue;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.DescriptorPool = descriptorPool;
init_info.Allocator = NULL;
init_info.MinImageCount = 2;
init_info.ImageCount = static_cast<uint32_t>(swapChainImages.size());
init_info.CheckVkResultFn = NULL;
ImGui_ImplVulkan_Init(&init_info, renderPass);
// Setup Dear ImGui style
ImGui::StyleColorsDark();
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
endSingleTimeCommands(commandBuffer);
ImGui_ImplVulkan_DestroyFontUploadObjects();
这是beginSingleTimeCommands()
的定义
VkCommandBuffer beginSingleTimeCommands()
VkCommandBufferAllocateInfo allocInfo = ;
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo = ;
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
return commandBuffer;
我不知道如何解决这个问题,因为我已经尝试为 ImGui 和主应用程序创建不同的 RenderPasses
,我还尝试创建不同的 CommandBuffers
,但这也没有解决问题。有什么建议吗?
编辑:这是我创建RenderPass
的方法:
void createRenderPass()
VkAttachmentDescription colorAttachment = ;
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
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_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = ;
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = ;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkSubpassDependency dependency = ;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo renderPassInfo = ;
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS)
throw std::runtime_error("failed to create render pass!");
还有GraphicsPipeline
,我对ImGui和主窗口使用相同的RenderPass
:renderPass
void createGraphicsPipeline()
auto vertShaderCode = readFile("Shaders\\vert.spv");
auto fragShaderCode = readFile("Shaders\\frag.spv");
VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
VkPipelineShaderStageCreateInfo vertShaderStageInfo = ;
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo fragShaderStageInfo = ;
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo shaderStages[] = vertShaderStageInfo, fragShaderStageInfo ;
VkPipelineVertexInputStateCreateInfo vertexInputInfo = ;
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Vertex::getBindingDescription();
auto attributeDescriptions = Vertex::getAttributeDescriptions();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
VkPipelineInputAssemblyStateCreateInfo inputAssembly = ;
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;
VkViewport viewport = ;
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)swapChainExtent.width;
viewport.height = (float)swapChainExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor = ;
scissor.offset = 0, 0 ;
scissor.extent = swapChainExtent;
VkPipelineViewportStateCreateInfo viewportState = ;
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer = ;
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo multisampling = ;
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState colorBlendAttachment = ;
// Original.
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_SUBTRACT;
// For ImGui.
/*colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;*/
VkPipelineColorBlendStateCreateInfo colorBlending = ;
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
VkPipelineLayoutCreateInfo pipelineLayoutInfo = ;
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
throw std::runtime_error("failed to create pipeline layout!");
VkGraphicsPipelineCreateInfo pipelineInfo = ;
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS)
throw std::runtime_error("failed to create graphics pipeline!");
vkDestroyShaderModule(device, fragShaderModule, nullptr);
vkDestroyShaderModule(device, vertShaderModule, nullptr);
【问题讨论】:
错误似乎很明显。那么,您在创建graphicsPipeline
时指定了什么\哪个渲染通道?该错误声称它与您用于vkCmdBeginRP
的渲染通道不同,而且它也不兼容。
@krOoze 我添加了一个编辑,展示了我如何创建RenderPass
。
是的,但是你如何创建管道,你使用哪个渲染通道?
PS:还要检查哪个 vkCmdDrawIndexed
失败。你的,还是imgui插入的那个?如果可行,甚至可以尝试不使用 imgui。
嗯,最简单的调试方法可能是启用VK_LAYER_LUNARG_api_dump
,然后查看错误中引用的对象来自哪里。如果你说你只创建了一个渲染通道,但错误说你有两个,这是一个奇怪的差异。
【参考方案1】:
这个问题似乎只是在您使用 ImGUI 中的多视图/停靠功能时发生。
当您启用多视图/停靠功能时,ImGUI 会自己创建自己的渲染通道、管道等来处理所有 ImGUI 外部窗口,所以当您将 ImGUI 窗口拖到主窗口之外时,问题就会出现。正如您在ImGUI vulkan implementation 中看到的那样,在为内部渲染通道选择表面格式时,它并不接受所有格式。我不知道具体原因,但内部渲染通道接受的可能格式是这部分代码中的格式。所以基本上,使用 VK_COLORSPACE_SRGB_NONLINEAR_KHR 颜色空间作为surfaceFormat 的另一对匹配项,它返回该格式可用的第一个选项。我解决问题的方法是选择表面的格式,就像它在 ImGUI 中实现的一样,或者换句话说,我的表面为我的表面返回 VK_FORMAT_B8G8R8A8_UNORM 标志。据说this PR 解决了这个问题(并且在 cmets 中,这家伙提到了这个问题)。
ImGui 的格式如下:
const VkFormat requestSurfaceImageFormat[] = VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM ;
【讨论】:
我将其标记为答案,因为自从我询问以来,这几乎已经死了,并且确实对修复的原因和时间提供了一些见解。以上是关于脱离时的 ImGui Vulkan 验证层错误的主要内容,如果未能解决你的问题,请参考以下文章
(图形学笔记 - Vulkan) 1.1.3 - Validation layers(建立vulkan的验证层)