vulkanfragment-shader

Vulkan - Fragment shader doesn't seem to output anything to swapchain image


I started building a little renderer to try out Vulkan (coming from OpenGL). I started by a good old triangle but the fragment shader doesn't want to output anything. My output image (coming directly from the swapchain) stays filled with the clear color. I'm using Vulkan 1.3 for dynamic rendering.

Using RenderDoc, I can see that the vertex shader works, but the output stays desperately empty. Here are some parts of my capture (if that can help) :

Rasterizer tab of my graphics pipeline during the vkCmdDraw call

Blend and depth state

Capture and API inspector

I try to disable rasterizer discard, disable face culling. I also try to tweak the blend state in all way possible, but nothing changed.

Here is my mainloop (if that can help) :

VkRenderingAttachmentInfo renderingAttachmentInfos {};
renderingAttachmentInfos.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
renderingAttachmentInfos.clearValue.color = {{0.1f, 0.1f, 0.1f, 1.f}};
renderingAttachmentInfos.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
renderingAttachmentInfos.imageView = context.getSwapchain()->getImageViews()[imageIndex];
renderingAttachmentInfos.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
renderingAttachmentInfos.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
renderingAttachmentInfos.resolveMode = VK_RESOLVE_MODE_NONE;
renderingAttachmentInfos.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
renderingAttachmentInfos.resolveImageView = VK_NULL_HANDLE;

VkRenderingInfo renderingInfos {};
renderingInfos.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
renderingInfos.colorAttachmentCount = 1;
renderingInfos.pColorAttachments = &renderingAttachmentInfos;
renderingInfos.renderArea.offset = {0, 0};
renderingInfos.renderArea.extent = context.getSwapchain()->getExtent();
renderingInfos.layerCount = 1;
renderingInfos.viewMask = 0;

VkCommandBufferBeginInfo beginInfos {};
beginInfos.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfos.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
beginInfos.pInheritanceInfo = nullptr;
(void)vkBeginCommandBuffer(graphicsCommandBuffer, &beginInfos);

VkImageMemoryBarrier imageMemoryBarrier {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.image = context.getSwapchain()->getImages()[imageIndex];
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
    graphicsCommandBuffer,
    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier
);

vkCmdBeginRendering(graphicsCommandBuffer, &renderingInfos);

vkCmdBindPipeline(graphicsCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getPipeline());

VkViewport viewport {};
viewport.x = 0.f;
viewport.y = 0.f;
viewport.width = context.getSwapchain()->getExtent().width;
viewport.height = context.getSwapchain()->getExtent().height;
viewport.minDepth = 0.f;
viewport.maxDepth = 1.f;
vkCmdSetViewport(graphicsCommandBuffer, 0, 1, &viewport);

VkRect2D scissor {};
scissor.offset = {0, 0};
scissor.extent = context.getSwapchain()->getExtent();
vkCmdSetScissor(graphicsCommandBuffer, 0, 1, &scissor);

VkBuffer buffer {vertexBuffer.getBuffer()};
VkDeviceSize offset {vertexBufferView.getInfos().offset};
vkCmdBindVertexBuffers(graphicsCommandBuffer, 0, 1, &buffer, &offset);

vkCmdDraw(graphicsCommandBuffer, vertices.size() / 5, vertices.size() / 15, 0, 0);

vkCmdEndRendering(graphicsCommandBuffer);

imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.image = context.getSwapchain()->getImages()[imageIndex];
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
    graphicsCommandBuffer,
    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
    0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier
);

(void)vkEndCommandBuffer(graphicsCommandBuffer);


VkSubmitInfo submitInfos {};
VkPipelineStageFlags dstStageMask {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfos.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfos.commandBufferCount = 1;
submitInfos.pCommandBuffers = &graphicsCommandBuffer;
submitInfos.waitSemaphoreCount = 1;
submitInfos.pWaitSemaphores = &imageReadySemaphore;
submitInfos.pWaitDstStageMask = &dstStageMask;
submitInfos.signalSemaphoreCount = 1;
submitInfos.pSignalSemaphores = &imageDrawnSemaphore;
(void)vkQueueSubmit(context.getDevice()->getQueue(se::renderer::vulkan::QueueType::eGraphics), 1, &submitInfos, previousFrameReadyFence);

VkSwapchainKHR swapchain {context.getSwapchain()->getSwapChain()};
VkPresentInfoKHR presentInfos {};
presentInfos.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfos.swapchainCount = 1;
presentInfos.pSwapchains = &swapchain;
presentInfos.pImageIndices = &imageIndex;
presentInfos.pResults = nullptr;
presentInfos.waitSemaphoreCount = 1;
presentInfos.pWaitSemaphores = &imageDrawnSemaphore;
(void)vkQueuePresentKHR(context.getDevice()->getQueue(se::renderer::vulkan::QueueType::ePresent), &presentInfos);

After a bit more testing, the only place where my code works is with an Nvidia GPU (rtx 4060 Mobile) on Arch with the proprietary driver


Solution

  • The problem was that I was not passing VkPipelineRenderingCreateInfo object in the pNext chain of VkGraphicsPipelineCreateInfo