Vulkan: Support 'desired' vs 'required' memory flags (Fix #9310)

When selecting a memory type, there are some property flags we need
(e.g., VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, without which we cannot
vkMapMemory), and others we'd simply prefer (e.g.,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, which may have a performance
impact, but otherwise shouldn't be required).

By specifying these separately, we can fall back to a memory type which
doesn't have everything we want, but which should still work, rather
than giving up.

Signed-off-by: David Gow <david@ingeniumdigital.com>
This commit is contained in:
David Gow
2024-02-25 17:25:59 +08:00
committed by Sam Lantinga
parent 1558d52a0a
commit c172fb5972

View File

@@ -408,7 +408,7 @@ static void VULKAN_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture);
static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer *vulkanBuffer);
static void VULKAN_DestroyImage(VULKAN_RenderData *rendererData, VULKAN_Image *vulkanImage);
static void VULKAN_ResetCommandList(VULKAN_RenderData *rendererData);
static SDL_bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags flags, uint32_t *memoryTypeIndexOut);
static SDL_bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut);
static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer);
static void VULKAN_DestroyAll(SDL_Renderer *renderer)
@@ -578,7 +578,7 @@ static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer
SDL_memset(vulkanBuffer, 0, sizeof(VULKAN_Buffer));
}
static VkResult VULKAN_AllocateBuffer(VULKAN_RenderData *rendererData, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProps, VULKAN_Buffer *bufferOut)
static VkResult VULKAN_AllocateBuffer(VULKAN_RenderData *rendererData, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags requiredMemoryProps, VkMemoryPropertyFlags desiredMemoryProps, VULKAN_Buffer *bufferOut)
{
VkResult result;
VkBufferCreateInfo bufferCreateInfo = { 0 };
@@ -600,7 +600,7 @@ static VkResult VULKAN_AllocateBuffer(VULKAN_RenderData *rendererData, VkDeviceS
}
uint32_t memoryTypeIndex = 0;
if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, memoryProps, &memoryTypeIndex)) {
if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, requiredMemoryProps, desiredMemoryProps, &memoryTypeIndex)) {
VULKAN_DestroyBuffer(rendererData, bufferOut);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "VULKAN_FindMemoryTypeIndex failed.\n");
return VK_ERROR_UNKNOWN;;
@@ -697,7 +697,7 @@ static VkResult VULKAN_AllocateImage(VULKAN_RenderData *rendererData, uint32_t w
}
uint32_t memoryTypeIndex = 0;
if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex)) {
if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex)) {
VULKAN_DestroyImage(rendererData, imageOut);
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "VULKAN_FindMemoryTypeIndex failed.\n");
return VK_ERROR_UNKNOWN;
@@ -1157,13 +1157,17 @@ static VULKAN_PipelineState *VULKAN_CreatePipelineState(SDL_Renderer *renderer,
return &pipelineStates[rendererData->pipelineStateCount - 1];
}
static SDL_bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags flags, uint32_t *memoryTypeIndexOut)
static SDL_bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut)
{
uint32_t memoryTypeIndex = 0;
SDL_bool foundExactMatch = SDL_FALSE;
/* Desired flags must be a superset of required flags. */
desiredFlags |= requiredFlags;
for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) {
if (typeBits & (1 << memoryTypeIndex)) {
if (rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags == flags) {
if (rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags == desiredFlags) {
foundExactMatch = SDL_TRUE;
break;
}
@@ -1172,7 +1176,7 @@ static SDL_bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint
if (!foundExactMatch) {
for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) {
if (typeBits & (1 << memoryTypeIndex)) {
if ((rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & flags) == flags) {
if ((rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & requiredFlags) == requiredFlags) {
break;
}
}
@@ -1195,9 +1199,9 @@ static VkResult VULKAN_CreateVertexBuffer(VULKAN_RenderData *rendererData, size_
result = VULKAN_AllocateBuffer(rendererData, size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&rendererData->vertexBuffers[vbidx]);
if (result != VK_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_RENDER, "VULKAN_AllocateBuffer(): %s\n", SDL_Vulkan_GetResultString(result));
@@ -2190,9 +2194,9 @@ static VkResult VULKAN_CreateSwapChain(SDL_Renderer *renderer, int w, int h)
result = VULKAN_AllocateBuffer(rendererData,
SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&rendererData->constantBuffers[i]);
if (result != VK_SUCCESS) {
VULKAN_DestroyAll(renderer);
@@ -2488,9 +2492,9 @@ static VkResult VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, Vk
result = VULKAN_AllocateBuffer(rendererData, uploadBufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
uploadBuffer);
if (result != VK_SUCCESS) {
return result;
@@ -2699,9 +2703,9 @@ static int VULKAN_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
result = VULKAN_AllocateBuffer(rendererData,
stagingBufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&textureData->stagingBuffer);
if (result != VK_SUCCESS) {
return SDL_SetError("[Vulkan] VULKAN_AllocateBuffer with result %s", SDL_Vulkan_GetResultString(result));
@@ -3539,9 +3543,9 @@ static SDL_Surface* VULKAN_RenderReadPixels(SDL_Renderer *renderer, const SDL_Re
readbackBufferSize = length * rect->h;
if (VULKAN_AllocateBuffer(rendererData, readbackBufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
&readbackBuffer) != VK_SUCCESS) {
SDL_SetError("[Vulkan] Failed to allocate buffer for readback.");
return NULL;