mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-25 06:18:40 +00:00
GPU: Refactor Vulkan barriers to fix defrag segfault (#15593)
This commit is contained in:
@@ -641,6 +641,11 @@ struct VulkanTexture
|
||||
VkImageAspectFlags aspectFlags;
|
||||
Uint32 depth; // used for cleanup only
|
||||
|
||||
// used to avoid indirection on barriers
|
||||
Uint32 levelCount;
|
||||
Uint32 layerCount;
|
||||
SDL_GPUTextureType type;
|
||||
|
||||
// FIXME: It'd be nice if we didn't have to have this on the texture...
|
||||
SDL_GPUTextureUsageFlags usage; // used for defrag transitions only.
|
||||
|
||||
@@ -2723,12 +2728,16 @@ static void VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
buffer->transitioned = true;
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
||||
static void VULKAN_INTERNAL_TextureMemoryBarrier(
|
||||
VulkanRenderer *renderer,
|
||||
VulkanCommandBuffer *commandBuffer,
|
||||
VulkanTextureUsageMode sourceUsageMode,
|
||||
VulkanTextureUsageMode destinationUsageMode,
|
||||
VulkanTextureSubresource *textureSubresource)
|
||||
Uint32 baseLevel,
|
||||
Uint32 levelCount,
|
||||
Uint32 baseLayer,
|
||||
Uint32 layerCount,
|
||||
VulkanTexture *texture)
|
||||
{
|
||||
VkPipelineStageFlags srcStages = 0;
|
||||
VkPipelineStageFlags dstStages = 0;
|
||||
@@ -2742,21 +2751,12 @@ static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
||||
memoryBarrier.newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
memoryBarrier.image = textureSubresource->parent->image;
|
||||
memoryBarrier.subresourceRange.aspectMask = textureSubresource->parent->aspectFlags;
|
||||
memoryBarrier.subresourceRange.baseMipLevel = textureSubresource->level;
|
||||
memoryBarrier.subresourceRange.levelCount = 1;
|
||||
memoryBarrier.subresourceRange.baseArrayLayer = textureSubresource->layer;
|
||||
memoryBarrier.subresourceRange.layerCount = 1;
|
||||
|
||||
// VK_KHR_maintenance9 adds the ability to independently transition arbitrary subsets of slices in a 3D texture
|
||||
// but otherwise it is not necessarily supported by the driver.
|
||||
// As a workaround we have to transition the whole texture instead of just the subresource.
|
||||
// If VK_KHR_maintenance9 becomes widely supported, this can be removed.
|
||||
// See https://docs.vulkan.org/features/latest/features/proposals/VK_KHR_maintenance9.html#_barriers_with_2d_array_compatible_3d_images
|
||||
if (textureSubresource->parent->container->header.info.type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
memoryBarrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
}
|
||||
memoryBarrier.image = texture->image;
|
||||
memoryBarrier.subresourceRange.aspectMask = texture->aspectFlags;
|
||||
memoryBarrier.subresourceRange.baseMipLevel = baseLevel;
|
||||
memoryBarrier.subresourceRange.levelCount = levelCount;
|
||||
memoryBarrier.subresourceRange.baseArrayLayer = baseLayer;
|
||||
memoryBarrier.subresourceRange.layerCount = layerCount;
|
||||
|
||||
if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED) {
|
||||
srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
@@ -2853,6 +2853,56 @@ static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
||||
&memoryBarrier);
|
||||
}
|
||||
|
||||
// Transitions the entire texture with a single barrier call.
|
||||
static void VULKAN_INTERNAL_FullTextureMemoryBarrier(
|
||||
VulkanRenderer *renderer,
|
||||
VulkanCommandBuffer *commandBuffer,
|
||||
VulkanTextureUsageMode sourceUsageMode,
|
||||
VulkanTextureUsageMode destinationUsageMode,
|
||||
VulkanTexture *texture)
|
||||
{
|
||||
VULKAN_INTERNAL_TextureMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
sourceUsageMode,
|
||||
destinationUsageMode,
|
||||
0,
|
||||
texture->levelCount,
|
||||
0,
|
||||
texture->layerCount,
|
||||
texture);
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
||||
VulkanRenderer *renderer,
|
||||
VulkanCommandBuffer *commandBuffer,
|
||||
VulkanTextureUsageMode sourceUsageMode,
|
||||
VulkanTextureUsageMode destinationUsageMode,
|
||||
VulkanTextureSubresource *textureSubresource)
|
||||
{
|
||||
Uint32 layerCount = 1;
|
||||
|
||||
// VK_KHR_maintenance9 adds the ability to independently transition arbitrary subsets of slices in a 3D texture
|
||||
// but otherwise it is not necessarily supported by the driver.
|
||||
// As a workaround we have to transition the whole texture instead of just the subresource.
|
||||
// If VK_KHR_maintenance9 becomes widely supported, this can be removed.
|
||||
// See https://docs.vulkan.org/features/latest/features/proposals/VK_KHR_maintenance9.html#_barriers_with_2d_array_compatible_3d_images
|
||||
if (textureSubresource->parent->type == SDL_GPU_TEXTURETYPE_3D) {
|
||||
layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
}
|
||||
|
||||
VULKAN_INTERNAL_TextureMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
sourceUsageMode,
|
||||
destinationUsageMode,
|
||||
textureSubresource->level,
|
||||
1,
|
||||
textureSubresource->layer,
|
||||
layerCount,
|
||||
textureSubresource->parent);
|
||||
}
|
||||
|
||||
static VulkanBufferUsageMode VULKAN_INTERNAL_DefaultBufferUsageMode(
|
||||
VulkanBuffer *buffer)
|
||||
{
|
||||
@@ -2950,13 +3000,12 @@ static void VULKAN_INTERNAL_TextureTransitionFromDefaultUsage(
|
||||
VulkanTextureUsageMode destinationUsageMode,
|
||||
VulkanTexture *texture)
|
||||
{
|
||||
for (Uint32 i = 0; i < texture->subresourceCount; i += 1) {
|
||||
VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
destinationUsageMode,
|
||||
&texture->subresources[i]);
|
||||
}
|
||||
VULKAN_INTERNAL_FullTextureMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_INTERNAL_DefaultTextureUsageMode(texture),
|
||||
destinationUsageMode,
|
||||
texture);
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
|
||||
@@ -2979,14 +3028,12 @@ static void VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
|
||||
VulkanTextureUsageMode sourceUsageMode,
|
||||
VulkanTexture *texture)
|
||||
{
|
||||
// FIXME: could optimize this barrier
|
||||
for (Uint32 i = 0; i < texture->subresourceCount; i += 1) {
|
||||
VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
sourceUsageMode,
|
||||
&texture->subresources[i]);
|
||||
}
|
||||
VULKAN_INTERNAL_FullTextureMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
sourceUsageMode,
|
||||
VULKAN_INTERNAL_DefaultTextureUsageMode(texture),
|
||||
texture);
|
||||
}
|
||||
|
||||
// Resource Disposal
|
||||
@@ -5738,6 +5785,9 @@ static VulkanTexture *VULKAN_INTERNAL_CreateTexture(
|
||||
texture->swizzle = SwizzleForSDLFormat(createinfo->format);
|
||||
texture->depth = depth;
|
||||
texture->usage = createinfo->usage;
|
||||
texture->levelCount = createinfo->num_levels;
|
||||
texture->layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth;
|
||||
texture->type = createinfo->type;
|
||||
SDL_SetAtomicInt(&texture->referenceCount, 0);
|
||||
|
||||
if (IsDepthFormat(createinfo->format)) {
|
||||
@@ -6959,7 +7009,9 @@ static SDL_GPUTexture *VULKAN_CreateTexture(
|
||||
barrierCommandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
|
||||
texture);
|
||||
|
||||
VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture);
|
||||
|
||||
if (!VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer)) {
|
||||
VULKAN_ReleaseTexture((SDL_GPURenderer *)renderer, (SDL_GPUTexture *)container);
|
||||
return NULL;
|
||||
@@ -8402,7 +8454,6 @@ static void VULKAN_BindComputeStorageTextures(
|
||||
VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ,
|
||||
textureContainer->activeTexture);
|
||||
|
||||
|
||||
VULKAN_INTERNAL_TrackTexture(
|
||||
vulkanCommandBuffer,
|
||||
textureContainer->activeTexture);
|
||||
@@ -11119,24 +11170,26 @@ static bool VULKAN_INTERNAL_DefragmentMemory(
|
||||
}
|
||||
|
||||
SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info;
|
||||
|
||||
VULKAN_INTERNAL_TextureTransitionFromDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
|
||||
currentRegion->vulkanTexture);
|
||||
|
||||
VULKAN_INTERNAL_FullTextureMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
|
||||
newTexture
|
||||
);
|
||||
|
||||
// Can only copy one mip level at a time
|
||||
for (Uint32 subresourceIndex = 0; subresourceIndex < currentRegion->vulkanTexture->subresourceCount; subresourceIndex += 1) {
|
||||
// copy subresource if necessary
|
||||
VulkanTextureSubresource *srcSubresource = ¤tRegion->vulkanTexture->subresources[subresourceIndex];
|
||||
VulkanTextureSubresource *dstSubresource = &newTexture->subresources[subresourceIndex];
|
||||
|
||||
VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE,
|
||||
srcSubresource);
|
||||
|
||||
VULKAN_INTERNAL_TextureSubresourceMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
|
||||
dstSubresource);
|
||||
|
||||
VkImageCopy imageCopy;
|
||||
imageCopy.srcOffset.x = 0;
|
||||
imageCopy.srcOffset.y = 0;
|
||||
@@ -11165,16 +11218,16 @@ static bool VULKAN_INTERNAL_DefragmentMemory(
|
||||
1,
|
||||
&imageCopy);
|
||||
|
||||
VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
|
||||
dstSubresource);
|
||||
|
||||
VULKAN_INTERNAL_TrackTexture(commandBuffer, srcSubresource->parent);
|
||||
VULKAN_INTERNAL_TrackTexture(commandBuffer, dstSubresource->parent);
|
||||
}
|
||||
|
||||
VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
|
||||
renderer,
|
||||
commandBuffer,
|
||||
VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION,
|
||||
newTexture);
|
||||
|
||||
// re-point original container to new texture
|
||||
newTexture->container = currentRegion->vulkanTexture->container;
|
||||
newTexture->containerIndex = currentRegion->vulkanTexture->containerIndex;
|
||||
|
||||
Reference in New Issue
Block a user