![](/img/trans.png)
[英]Why I got white blinking while resizing resizing the images of the swapchain with VK_PRESENT_MODE_FIFO_KHR present mode?
[英]Vulkan validation errors states my images are in the wrong layout, but only the two first times I present images from the swapchain
我一直在按照本指南使用 Vulkan-Hpp 中的 raii 标头在 Vulkan 中设置一些简单的渲染。 我跳过了图形管道基础部分(渲染通道章节除外),只是为了看看我是否只能让渲染通道工作并呈现来自交换链的图像。
我现在可以将当前交换链图像清除为某种颜色并呈现它。 但是,对于我尝试呈现的前两帧,这失败了,之后它运行顺利,没有任何验证错误。 我完全不知道为什么会发生这种情况,所以我只想详细说明我所知道的和我尝试过的,希望有人可能在这里知道答案。
我在前两帧得到的错误如下:
Validation Error: [ VUID-VkPresentInfoKHR-pImageIndices-01296 ] Object 0: handle = 0x1f5d50ee1e0, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0xc7aabc16 | vkQueuePresentKHR(): pSwapchains[0] images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in VK_IMAGE_LAYOUT_UNDEFINED. The Vulkan spec states: Each element of pImageIndices must be the index of a presentable image acquired from the swapchain specified by the corresponding element of the pSwapchains array, and the presented image subresource must be in the VK_IMAGE_LAYOUT_PRESENT_SRC_KHR layout at the time the operation is executed on a VkDevice (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)VUID-VkPresentInfoKHR-pImageIndices-01296)
这使得前两帧或其他东西看起来可能存在同步问题。 由于我仍在使用 Vulkan 进行早期测试,因此我只是使用device.waitIdle()
而不是与信号量和栅栏正确同步。 我知道使用waitIdle
是一个缓慢的解决方案,但我认为它至少可以保持同步,所以我不确定这是否是一个同步问题。
我的交换链有 3 个图像,所以如果在第一轮通过图像呈现图像存在问题,那么我应该得到三个错误......
presentKHR
function 即使在前两帧也返回vk::Result::Success
。 我也尝试关闭验证层,当我这样做时,前两帧能够呈现,所以它可能是验证层中的错误?
我的一些初始化代码:
// After swapchain creation
auto images = m_swapchain.getImages();
for (auto& image : images) {
m_images.emplace(image, createImageView(image));
}
m_renderPass = createRenderPass();
m_frameBuffers.reserve(m_images.size());
for (auto& [image, imageView] : m_images) {
m_frameBuffers.push_back(createFrameBuffer(imageView));
}
auto [result, imageIndex] = m_swapchain.acquireNextImage(
std::numeric_limits<uint64_t>().max(),
*m_imageAvailableSemaphore
);
// I use a semaphore here because the Vulkan spec states that I must use a semaphore or fence here
m_imageIndex = imageIndex;
// Functions called above
vk::raii::ImageView Swapchain::createImageView(const vk::Image& image) const {
try {
return m_context.getDevice().createImageView(
vk::ImageViewCreateInfo{
.flags = {},
.image = image,
.viewType = vk::ImageViewType::e2D,
.format = m_surfaceFormat.format,
.components = vk::ComponentMapping{
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eIdentity
},
.subresourceRange = vk::ImageSubresourceRange{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
}
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
vk::raii::RenderPass Swapchain::createRenderPass() const {
auto attachments = std::array{
vk::AttachmentDescription{
.flags = {},
.format = m_surfaceFormat.format,
.samples = vk::SampleCountFlagBits::e1,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
.stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
.initialLayout = vk::ImageLayout::eUndefined,
.finalLayout = vk::ImageLayout::ePresentSrcKHR
}
};
auto attachmentReferences = std::array{
vk::AttachmentReference{
.attachment = 0,
.layout = vk::ImageLayout::eColorAttachmentOptimal
}
};
auto subpasses = std::array{
vk::SubpassDescription{
.flags = {},
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = 0,
.pInputAttachments = nullptr,
.colorAttachmentCount = static_cast<uint32_t>(attachmentReferences.size()),
.pColorAttachments = attachmentReferences.data(),
.pResolveAttachments = nullptr,
.pDepthStencilAttachment = nullptr,
.preserveAttachmentCount = 0,
.pPreserveAttachments = nullptr
}
};
try {
return m_context.getDevice().createRenderPass(
vk::RenderPassCreateInfo{
.flags = {},
.attachmentCount = static_cast<uint32_t>(attachments.size()),
.pAttachments = attachments.data(),
.subpassCount = static_cast<uint32_t>(subpasses.size()),
.pSubpasses = subpasses.data(),
.dependencyCount = 0,
.pDependencies = nullptr
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
vk::raii::Framebuffer Swapchain::createFrameBuffer(const vk::raii::ImageView& imageView) const {
try {
return m_context.getDevice().createFramebuffer(
vk::FramebufferCreateInfo{
.flags = {},
.renderPass = *m_renderPass,
.attachmentCount = 1,
.pAttachments = &*imageView,
.width = m_imageExtent.width,
.height = m_imageExtent.height,
.layers = 1
}
);
}
catch (const std::exception& e) {
// Error handling...
}
}
每帧执行的渲染代码:
// The actual render function called every frame
void Renderer::render() {
m_context->recordCommands(
[&]() {
m_swapchain->beginRenderPassCommand(0.125f, 0.125f, 0.125f);
m_swapchain->endRenderPassCommand();
}
);
m_context->submitRecording();
m_swapchain->swap();
}
void GraphicsContext::recordCommands(const Application::Recording& recording) {
m_device.waitIdle();
m_commandBuffer.reset();
m_commandBuffer.begin(
vk::CommandBufferBeginInfo{
.flags = {},
.pInheritanceInfo = {}
}
);
recording();
m_commandBuffer.end();
}
void Swapchain::beginRenderPassCommand(
float clearColorRed,
float clearColorGreen,
float clearColorBlue
) {
auto clearValues = std::array{
vk::ClearValue(
vk::ClearColorValue(
std::array{
clearColorRed,
clearColorGreen,
clearColorBlue,
1.0f
}
)
)
};
m_context.getCommandBuffer().beginRenderPass(
vk::RenderPassBeginInfo{
.renderPass = *m_renderPass,
.framebuffer = *m_frameBuffers[m_imageIndex],
.renderArea = vk::Rect2D{
.offset = vk::Offset2D{
.x = 0,
.y = 0
},
.extent = m_imageExtent
},
.clearValueCount = static_cast<uint32_t>(clearValues.size()),
.pClearValues = clearValues.data()
},
vk::SubpassContents::eInline
);
}
void Swapchain::endRenderPassCommand() {
m_context.getCommandBuffer().endRenderPass();
}
void GraphicsContext::submitRecording() {
m_device.waitIdle();
m_graphicsQueue.submit(
vk::SubmitInfo{
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.pWaitDstStageMask = nullptr,
.commandBufferCount = 1,
.pCommandBuffers = &*m_commandBuffer,
.signalSemaphoreCount = 0,
.pSignalSemaphores = nullptr
}
);
}
void Swapchain::swap() {
m_context.getDevice().waitIdle();
auto presentResult = m_context.getPresentQueue().presentKHR(
vk::PresentInfoKHR{
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.swapchainCount = 1,
.pSwapchains = &*m_swapchain,
.pImageIndices = &m_imageIndex,
.pResults = nullptr
}
);
m_context.getDevice().waitIdle();
auto [result, imageIndex] = m_swapchain.acquireNextImage(
std::numeric_limits<uint64_t>().max(),
*m_imageAvailableSemaphore
);
m_imageIndex = imageIndex;
}
在特定情况或显式同步之外,GPU 上的操作以任意顺序执行。
您的图形提交和队列演示之间没有同步。 因此,无论您何时发布它们,它们都可以按照实现所需的任何顺序执行。
但是,由于图形操作作用于演示操作使用的 object,因此存在事实上的依赖关系。 图形操作必须先行动。 但是您没有实际的同步来强制执行这种依赖关系。
因此验证错误。 您需要确保队列呈现发生在渲染操作之后。
我现在已经确认此问题是由验证层中的错误引起的。 这是 Github 上的问题: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4422
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.