Vulkan queue waiting on semaphore that can't be signaled - c++

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();

Related

Vulkan validation errors states my images are in the wrong layout, but only the two first times I present images from the swapchain

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

vkQueueSubmit blocks when using timeline semaphores

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

E_INVALIDARG when calling CreateGraphicsPipelineState

I've been getting a weird error when calling CreateGraphicsPipelineState().
The function returns E_INVALIDARG even though the description is all set up.
The description worked before and the I tried to add indexbuffers to my pipeline, I didn't even touch any of the code for PSO or Shaders and now the PSO creation is all messed up.
The issue is that I don't get any DX-error messages from the driver when enabling the debug-layer. I only get this
"Microsoft C++ exception: _com_error at memory location
when I step through the function.
It feels like it is some pointer error or similar, but I can't figure out what the error is. Perhaps anyone of you can see an obvious mistake that I made?
Here's my code:
CGraphicsPSO* pso = new CGraphicsPSO();
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
// Input Layout
std::vector<D3D12_INPUT_ELEMENT_DESC> elements;
if (aPSODesc.inputLayout != nullptr)
{
auto& ilData = aPSODesc.inputLayout->desc;
for (auto& element : ilData)
{
// All Data here is correct when breaking
D3D12_INPUT_ELEMENT_DESC elementDesc;
elementDesc.SemanticName = element.mySemanticName;
elementDesc.SemanticIndex = element.mySemanticIndex;
elementDesc.InputSlot = element.myInputSlot;
elementDesc.AlignedByteOffset = element.myAlignedByteOffset;
elementDesc.InputSlotClass = _ConvertInputClassificationDX12(element.myInputSlotClass);
elementDesc.Format = _ConvertFormatDX12(element.myFormat);
elementDesc.InstanceDataStepRate = element.myInstanceDataStepRate;
elements.push_back(elementDesc);
}
D3D12_INPUT_LAYOUT_DESC inputLayout = {};
inputLayout.NumElements = (UINT)elements.size();
inputLayout.pInputElementDescs = elements.data();
psoDesc.InputLayout = inputLayout;
}
// TOPOLOGY
switch (aPSODesc.topology)
{
default:
case EPrimitiveTopology::TriangleList:
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; // <--- Always this option
break;
case EPrimitiveTopology::PointList:
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
break;
case EPrimitiveTopology::LineList:
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
break;
//case EPrimitiveTopology::Patch:
// psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
// break;
}
// Shaders
if (aPSODesc.vs != nullptr)
{
D3D12_SHADER_BYTECODE vertexShaderBytecode = {};
vertexShaderBytecode.BytecodeLength = aPSODesc.vs->myByteCodeSize;
vertexShaderBytecode.pShaderBytecode = aPSODesc.vs->myByteCode;
psoDesc.VS = vertexShaderBytecode;
}
if (aPSODesc.ps != nullptr)
{
D3D12_SHADER_BYTECODE pixelShaderBytecode = {};
pixelShaderBytecode.BytecodeLength = aPSODesc.ps->myByteCodeSize;
pixelShaderBytecode.pShaderBytecode = aPSODesc.ps->myByteCode;
psoDesc.PS = pixelShaderBytecode;
}
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; // format of the render target
DXGI_SAMPLE_DESC sampleDesc = {};
sampleDesc.Count = 1;
sampleDesc.Quality = 0;
psoDesc.DepthStencilState.DepthEnable = FALSE;
psoDesc.DepthStencilState.StencilEnable = FALSE;
psoDesc.SampleDesc = sampleDesc; // must be the same sample description as the swapchain and depth/stencil buffer
psoDesc.SampleMask = UINT_MAX; // sample mask has to do with multi-sampling. 0xffffffff means point sampling is done
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); // a default rasterizer state.
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); // a default blent state.
psoDesc.NumRenderTargets = 1; // we are only binding one render target
psoDesc.pRootSignature = myGraphicsRootSignature;
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
ID3D12PipelineState* pipelineState;
HRESULT hr = myDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineState));
pso->myPipelineState = pipelineState;
if (FAILED(hr))
{
delete pso;
return nullptr;
}
return pso;
So I just found the error.
It seems like the way I parsed my semantics for my input-layout gave me an invalid pointer.
Thus the memory at the adress was invalid and giving the DX12-device incorrect decriptions.
So what I did was to locally store the semantic-names within my CreatePSO function until the PSO was created, and now it all works.
Looks to me like the pointers to storage you promised are going out of scope.
..
D3D12_INPUT_LAYOUT_DESC inputLayout = {};
..
psoDesc.InputLayout = inputLayout;
}

vkGetSwapChainImages crashes after first call

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.

OSX AUGraph recreation causes badComponentType error

On OSX I'm creating an AUGraph for my audio system like so:
OSStatus result = NewAUGraph(&mGraph);
AUNode outputNode;
AudioComponentDescription outputDesc;
outputDesc.componentType = kAudioUnitType_Output;
outputDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
outputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
outputDesc.componentFlags = 0;
outputDesc.componentFlagsMask = 0;
result = AUGraphAddNode(mGraph, &outputDesc, &outputNode);
AUNode converterNode;
AudioComponentDescription converterDesc;
converterDesc.componentType = kAudioUnitType_FormatConverter;
converterDesc.componentSubType = kAudioUnitSubType_AUConverter;
converterDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
converterDesc.componentFlags = 0;
outputDesc.componentFlagsMask = 0;
result = AUGraphAddNode(mGraph, &converterDesc, &converterNode);
result = AUGraphConnectNodeInput(mGraph, converterNode, 0, outputNode, 0);
result = AUGraphOpen(mGraph);
...initialize graph, start graph, etc...
This all works fine, I can hear sound, etc. Later the system is shut down:
unsigned char isRunning = false;
AUGraphIsRunning(mGraph, &isRunning);
if (isRunning)
AUGraphStop(mGraph);
OSStatus result;
unsigned char isInitialized = false;
AUGraphIsInitialized(mGraph, &isInitialized);
if (isInitialized)
{
result = AUGraphUninitialize(mGraph);
}
result = DisposeAUGraph(mGraph);
Again, no problems here. However a short while after the first code block gets executed again when the system is restarted. On:
result = AUGraphOpen(mGraph);
"result" comes out as -2005 (badComponentType). Anyone know what causes this?
Calling AUGraphClose in the shutdown fixed this. Guess you can't have two open graphs with the same output unit in?