Command buffer still in use

Hello again.

I got one more report from the validation layers.
I can’t reset my commandbuffers because they are still in use --> Error

I can’t find a way to fix this. There are a lot of examples without resetting commandbuffers out there, but none with it.
That makes it hard for me.

Fences are created with the VK_FENCE_CREATE_SIGNALED_BIT flag.

The code (function order == execution order):


void DCRHI::BuildCommandBuffers()
{
	VkCommandBufferBeginInfo cmdBufInfo = {};
	cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
	cmdBufInfo.pNext = VK_NULL_HANDLE;

	VkClearValue clearValues[2];
	clearValues[0].color = { { 0.2f, 0.0f, 0.2f, 1.0f } };
	clearValues[1].depthStencil = { 1.0f, 0 };

	VkRenderPassBeginInfo renderPassBeginInfo = {};
	renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
	renderPassBeginInfo.pNext = VK_NULL_HANDLE;
	renderPassBeginInfo.renderPass = DCINTERNAL::g_renderpass.GetRenderPass();
	renderPassBeginInfo.renderArea.offset.x = 0;
	renderPassBeginInfo.renderArea.offset.y = 0;
	renderPassBeginInfo.renderArea.extent.width = DCINTERNAL::g_swapchain.GetSwapchainWidth();
	renderPassBeginInfo.renderArea.extent.height = DCINTERNAL::g_swapchain.GetSwapchainHeight();
	renderPassBeginInfo.clearValueCount = 2;
	renderPassBeginInfo.pClearValues = clearValues;

	// some special stuff
	DCScene* scene = nullptr;
	scene = DCSceneManager::GetSceneByIndex(0);
	DCHierarchy& hierarchy = scene->GetHierarchy();
	std::vector<DCEntity*> entities = hierarchy.GetEntitiesByName("Camera");
	DCEntity* cameraEntity = entities[0];
	Camera* cam = cameraEntity->GetComponent<Camera>();
	
	// prepares all meshRenderers for rendering
	for (uint32_t ii = 0; ii < m_renderables.size(); ii++)
	{
		m_renderables[ii]->PrepareRenderer(*cam);
	}

	for (uint32_t i = 0; i < 2; i++)
	{
		VkResult result;
		// wait for the sync fence to ensure the commandBuffer is not in use on rendering
		result = vkWaitForFences(DCINTERNAL::g_devices[0].GetDevice(), 1, &m_waitFences[m_currentBuffer], VK_TRUE, UINT64_MAX);

		// error. Command buffer still in use
		result = vkResetCommandBuffer(m_commandBuffers[i]->GetCommandBuffer(), VkCommandBufferResetFlagBits::VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);

		// Set target frame
		renderPassBeginInfo.framebuffer = DCINTERNAL::g_swapchain.GetFramebuffers().GetFramebuffer(i);

		this->GetCommandBuffer(i).BeginCommandBuffer(VkCommandBufferUsageFlagBits::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);

		// Startes the first sub pass specified in our default render pass setup
		// by the base class. This will clear the color and depth attachment
		vkCmdBeginRenderPass(this->GetCommandBuffer(i).GetCommandBuffer(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

		// Update the dynamic viewport
		VkViewport viewport = {};
		viewport.width = (float)DCINTERNAL::g_swapchain.GetSwapchainWidth();
		viewport.height = (float)DCINTERNAL::g_swapchain.GetSwapchainHeight();
		viewport.minDepth = (float)0.0f;
		viewport.maxDepth = (float)1.0f;
		vkCmdSetViewport(this->GetCommandBuffer(i).GetCommandBuffer(), 0, 1, &viewport);

		// Update the dynamic viewport
		VkRect2D scissor = {};
		scissor.extent.width = (float)DCINTERNAL::g_swapchain.GetSwapchainWidth();
		scissor.extent.height = (float)DCINTERNAL::g_swapchain.GetSwapchainHeight();
		scissor.offset.x = 0;
		scissor.offset.y = 0;
		vkCmdSetScissor(this->GetCommandBuffer(i).GetCommandBuffer(), 0, 1, &scissor);


		for (uint32_t ii = m_renderables.size() - 1; ii >= 0; ii--)
		{
			m_renderables[ii]->Render(this->GetCommandBuffer(i));
			if (ii == 0)
				break;
		}

		vkCmdEndRenderPass(this->GetCommandBuffer(i).GetCommandBuffer());

		vkEndCommandBuffer(this->GetCommandBuffer(i).GetCommandBuffer());
	}
}

void DCRHI::SubmitToQueue()
{
	VkResult result;
	// get the next image in the swapchain (back/front buffer)
	result = DCINTERNAL::g_swapchain.AcquireNextImage(m_semPresentComplete, &m_currentBuffer);
	// use a fence to wait until the command buffer has finished execution before using it again
	result = vkWaitForFences(DCINTERNAL::g_devices[0].GetDevice(), 1, &m_waitFences[m_currentBuffer], VK_TRUE, UINT64_MAX);
	result = vkResetFences(DCINTERNAL::g_devices[0].GetDevice(), 1, &m_waitFences[m_currentBuffer]);

	// pipeline stage at which the queue submission will wait
	VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
	// the submit info structure specifies a command buffer queue submission batch
	VkSubmitInfo submitInfo = {};
	submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
	submitInfo.pWaitDstStageMask = &waitStageMask;
	submitInfo.pWaitSemaphores = &m_semPresentComplete;
	submitInfo.waitSemaphoreCount = 1;
	submitInfo.pSignalSemaphores = &m_semRenderComplete;
	submitInfo.signalSemaphoreCount = 1;
	submitInfo.pCommandBuffers = &this->GetCommandBuffer(m_currentBuffer).GetCommandBuffer();
	submitInfo.commandBufferCount = 1;

	vkQueueSubmit(DCINTERNAL::g_swapchain.GetQueue(), 1, &submitInfo, m_waitFences[m_currentBuffer]);
}

void DCRHI::render()
{
	DCINTERNAL::g_swapchain.QueuePresent(DCINTERNAL::g_swapchain.GetQueue() , m_currentBuffer, m_semRenderComplete);
}

Thank you!

Problem solved. Fences were recreated each frame… sorry for that.