I'm running into an access violation on this piece of Vulkan API.
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.billboard);
The error is:
Exception thrown at 0x00007FFB8BEDB276 (amdvlk64.dll) in 3Dfunctionvisualizer.exe: 0xC0000005: Access violation reading location 0x000000000000004C.
All other relevant code, as far as I can tell:
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
VkResult err = vkCreatePipelineCache(device, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
vkTools::initializers::pipelineInputAssemblyStateCreateInfo(
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
0,
VK_FALSE);
VkPipelineRasterizationStateCreateInfo rasterizationState =
vkTools::initializers::pipelineRasterizationStateCreateInfo(
VK_POLYGON_MODE_FILL,
VK_CULL_MODE_BACK_BIT,
VK_FRONT_FACE_CLOCKWISE,
0);
VkPipelineColorBlendAttachmentState blendAttachmentState =
vkTools::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_FALSE);
VkPipelineColorBlendStateCreateInfo colorBlendState =
vkTools::initializers::pipelineColorBlendStateCreateInfo(
1,
&blendAttachmentState);
VkPipelineDepthStencilStateCreateInfo depthStencilState =
vkTools::initializers::pipelineDepthStencilStateCreateInfo(
VK_TRUE,
VK_TRUE,
VK_COMPARE_OP_LESS_OR_EQUAL);
VkPipelineViewportStateCreateInfo viewportState =
vkTools::initializers::pipelineViewportStateCreateInfo(1, 1, 0);
VkPipelineMultisampleStateCreateInfo multisampleState =
vkTools::initializers::pipelineMultisampleStateCreateInfo(
VK_SAMPLE_COUNT_1_BIT,
0);
std::vector<VkDynamicState> dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_LINE_WIDTH
};
VkPipelineDynamicStateCreateInfo dynamicState =
vkTools::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(),
dynamicStateEnables.size(),
0);
std::array<VkPipelineShaderStageCreateInfo, 3> shaderStages;
shaderStages[0] = loadShader("./../data/shaders/3DVisualizer/billboard.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader("./../data/shaders/3DVisualizer/billboard.geom.spv", VK_SHADER_STAGE_GEOMETRY_BIT);
shaderStages[2] = loadShader("./../data/shaders/3DVisualizer/billboard.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
vkTools::initializers::pipelineCreateInfo(
pipelineLayout,
renderPass,
0);
pipelineCreateInfo.pVertexInputState = &vertices.billboard.inputState;
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
pipelineCreateInfo.pRasterizationState = &rasterizationState;
pipelineCreateInfo.pColorBlendState = &colorBlendState;
pipelineCreateInfo.pMultisampleState = &multisampleState;
pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = 3;
pipelineCreateInfo.pStages = shaderStages.data();
pipelineCreateInfo.renderPass = renderPass;
The device and pipelineCache are both set by the superclass, which was written by Sascha Willems and works for all of the examples he has created, so I don't expect the problem would be there. However, that really only leaves pipelineCreateInfo or pipelines.billboard as the potential source of the error.
Both of those are dealt with in the (almost exact) same way as the examples by Sascha in his examples, so I'm at a loss here.
EDIT: I found the problem. I had failed to specify the binding point for the sampler in my shader.
Related
I have loosely been following this guide to setup some simple rendering in Vulkan using the raii headers in Vulkan-Hpp. I have skipped the Graphics Pipeline Basics section (except for the render pass chapter) just to see if I'm able to only get the render pass working and presenting images from the swapchain.
I am now at the point where I can clear the current swapchain image to a certain color and present it. However, this fails for the first two frames that I try to present, and after that it runs smoothly without any validation errors. I am completely stumped at why this is happening, so I'm just gonna give the details of what I know and what I have tried and hopefully someone might know the answer here.
The error I get for the first two frames is as follows:
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)
This makes it seem like there might be a synchronization issue for the first two frames or something. Since I'm still doing early testing with Vulkan I'm just using device.waitIdle() instead of proper synchronization with semaphores and fences. I know that usage of waitIdle is a slow solution, but I thought it would at least serve to keep things synchronized, so I'm not sure if it is a synchronization issue.
My swapchain has 3 images, so if it was a problem with presenting images in the first round through the images then I should have gotten three errors...
The presentKHR function returns vk::Result::Success even on the first two frames. I have also tried turning off validation layers, and when I do so the first two frames are able to be presented, so it might be a bug in the validation layers?
Some of my initialization code:
// 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...
}
}
Rendering code executed every frame:
// 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;
}
Outside of specific circumstances or explicit synchronization, operations on the GPU execute in an arbitrary order.
Your graphics submission and your queue presentation have no synchronization between them. Therefore, they can execute in whatever order the implementation wants regardless of when you issue them.
However, since the graphics operation acts on an object which the presentation operation uses, there is a de-facto dependency. The graphics operation must act first. But you have no actual synchronization to enforce that dependency.
Hence the validation errors. You need to ensure that the queue presentation happens after the rendering operation.
I have now gotten confirmation that this issue is caused by a bug in the validation layers.
Here's the issue on Github: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4422
I have an object that I need to populate before using called pipelineInfo. To populate the object I use a function called createPipelineInfo. This works perfectly well when I use visual studios to compile a debug build but when I try to compile a release build the compiler "optimizes" out the entire createPipelineInfo function.
Here is the call to initialize the object and its use:
VkGraphicsPipelineCreateInfo pipelineInfo = createPipelineInfo(shaderStages, vertexInputInfo, inputAssembly, viewportState, rasterizer,
multisampling, colorBlending, pipelineLayout, renderPass);
if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
The following is the createPipelineInfo function:
inline static VkGraphicsPipelineCreateInfo createPipelineInfo(
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages,
const VkPipelineVertexInputStateCreateInfo& vertexInputInfo,
const VkPipelineInputAssemblyStateCreateInfo& inputAssembly,
const VkPipelineViewportStateCreateInfo& viewportState,
const VkPipelineRasterizationStateCreateInfo& rasterizer,
const VkPipelineMultisampleStateCreateInfo& multisampling,
const VkPipelineColorBlendStateCreateInfo& colorBlending,
const VkPipelineLayout& pipelineLayout,
const VkRenderPass& renderPass) {
VkGraphicsPipelineCreateInfo pipelineInfo{};
//Shader Stage
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages.data();
//Fixed Pipeline Stage
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
//pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr; // Optional
//Pipeline Layout
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
return pipelineInfo;
}
On the other hand if I copy the body of the function and dump it in place of the function call everything works perfectly fine.
VkGraphicsPipelineCreateInfo pipelineInfo{};
//Shader Stage
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages.data();
//Fixed Pipeline Stage
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
//pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr; // Optional
//Pipeline Layout
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
if (vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
I'm trying to figure out why the compiler is optimizing out the function call and failing that trying to develop a work around that doesn't involve dumping the body of the function in place of every call to the function.
wild guess: this parameter is passed by copy
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages
so when taking the address of its contents here with data method call:
pipelineInfo.pStages = shaderStages.data();
you invoke undefined behaviour. The compiler isn't smart enough to 1) warn you about taking a reference to temporary because of the complexity of the calls, and 2) it doesn't automatically perform copy elision on parameter passing.
Fix: pass it by reference (note that all other parameters use a by reference mode for a reason)
const std::array<VkPipelineShaderStageCreateInfo, 2> &shaderStages
I need to run a function on CPU between two GPU batches. For this I use timeline semaphores. As far as I know, vkQueueSubmit does not block. However, it blocks when I submit these GPU batches:
uint64_t host_wait = timeline;
uint64_t host_signal = ++timeline;
uint64_t wait0 = timeline;
uint64_t signal0 = ++timeline;
uint64_t wait1 = timeline;
uint64_t signal1 = ++timeline;
VkPipelineStageFlags wait_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkTimelineSemaphoreSubmitInfo sp_submit0 = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.waitSemaphoreValueCount = 1,
.pWaitSemaphoreValues = &wait0,
.signalSemaphoreValueCount = 1,
.pSignalSemaphoreValues = &signal0,
};
VkSubmitInfo submit0 = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = &sp_submit0,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &timeline_semaphore,
.pWaitDstStageMask = &wait_mask,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &timeline_semaphore,
};
VkTimelineSemaphoreSubmitInfo sp_submit1 = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.waitSemaphoreValueCount = 1,
.pWaitSemaphoreValues = &wait1,
.signalSemaphoreValueCount = 1,
.pSignalSemaphoreValues = &signal1,
};
VkSubmitInfo submit1 = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = &sp_submit1,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &timeline_semaphore,
.pWaitDstStageMask = &wait_mask,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &timeline_semaphore,
};
VkSubmitInfo infos[2] = { submit0, submit1 };
vkQueueSubmit(queue, 2, infos, fence);
// here vkQueueSubmit blocks the thread
WaitSemaphore(timeline_semaphore, host_wait);
some_function();
SignalSemaphore(timeline_semaphore, host_signal);
It is blocking for seconds without return, I think this is something like a deadlock. In the debugger, I saw SleepEx function call from vkQueueSubmit: vk_icdGetInstanceProcAddrSG -> ... -> SleepEx.
But vkQueueSubmit does not block in this sample (combined batch):
uint64_t host_wait = timeline;
uint64_t host_signal = ++timeline;
uint64_t wait1 = timeline;
uint64_t signal1 = ++timeline;
VkPipelineStageFlags wait_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkTimelineSemaphoreSubmitInfo sp_submit1 = {
.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
.waitSemaphoreValueCount = 1,
.pWaitSemaphoreValues = &wait1,
.signalSemaphoreValueCount = 1,
.pSignalSemaphoreValues = &signal1,
};
VkSubmitInfo submit1 = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = &sp_submit1,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &timeline_semaphore,
.pWaitDstStageMask = &wait_mask,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &timeline_semaphore,
};
VkSubmitInfo infos[1] = { submit1 };
vkQueueSubmit(queue, 1, infos, fence);
WaitSemaphore(timeline_semaphore, host_wait);
some_function();
SignalSemaphore(timeline_semaphore, host_signal);
Why vkQueueSubmit blocks in the first code sample? What are the possible causes of this problem?
I use Vulkan 1.2 (SDK 1.2.135) on Windows 10 and Radeon RX 570 (driver 20.4.2).
EDIT: When I add a command buffer to submit0, vkQueueSubmit will not block. Is it a bug in the driver?
Doing something odd like submitting a batch with no work is far more likely to be the cause.
The spec doesn’t have performance requirements. The fact that something is legal does not make it a good idea. Broadly speaking, if there are two ways to do a thing, do it the obvious way. And sending an empty batch isn’t exactly obvious
https://community.khronos.org/t/vkqueuesubmit-blocks-when-using-timeline-semaphores/105704/2
It seems I have had invalid code for a while but the validation layers were silent. After updating my sdk to the latest version I started getting this error:
Message ID name: VUID-vkQueuePresentKHR-pWaitSemaphores-03268
Message: [ VUID-vkQueuePresentKHR-pWaitSemaphores-03268 ] Object: 0x55b4b87478f0 (Name = Selected logical device : Type = 3) | VkQueue 0x55b4b8224020[Main queue] is waiting on VkSemaphore 0x110000000011[Render Finished Semaphore: 0] that has no way to be signaled. The Vulkan spec states: All elements of the pWaitSemaphores member of pPresentInfo must reference a semaphore signal operation that has been submitted for execution and any semaphore signal operations on which it depends (if any) must have also been submitted for execution. (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkQueuePresentKHR-pWaitSemaphores-03268)
Severity: VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT
This happens inside of my main draw loop and it's the only validation layer error in my code. If I never call the code that is responsible for surface presentation. I get no errors.
I am sure the place where I am doing things wrong is here:
void DisplayTarget::StartPass(uint target_num, bool should_clear,
VulkanImage* external_depth)
{
auto device = h_interface->GetDevice();
auto result = device.acquireNextImageKHR(
*swap_chain,
std::numeric_limits<uint64_t>::max(),
*img_available_sems[current_frame],
nullptr,
&active_image_index);
if(result != vk::Result::eSuccess)
Log::RecordLog("Failed to acquire image");
}
vk::Result DisplayTarget::EndPass()
{
auto device = h_interface->GetDevice();
auto cmd_buff = h_interface->GetCmdBuffer();
auto graphics_queue = h_interface->GetQueue();
device.waitForFences(
1,
&*in_flight_fences[current_frame],
VK_TRUE,
std::numeric_limits<uint64_t>::max());
vk::Semaphore wait_semaphores[] = {*img_available_sems[current_frame]};
vk::PipelineStageFlags wait_stages[] = {
vk::PipelineStageFlagBits::eColorAttachmentOutput};
vk::Semaphore signal_semaphores[] = {*render_finished_sems[current_frame]};
vk::SubmitInfo submit_info(
1, wait_semaphores, wait_stages, 1, &cmd_buff, 1, signal_semaphores);
device.resetFences(1, &*in_flight_fences[current_frame]);
auto result =
graphics_queue.submit(1, &submit_info, *in_flight_fences[current_frame]);
if(result != vk::Result::eSuccess)
Log::RecordLog("Failed to submit draw command buffer!");
graphics_queue.waitIdle();
device.waitIdle();
vk::SwapchainKHR swap_chains[] = {*swap_chain};
vk::PresentInfoKHR present_info = {};
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphores;
present_info.swapchainCount = 1;
present_info.pSwapchains = swap_chains;
present_info.pImageIndices = &active_image_index;
result = graphics_queue.presentKHR(&present_info);
current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
return result;
}
Currently they are called consecutively:
display.StartPass();
display.EndPass();
To get things working I have tried both commenting parts of these 2 functions out or changing the order in which things are called, but either the error persists or I get different validation errors.
I also tried signaling the semaphore directly:
vk::SemaphoreSignalInfo semaphore_info = {};
semaphore_info.semaphore = *render_finished_sems[current_frame];
semaphore_info.value = 0;
device.signalSemaphore(semaphore_info);
But all I managed is to cause a segmentation fault
The error was the order of operations. This is wrong:
graphics_queue.waitIdle();
device.waitIdle();
vk::SwapchainKHR swap_chains[] = {*swap_chain};
vk::PresentInfoKHR present_info = {};
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphores;
present_info.swapchainCount = 1;
present_info.pSwapchains = swap_chains;
present_info.pImageIndices = &active_image_index;
result = graphics_queue.presentKHR(&present_info);
current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
This is the correct use:
vk::SwapchainKHR swap_chains[] = {*swap_chain};
vk::PresentInfoKHR present_info = {};
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphores;
present_info.swapchainCount = 1;
present_info.pSwapchains = swap_chains;
present_info.pImageIndices = &active_image_index;
result = graphics_queue.presentKHR(&present_info);
current_frame = (current_frame + 1) % MAX_FRAMES_IN_FLIGHT;
graphics_queue.waitIdle();
device.waitIdle();
I started learning Vulkan and everything went quite well, but somehow, the function vkGetSwapChainImages() wants to ruin my life.
Basically, this is how I create the SwapChain. desiredFormat, desiredExtent, desiredUsage, desiredExtent and desiredTransform are all set well.
VkSwapchainCreateInfoKHR swapChainCreateInfo = { };
swapChainCreateInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapChainCreateInfo.flags = 0;
swapChainCreateInfo.pNext = nullptr;
swapChainCreateInfo.compositeAlpha = VkCompositeAlphaFlagBitsKHR::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapChainCreateInfo.imageColorSpace = desiredFormat.colorSpace;
swapChainCreateInfo.imageFormat = desiredFormat.format;
swapChainCreateInfo.imageExtent = desiredExtent;
swapChainCreateInfo.clipped = VK_TRUE;
swapChainCreateInfo.imageArrayLayers = 1;
swapChainCreateInfo.imageSharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
swapChainCreateInfo.surface = mRenderingSurface;
swapChainCreateInfo.imageUsage = desiredUsage;
swapChainCreateInfo.minImageCount = desiredImageCount;
swapChainCreateInfo.presentMode = desiredMode;
swapChainCreateInfo.oldSwapchain = oldSwapChain;
swapChainCreateInfo.pQueueFamilyIndices = nullptr;
swapChainCreateInfo.queueFamilyIndexCount = 0;
swapChainCreateInfo.preTransform = desiredTransform;
if ( vkCreateSwapchainKHR( mLogicalDevice, &swapChainCreateInfo, nullptr, &mSwapChain ) != VK_SUCCESS )
return false;
If I call vkGetSwapChainImages nothing bad happens. But if I want to call vkGetSwapChainImages a second time, it doesn't work and I get an exception like this
Exception thrown at 0x0433A209 (VkLayer_core_validation.dll) in Project1.exe: 0xC0000005: Access violation reading location 0x000000A8.
And I don't understand why this happens. I tried saving the results from first call and using them, but I still get an error, so I that there's something I'm doing wrong here.