Skip to content

Commit

Permalink
Simplify code for image layout transition
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed Jun 28, 2024
1 parent 8c852ed commit 4980977
Showing 1 changed file with 82 additions and 192 deletions.
274 changes: 82 additions & 192 deletions src/XenoAtom.Graphics/Vk/VulkanUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,202 +135,28 @@ public static void TransitionImageLayout(
barrier.subresourceRange.baseArrayLayer = baseArrayLayer;
barrier.subresourceRange.layerCount = layerCount;

VkPipelineStageFlagBits srcStageFlags = VK_PIPELINE_STAGE_NONE;
VkPipelineStageFlagBits dstStageFlags = VK_PIPELINE_STAGE_NONE;
VkPipelineStageFlagBits srcStageFlags;
VkPipelineStageFlagBits dstStageFlags;

if ((oldLayout == VK_IMAGE_LAYOUT_UNDEFINED || oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_NONE;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_NONE;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_GENERAL)
{
barrier.srcAccessMask = VK_ACCESS_NONE;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_NONE;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_GENERAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_GENERAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
barrier.srcAccessMask = GetDefaultTransitionImageLayoutFlags(oldLayout, out srcStageFlags, true);
barrier.dstAccessMask = GetDefaultTransitionImageLayoutFlags(newLayout, out dstStageFlags, true);

else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
// Special cases for transitions
if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dstStageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
{
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_GENERAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_GENERAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
if (newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
}
else
else if (oldLayout == VK_IMAGE_LAYOUT_GENERAL)
{
Debug.Fail($"Invalid image layout transition. {oldLayout} -> {newLayout}");
if (newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
srcStageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
}

vkCmdPipelineBarrier(
Expand All @@ -342,9 +168,73 @@ public static void TransitionImageLayout(
0, null,
1, &barrier);
}

private static VkAccessFlagBits GetDefaultTransitionImageLayoutFlags(VkImageLayout layout, out VkPipelineStageFlagBits stageFlags, bool isSrc)
{
// Return VkAccessFlagBits and VkPipelineStageFlagBits according to layout
VkAccessFlagBits accessFlags;

// Switch
switch (layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
case VK_IMAGE_LAYOUT_PREINITIALIZED:
accessFlags = VK_ACCESS_NONE;
stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;

case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
accessFlags = VK_ACCESS_TRANSFER_WRITE_BIT;
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;

case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
accessFlags = VK_ACCESS_TRANSFER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;

case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
accessFlags = VK_ACCESS_SHADER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;

case VK_IMAGE_LAYOUT_GENERAL:
if (isSrc)
{
accessFlags = VK_ACCESS_TRANSFER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else
{
accessFlags = VK_ACCESS_SHADER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
break;

case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
accessFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;

case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
accessFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
stageFlags = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;

case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
accessFlags = VK_ACCESS_MEMORY_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;

default:
throw new NotImplementedException($"The transition for image layout {layout} is not implemented or valid.");
}

return accessFlags;
}
}

internal unsafe static class VkPhysicalDeviceMemoryPropertiesEx
internal static unsafe class VkPhysicalDeviceMemoryPropertiesEx
{
public static VkMemoryType GetMemoryType(this VkPhysicalDeviceMemoryProperties memoryProperties, uint index)
{
Expand Down

0 comments on commit 4980977

Please sign in to comment.