Ok I found vulkan is very not practice to use.
At each beginning of command buffer recording, the buffer is cleared, I tried to make several submits, so I tried to do this :
-Acquiring en image.
-Submitting graphics work.
-Presenting.
But that doesn’t work if I don’t put all this code in the same function like this :
void RenderWindow::drawVulkanFrame() {
vkWaitForFences(vkDevice.getDevice(), 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
uint32_t imageIndex;
vkAcquireNextImageKHR(vkDevice.getDevice(), swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
// Vérifier si une frame précédente est en train d'utiliser cette image (il y a une fence à attendre)
if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
vkWaitForFences(vkDevice.getDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
}
// Marque l'image comme étant à nouveau utilisée par cette frame
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &getCommandBuffers()[imageIndex];
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
vkResetFences(vkDevice.getDevice(), 1, &inFlightFences[currentFrame]);
/*VkResult result = vkQueueSubmit(vkDevice.getGraphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]);
std::cout<<"render window result : "<<result<<std::endl;*/
if (vkQueueSubmit(vkDevice.getGraphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
throw core::Erreur(0, "échec de l'envoi d'un command buffer!", 1);
}
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = {swapChain};
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr; // Optionnel
vkQueuePresentKHR(vkDevice.getPresentQueue(), &presentInfo);
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
vkDeviceWaitIdle(vkDevice.getDevice());
}
}
I’ve a bunch a errors :
It tells me a semaphore is signaled when acquiring the swapchain I don’t know why.
It tells me the image acquiring is exceeded the maximum swapchain images I don’t know why.
And it tells me a semaphore is never signaled I don’t know why.
So I tried to submit all draw command at once like this :
-I start recording.
-I record all draw calls.
-I end recording before the presentation.
void RenderWindow::clear(const sf::Color& color) {
clearColor = color;
VkClearColorValue clearValue{
.uint32 = {clearColor.r, clearColor.g, clearColor.b, clearColor.a}
};
VkImageSubresourceRange imageRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1
};
for (unsigned int i = 0; i < getCommandBuffers().size(); i++) {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (vkBeginCommandBuffer(getCommandBuffers()[i], &beginInfo) != VK_SUCCESS) {
throw core::Erreur(0, "failed to begin recording command buffer!", 1);
}
VkImageMemoryBarrier presentToClearBarrier {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = getSwapchainImages()[i],
.subresourceRange = imageRange
};
VkImageMemoryBarrier clearToPresentBarrier {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = getSwapchainImages()[i],
.subresourceRange = imageRange
};
vkCmdPipelineBarrier(getCommandBuffers()[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &presentToClearBarrier);
vkCmdClearColorImage(getCommandBuffers()[i], getSwapchainImages()[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue, 1, &imageRange);
vkCmdPipelineBarrier(getCommandBuffers()[i], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &clearToPresentBarrier);
/*if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
throw core::Erreur(0, "failed to record command buffer!", 1);
}*/
}
}
void RenderTarget::draw(const Vertex* vertices, unsigned int vertexCount, sf::PrimitiveType type,
RenderStates states) {
vertexBuffer.clear();
for (unsigned int i = 0; i < vertexCount; i++) {
vertexBuffer.append(vertices[i]);
}
if (type == sf::Quads) {
for (unsigned int i = 0; i < vertexBuffer.getSize(); i+=4) {
vertexBuffer.addIndex(i);
vertexBuffer.addIndex(i+1);
vertexBuffer.addIndex(i+2);
vertexBuffer.addIndex(i);
vertexBuffer.addIndex(i+2);
vertexBuffer.addIndex(i+3);
}
type = sf::Triangles;
}
vertexBuffer.update();
UniformBufferObject ubo;
ubo.proj = m_view.getProjMatrix().getMatrix().transpose();
ubo.proj.m22 *= -1;
ubo.view = m_view.getViewMatrix().getMatrix().transpose();
ubo.model = states.transform.getMatrix().transpose();
updateUniformBuffer(getCurrentFrame(), ubo);
createDescriptorSetLayout(states.texture);
createGraphicPipeline(type, states);
createDescriptorPool(states.texture);
createDescriptorSets(states.texture);
recordCommandBuffers();
vertexBuffer.clearIndexes();
}
void RenderTarget::recordCommandBuffers() {
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 core::Erreur(0, "failed to begin recording command buffer!", 1);
}*/
VkRenderPassBeginInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassInfo.renderPass = getRenderPass();
renderPassInfo.framebuffer = getSwapchainFrameBuffers()[i];
renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = getSwapchainExtents();
VkClearValue clrColor = {clearColor.r / 255.f,clearColor.g / 255.f, clearColor.b / 255.f, clearColor.a / 255.f};
renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clrColor;
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
VkBuffer vertexBuffers[] = {vertexBuffer.getVertexBuffer()};
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[getCurrentFrame()], 0, nullptr);
if(vertexBuffer.getIndicesSize() > 0) {
vkCmdBindIndexBuffer(commandBuffers[i], vertexBuffer.getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16);
}
if(vertexBuffer.getIndicesSize() > 0) {
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(vertexBuffer.getIndicesSize()), 1, 0, 0, 0);
} else {
vkCmdDraw(commandBuffers[i], static_cast<uint32_t>(vertexBuffer.getSize()), 1, 0, 0);
}
vkCmdEndRenderPass(commandBuffers[i]);
/*if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
throw core::Erreur(0, "failed to record command buffer!", 1);
}*/
}
}
void RenderWindow::drawVulkanFrame() {
if (getCommandBuffers().size() > 0) {
for (unsigned int i = 0; i < getCommandBuffers().size(); i++) {
if (vkEndCommandBuffer(getCommandBuffers()[i]) != VK_SUCCESS) {
throw core::Erreur(0, "failed to record command buffer!", 1);
}
}
vkWaitForFences(vkDevice.getDevice(), 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
uint32_t imageIndex;
vkAcquireNextImageKHR(vkDevice.getDevice(), swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
// Vérifier si une frame précédente est en train d'utiliser cette image (il y a une fence à attendre)
if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
vkWaitForFences(vkDevice.getDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX);
}
// Marque l'image comme étant à nouveau utilisée par cette frame
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &getCommandBuffers()[imageIndex];
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
vkResetFences(vkDevice.getDevice(), 1, &inFlightFences[currentFrame]);
/*VkResult result = vkQueueSubmit(vkDevice.getGraphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]);
std::cout<<"render window result : "<<result<<std::endl;*/
if (vkQueueSubmit(vkDevice.getGraphicsQueue(), 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
throw core::Erreur(0, "échec de l'envoi d'un command buffer!", 1);
}
VkPresentInfoKHR presentInfo{};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
VkSwapchainKHR swapChains[] = {swapChain};
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentInfo.pResults = nullptr; // Optionnel
vkQueuePresentKHR(vkDevice.getPresentQueue(), &presentInfo);
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
vkDeviceWaitIdle(vkDevice.getDevice());
}
}
void RenderWindow::cleanupSwapchain() {
for (size_t i = 0; i < swapChainFramebuffers.size(); i++) {
vkDestroyFramebuffer(vkDevice.getDevice(), swapChainFramebuffers[i], nullptr);
}
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
vkDestroyImageView(vkDevice.getDevice(), swapChainImageViews[i], nullptr);
}
vkDestroySwapchainKHR(vkDevice.getDevice(), swapChain, nullptr);
vkDestroyRenderPass(vkDevice.getDevice(), renderPass, nullptr);
}
But it cause another problem, my buffers are updated at each draw calls, so, the values passed to the shaders are only the ones from the last buffer update.
And I don’t know how to fix this.
Thanks.