|
|
@@ -672,17 +672,16 @@ struct VulkanTextureContainer
|
|
|
bool externallyManaged; // true for XR swapchain images
|
|
|
};
|
|
|
|
|
|
-typedef enum VulkanBufferUsageMode
|
|
|
-{
|
|
|
- VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_VERTEX_READ,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_INDEX_READ,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_INDIRECT,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ,
|
|
|
- VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE,
|
|
|
-} VulkanBufferUsageMode;
|
|
|
+typedef Uint32 VulkanBufferUsageModeFlags;
|
|
|
+
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE (1u << 0)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION (1u << 1)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_VERTEX_READ (1u << 2)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_INDEX_READ (1u << 3)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_INDIRECT (1u << 4)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ (1u << 5)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ (1u << 6)
|
|
|
+#define VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE (1u << 7)
|
|
|
|
|
|
typedef enum VulkanTextureUsageMode
|
|
|
{
|
|
|
@@ -2609,6 +2608,9 @@ static void VULKAN_INTERNAL_TrackUniformBuffer(
|
|
|
* These indicate the current usage of that resource on the command buffer.
|
|
|
* The transition from one usage mode to another indicates how the barrier should be constructed.
|
|
|
*
|
|
|
+ * For buffer reads, read usage modes can be combined.
|
|
|
+ * This can be a useful shortcut in certain cases, like when reading GLTF data.
|
|
|
+ *
|
|
|
* Pipeline barriers cannot be inserted during a render pass, but they can be inserted
|
|
|
* during a compute or copy pass.
|
|
|
*
|
|
|
@@ -2628,17 +2630,66 @@ static void VULKAN_INTERNAL_TrackUniformBuffer(
|
|
|
* and transition it back to its default on EndRenderPass.
|
|
|
*
|
|
|
* This strategy imposes certain limitations on resource usage flags.
|
|
|
- * For example, a texture cannot have both the SAMPLER and GRAPHICS_STORAGE usage flags,
|
|
|
+ * For example, a texture cannot have both the SAMPLER and STORAGE_READ usage flags,
|
|
|
* because then it is impossible for the backend to infer which default usage mode the texture should use.
|
|
|
*
|
|
|
* Sync hazards can be detected by setting VK_KHRONOS_VALIDATION_VALIDATE_SYNC=1 when using validation layers.
|
|
|
*/
|
|
|
|
|
|
+static void VULKAN_INTERNAL_SetMemoryBarrierFlags(
|
|
|
+ VulkanBufferUsageModeFlags usageModeFlags,
|
|
|
+ VkPipelineStageFlags *stageFlags,
|
|
|
+ VkAccessFlags *accessMask)
|
|
|
+{
|
|
|
+ // Combinable read flags
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_INDEX_READ) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_INDEX_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_INDIRECT) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_SHADER_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_SHADER_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Transfer flags (these will never be combined with other usages)
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_TRANSFER_READ_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read-write flag
|
|
|
+ if (usageModeFlags & VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
|
|
|
+ *stageFlags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
+ *accessMask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void VULKAN_INTERNAL_BufferMemoryBarrier(
|
|
|
VulkanRenderer *renderer,
|
|
|
VulkanCommandBuffer *commandBuffer,
|
|
|
- VulkanBufferUsageMode sourceUsageMode,
|
|
|
- VulkanBufferUsageMode destinationUsageMode,
|
|
|
+ VulkanBufferUsageModeFlags sourceUsageMode,
|
|
|
+ VulkanBufferUsageModeFlags destinationUsageMode,
|
|
|
VulkanBuffer *buffer)
|
|
|
{
|
|
|
VkPipelineStageFlags srcStages = 0;
|
|
|
@@ -2655,63 +2706,15 @@ static void VULKAN_INTERNAL_BufferMemoryBarrier(
|
|
|
memoryBarrier.offset = 0;
|
|
|
memoryBarrier.size = buffer->size;
|
|
|
|
|
|
- if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_INDEX_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
|
- } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
|
|
|
- srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
- memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
|
|
- } else {
|
|
|
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer source barrier type!");
|
|
|
- return;
|
|
|
- }
|
|
|
+ VULKAN_INTERNAL_SetMemoryBarrierFlags(
|
|
|
+ sourceUsageMode,
|
|
|
+ &srcStages,
|
|
|
+ &memoryBarrier.srcAccessMask);
|
|
|
|
|
|
- if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_INDEX_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
|
- } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) {
|
|
|
- dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
|
|
- memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
|
|
- } else {
|
|
|
- SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer destination barrier type!");
|
|
|
- return;
|
|
|
- }
|
|
|
+ VULKAN_INTERNAL_SetMemoryBarrierFlags(
|
|
|
+ destinationUsageMode,
|
|
|
+ &dstStages,
|
|
|
+ &memoryBarrier.dstAccessMask);
|
|
|
|
|
|
renderer->vkCmdPipelineBarrier(
|
|
|
commandBuffer->commandBuffer,
|
|
|
@@ -2903,27 +2906,38 @@ static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
|
|
textureSubresource->parent);
|
|
|
}
|
|
|
|
|
|
-static VulkanBufferUsageMode VULKAN_INTERNAL_DefaultBufferUsageMode(
|
|
|
+static VulkanBufferUsageModeFlags VULKAN_INTERNAL_DefaultBufferUsageMode(
|
|
|
VulkanBuffer *buffer)
|
|
|
{
|
|
|
- // NOTE: order matters here!
|
|
|
+ VulkanBufferUsageModeFlags flags = 0;
|
|
|
|
|
|
if (buffer->usage & SDL_GPU_BUFFERUSAGE_VERTEX) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ;
|
|
|
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDEX) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_INDEX_READ;
|
|
|
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_INDIRECT;
|
|
|
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ;
|
|
|
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ;
|
|
|
- } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
|
|
|
- return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE;
|
|
|
- } else {
|
|
|
+ flags |= VULKAN_BUFFER_USAGE_MODE_VERTEX_READ;
|
|
|
+ }
|
|
|
+ if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDEX) {
|
|
|
+ flags |= VULKAN_BUFFER_USAGE_MODE_INDEX_READ;
|
|
|
+ }
|
|
|
+ if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) {
|
|
|
+ flags |= VULKAN_BUFFER_USAGE_MODE_INDIRECT;
|
|
|
+ }
|
|
|
+ if (buffer->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) {
|
|
|
+ flags |= VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ;
|
|
|
+ }
|
|
|
+ if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) {
|
|
|
+ flags |= VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If no read flags are set, read-write can be the default.
|
|
|
+ if (!flags && buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
|
|
|
+ flags = VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!flags) {
|
|
|
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!");
|
|
|
return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ;
|
|
|
}
|
|
|
+
|
|
|
+ return flags;
|
|
|
}
|
|
|
|
|
|
static VulkanTextureUsageMode VULKAN_INTERNAL_DefaultTextureUsageMode(
|
|
|
@@ -2955,7 +2969,7 @@ static VulkanTextureUsageMode VULKAN_INTERNAL_DefaultTextureUsageMode(
|
|
|
static void VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
|
|
|
VulkanRenderer *renderer,
|
|
|
VulkanCommandBuffer *commandBuffer,
|
|
|
- VulkanBufferUsageMode destinationUsageMode,
|
|
|
+ VulkanBufferUsageModeFlags destinationUsageMode,
|
|
|
VulkanBuffer *buffer)
|
|
|
{
|
|
|
VULKAN_INTERNAL_BufferMemoryBarrier(
|
|
|
@@ -2969,7 +2983,7 @@ static void VULKAN_INTERNAL_BufferTransitionFromDefaultUsage(
|
|
|
static void VULKAN_INTERNAL_BufferTransitionToDefaultUsage(
|
|
|
VulkanRenderer *renderer,
|
|
|
VulkanCommandBuffer *commandBuffer,
|
|
|
- VulkanBufferUsageMode sourceUsageMode,
|
|
|
+ VulkanBufferUsageModeFlags sourceUsageMode,
|
|
|
VulkanBuffer *buffer)
|
|
|
{
|
|
|
VULKAN_INTERNAL_BufferMemoryBarrier(
|
|
|
@@ -6102,7 +6116,7 @@ static VulkanBuffer *VULKAN_INTERNAL_PrepareBufferForWrite(
|
|
|
VulkanCommandBuffer *commandBuffer,
|
|
|
VulkanBufferContainer *bufferContainer,
|
|
|
bool cycle,
|
|
|
- VulkanBufferUsageMode destinationUsageMode)
|
|
|
+ VulkanBufferUsageModeFlags destinationUsageMode)
|
|
|
{
|
|
|
if (
|
|
|
cycle &&
|