texture alloc fallback to host memory

submit_rewrite
cosmonaut 2021-01-27 12:51:36 -08:00
parent 68d9a74ff4
commit 6457967470
1 changed files with 291 additions and 124 deletions

View File

@ -758,7 +758,6 @@ typedef struct VulkanTexture
uint32_t layerCount; uint32_t layerCount;
uint32_t levelCount; uint32_t levelCount;
VkFormat format; VkFormat format;
Refresh_TextureFormat refreshFormat;
VulkanResourceAccessType resourceAccessType; VulkanResourceAccessType resourceAccessType;
uint32_t queueFamilyIndex; uint32_t queueFamilyIndex;
VkImageUsageFlags usageFlags; VkImageUsageFlags usageFlags;
@ -1473,7 +1472,7 @@ static inline const char* VkErrorMessages(VkResult code)
#undef ERR_TO_STR #undef ERR_TO_STR
} }
static inline void LogVulkanResult( static inline void LogVulkanResultAsError(
const char* vulkanFunctionName, const char* vulkanFunctionName,
VkResult result VkResult result
) { ) {
@ -1487,16 +1486,30 @@ static inline void LogVulkanResult(
} }
} }
static inline void LogVulkanResultAsWarn(
const char* vulkanFunctionName,
VkResult result
) {
if (result != VK_SUCCESS)
{
Refresh_LogWarn(
"%s: %s",
vulkanFunctionName,
VkErrorMessages(result)
);
}
}
/* Utility */ /* Utility */
static inline uint8_t IsDepthFormat(Refresh_TextureFormat format) static inline uint8_t IsDepthFormat(VkFormat format)
{ {
switch(format) switch(format)
{ {
case REFRESH_TEXTUREFORMAT_D16_UNORM: case VK_FORMAT_D16_UNORM:
case REFRESH_TEXTUREFORMAT_D32_SFLOAT: case VK_FORMAT_D32_SFLOAT:
case REFRESH_TEXTUREFORMAT_D16_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM_S8_UINT:
case REFRESH_TEXTUREFORMAT_D32_SFLOAT_S8_UINT: case VK_FORMAT_D32_SFLOAT_S8_UINT:
return 1; return 1;
default: default:
@ -1504,12 +1517,12 @@ static inline uint8_t IsDepthFormat(Refresh_TextureFormat format)
} }
} }
static inline uint8_t IsStencilFormat(Refresh_TextureFormat format) static inline uint8_t IsStencilFormat(VkFormat format)
{ {
switch(format) switch(format)
{ {
case REFRESH_TEXTUREFORMAT_D16_UNORM_S8_UINT: case VK_FORMAT_D16_UNORM_S8_UINT:
case REFRESH_TEXTUREFORMAT_D32_SFLOAT_S8_UINT: case VK_FORMAT_D32_SFLOAT_S8_UINT:
return 1; return 1;
default: default:
@ -1517,6 +1530,37 @@ static inline uint8_t IsStencilFormat(Refresh_TextureFormat format)
} }
} }
static inline uint8_t ImageFormatCanBeCPUAllocated(VkFormat format)
{
switch (format)
{
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
case VK_FORMAT_BC2_SRGB_BLOCK:
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC3_SRGB_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC4_SNORM_BLOCK:
case VK_FORMAT_BC4_UNORM_BLOCK:
case VK_FORMAT_BC5_SNORM_BLOCK:
case VK_FORMAT_BC5_UNORM_BLOCK:
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
case VK_FORMAT_BC7_SRGB_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
return 0;
default:
return 1;
}
}
/* Memory Management */ /* Memory Management */
static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment( static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment(
@ -1689,6 +1733,7 @@ static uint8_t VULKAN_INTERNAL_FindBufferMemoryRequirements(
static uint8_t VULKAN_INTERNAL_FindImageMemoryRequirements( static uint8_t VULKAN_INTERNAL_FindImageMemoryRequirements(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VkImage image, VkImage image,
VkMemoryPropertyFlags memoryPropertyFlags,
VkMemoryRequirements2KHR *pMemoryRequirements, VkMemoryRequirements2KHR *pMemoryRequirements,
uint32_t *pMemoryTypeIndex uint32_t *pMemoryTypeIndex
) { ) {
@ -1707,7 +1752,7 @@ static uint8_t VULKAN_INTERNAL_FindImageMemoryRequirements(
if (!VULKAN_INTERNAL_FindMemoryType( if (!VULKAN_INTERNAL_FindMemoryType(
renderer, renderer,
pMemoryRequirements->memoryRequirements.memoryTypeBits, pMemoryRequirements->memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memoryPropertyFlags,
pMemoryTypeIndex pMemoryTypeIndex
)) { )) {
Refresh_LogError( Refresh_LogError(
@ -1726,6 +1771,7 @@ static uint8_t VULKAN_INTERNAL_AllocateMemory(
uint32_t memoryTypeIndex, uint32_t memoryTypeIndex,
VkDeviceSize allocationSize, VkDeviceSize allocationSize,
uint8_t dedicated, uint8_t dedicated,
uint8_t cpuAllocation,
VulkanMemoryAllocation **pMemoryAllocation VulkanMemoryAllocation **pMemoryAllocation
) { ) {
VulkanMemoryAllocation *allocation; VulkanMemoryAllocation *allocation;
@ -1758,7 +1804,6 @@ static uint8_t VULKAN_INTERNAL_AllocateMemory(
{ {
allocInfo.pNext = NULL; allocInfo.pNext = NULL;
/* allocate a non-dedicated texture buffer */
allocator->allocationCount += 1; allocator->allocationCount += 1;
allocator->allocations = SDL_realloc( allocator->allocations = SDL_realloc(
allocator->allocations, allocator->allocations,
@ -1786,11 +1831,23 @@ static uint8_t VULKAN_INTERNAL_AllocateMemory(
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
LogVulkanResult("vkAllocateMemory", result); /* Uh oh, we couldn't allocate, time to clean up */
SDL_free(allocation->freeRegions);
allocator->allocationCount -= 1;
allocator->allocations = SDL_realloc(
allocator->allocations,
sizeof(VulkanMemoryAllocation*) * allocator->allocationCount
);
SDL_free(allocation);
LogVulkanResultAsWarn("vkAllocateMemory", result);
return 0; return 0;
} }
if (buffer != NULL) /* persistent mapping for host memory */
if (cpuAllocation)
{ {
result = renderer->vkMapMemory( result = renderer->vkMapMemory(
renderer->logicalDevice, renderer->logicalDevice,
@ -1803,7 +1860,7 @@ static uint8_t VULKAN_INTERNAL_AllocateMemory(
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
LogVulkanResult("vkMapMemory", result); LogVulkanResultAsError("vkMapMemory", result);
return 0; return 0;
} }
} }
@ -1824,70 +1881,30 @@ static uint8_t VULKAN_INTERNAL_AllocateMemory(
static uint8_t VULKAN_INTERNAL_FindAvailableMemory( static uint8_t VULKAN_INTERNAL_FindAvailableMemory(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VkBuffer buffer, uint32_t memoryTypeIndex,
VkImage image, uint8_t cpuAllocation,
VkMemoryRequirements2KHR *memoryRequirements,
VkMemoryDedicatedRequirementsKHR *dedicatedRequirements,
VkBuffer buffer, /* may be VK_NULL_HANDLE */
VkImage image, /* may be VK_NULL_HANDLE */
VulkanMemoryAllocation **pMemoryAllocation, VulkanMemoryAllocation **pMemoryAllocation,
VkDeviceSize *pOffset, VkDeviceSize *pOffset,
VkDeviceSize *pSize VkDeviceSize *pSize
) { ) {
VkMemoryDedicatedRequirementsKHR dedicatedRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR,
NULL
};
VkMemoryRequirements2KHR memoryRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR,
&dedicatedRequirements
};
uint32_t memoryTypeIndex;
VulkanMemoryAllocation *allocation; VulkanMemoryAllocation *allocation;
VulkanMemorySubAllocator *allocator; VulkanMemorySubAllocator *allocator;
VulkanMemoryFreeRegion *region; VulkanMemoryFreeRegion *region;
VkDeviceSize requiredSize, allocationSize; VkDeviceSize requiredSize, allocationSize;
VkDeviceSize alignedOffset; VkDeviceSize alignedOffset;
VkDeviceSize newRegionSize, newRegionOffset; uint32_t newRegionSize, newRegionOffset;
uint8_t shouldAllocDedicated =
dedicatedRequirements->prefersDedicatedAllocation ||
dedicatedRequirements->requiresDedicatedAllocation;
uint8_t allocationResult; uint8_t allocationResult;
if (buffer != VK_NULL_HANDLE && image != VK_NULL_HANDLE)
{
Refresh_LogError("Calling FindAvailableMemory with both a buffer and image handle is invalid!");
return 0;
}
else if (buffer != VK_NULL_HANDLE)
{
if (!VULKAN_INTERNAL_FindBufferMemoryRequirements(
renderer,
buffer,
&memoryRequirements,
&memoryTypeIndex
)) {
Refresh_LogError("Failed to acquire buffer memory requirements!");
return 0;
}
}
else if (image != VK_NULL_HANDLE)
{
if (!VULKAN_INTERNAL_FindImageMemoryRequirements(
renderer,
image,
&memoryRequirements,
&memoryTypeIndex
)) {
Refresh_LogError("Failed to acquire image memory requirements!");
return 0;
}
}
else
{
Refresh_LogError("Calling FindAvailableMemory with neither buffer nor image handle is invalid!");
return 0;
}
allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex];
requiredSize = memoryRequirements.memoryRequirements.size; requiredSize = memoryRequirements->memoryRequirements.size;
SDL_LockMutex(renderer->allocatorLock); SDL_LockMutex(renderer->allocatorLock);
@ -1899,7 +1916,7 @@ static uint8_t VULKAN_INTERNAL_FindAvailableMemory(
alignedOffset = VULKAN_INTERNAL_NextHighestAlignment( alignedOffset = VULKAN_INTERNAL_NextHighestAlignment(
region->offset, region->offset,
memoryRequirements.memoryRequirements.alignment memoryRequirements->memoryRequirements.alignment
); );
if (alignedOffset + requiredSize <= region->offset + region->size) if (alignedOffset + requiredSize <= region->offset + region->size)
@ -1943,7 +1960,7 @@ static uint8_t VULKAN_INTERNAL_FindAvailableMemory(
/* No suitable free regions exist, allocate a new memory region */ /* No suitable free regions exist, allocate a new memory region */
if (dedicatedRequirements.prefersDedicatedAllocation || dedicatedRequirements.requiresDedicatedAllocation) if (shouldAllocDedicated)
{ {
allocationSize = requiredSize; allocationSize = requiredSize;
} }
@ -1965,17 +1982,18 @@ static uint8_t VULKAN_INTERNAL_FindAvailableMemory(
image, image,
memoryTypeIndex, memoryTypeIndex,
allocationSize, allocationSize,
dedicatedRequirements.prefersDedicatedAllocation || dedicatedRequirements.requiresDedicatedAllocation, shouldAllocDedicated,
cpuAllocation,
&allocation &allocation
); );
/* Uh oh, we're out of memory */ /* Uh oh, we're out of memory */
if (allocationResult == 0) if (allocationResult == 0)
{ {
/* Responsibility of the caller to handle being out of memory */
Refresh_LogWarn("Failed to allocate memory!");
SDL_UnlockMutex(renderer->allocatorLock); SDL_UnlockMutex(renderer->allocatorLock);
/* Responsibility of the caller to handle being out of memory */
Refresh_LogWarn("Failed to allocate memory!");
return 2; return 2;
} }
@ -2004,6 +2022,106 @@ static uint8_t VULKAN_INTERNAL_FindAvailableMemory(
return 1; return 1;
} }
static uint8_t VULKAN_INTERNAL_FindAvailableBufferMemory(
VulkanRenderer *renderer,
VkBuffer buffer,
VulkanMemoryAllocation **pMemoryAllocation,
VkDeviceSize *pOffset,
VkDeviceSize *pSize
) {
uint32_t memoryTypeIndex;
VkMemoryDedicatedRequirementsKHR dedicatedRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR,
NULL
};
VkMemoryRequirements2KHR memoryRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR,
&dedicatedRequirements
};
if (!VULKAN_INTERNAL_FindBufferMemoryRequirements(
renderer,
buffer,
&memoryRequirements,
&memoryTypeIndex
)) {
Refresh_LogError("Failed to acquire buffer memory requirements!");
return 0;
}
return VULKAN_INTERNAL_FindAvailableMemory(
renderer,
memoryTypeIndex,
1,
&memoryRequirements,
&dedicatedRequirements,
buffer,
VK_NULL_HANDLE,
pMemoryAllocation,
pOffset,
pSize
);
}
static uint8_t VULKAN_INTERNAL_FindAvailableTextureMemory(
VulkanRenderer *renderer,
VkImage image,
uint8_t cpuAllocation,
VulkanMemoryAllocation **pMemoryAllocation,
VkDeviceSize *pOffset,
VkDeviceSize *pSize
) {
uint32_t memoryTypeIndex;
VkMemoryPropertyFlags memoryPropertyFlags;
VkMemoryDedicatedRequirementsKHR dedicatedRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR,
NULL
};
VkMemoryRequirements2KHR memoryRequirements =
{
VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR,
&dedicatedRequirements
};
if (cpuAllocation)
{
memoryPropertyFlags =
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
}
else
{
memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
if (!VULKAN_INTERNAL_FindImageMemoryRequirements(
renderer,
image,
memoryPropertyFlags,
&memoryRequirements,
&memoryTypeIndex
)) {
Refresh_LogError("Failed to acquire image memory requirements!");
return 0;
}
return VULKAN_INTERNAL_FindAvailableMemory(
renderer,
memoryTypeIndex,
cpuAllocation,
&memoryRequirements,
&dedicatedRequirements,
VK_NULL_HANDLE,
image,
pMemoryAllocation,
pOffset,
pSize
);
}
/* Memory Barriers */ /* Memory Barriers */
static void VULKAN_INTERNAL_BufferMemoryBarrier( static void VULKAN_INTERNAL_BufferMemoryBarrier(
@ -3108,7 +3226,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateSwapchainKHR", vulkanResult); LogVulkanResultAsError("vkCreateSwapchainKHR", vulkanResult);
return CREATE_SWAPCHAIN_FAIL; return CREATE_SWAPCHAIN_FAIL;
} }
@ -3190,7 +3308,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateImageView", vulkanResult); LogVulkanResultAsError("vkCreateImageView", vulkanResult);
SDL_stack_free(swapChainImages); SDL_stack_free(swapChainImages);
return CREATE_SWAPCHAIN_FAIL; return CREATE_SWAPCHAIN_FAIL;
} }
@ -3293,15 +3411,14 @@ static uint8_t VULKAN_INTERNAL_CreateBuffer(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateBuffer", vulkanResult); LogVulkanResultAsError("vkCreateBuffer", vulkanResult);
Refresh_LogError("Failed to create VkBuffer"); Refresh_LogError("Failed to create VkBuffer");
return 0; return 0;
} }
findMemoryResult = VULKAN_INTERNAL_FindAvailableMemory( findMemoryResult = VULKAN_INTERNAL_FindAvailableBufferMemory(
renderer, renderer,
buffer->subBuffers[i]->buffer, buffer->subBuffers[i]->buffer,
VK_NULL_HANDLE,
&buffer->subBuffers[i]->allocation, &buffer->subBuffers[i]->allocation,
&buffer->subBuffers[i]->offset, &buffer->subBuffers[i]->offset,
&buffer->subBuffers[i]->size &buffer->subBuffers[i]->size
@ -3369,7 +3486,7 @@ static void VULKAN_INTERNAL_BeginCommandBuffer(
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
LogVulkanResult("vkBeginCommandBuffer", result); LogVulkanResultAsError("vkBeginCommandBuffer", result);
} }
} }
@ -3385,7 +3502,7 @@ static void VULKAN_INTERNAL_EndCommandBuffer(
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
{ {
LogVulkanResult("vkEndCommandBuffer", result); LogVulkanResultAsError("vkEndCommandBuffer", result);
} }
commandBuffer->currentComputePipeline = NULL; commandBuffer->currentComputePipeline = NULL;
@ -3409,7 +3526,7 @@ static void VULKAN_DestroyDevice(
if (waitResult != VK_SUCCESS) if (waitResult != VK_SUCCESS)
{ {
LogVulkanResult("vkDeviceWaitIdle", waitResult); LogVulkanResultAsError("vkDeviceWaitIdle", waitResult);
} }
VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyVertexUniformBuffer); VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyVertexUniformBuffer);
@ -4146,7 +4263,7 @@ static Refresh_RenderPass* VULKAN_CreateRenderPass(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateRenderPass", vulkanResult); LogVulkanResultAsError("vkCreateRenderPass", vulkanResult);
return NULL_RENDER_PASS; return NULL_RENDER_PASS;
} }
@ -4184,7 +4301,7 @@ static uint8_t VULKAN_INTERNAL_CreateDescriptorPool(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateDescriptorPool", vulkanResult); LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult);
return 0; return 0;
} }
@ -4224,7 +4341,7 @@ static uint8_t VULKAN_INTERNAL_AllocateDescriptorSets(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkAllocateDescriptorSets", vulkanResult); LogVulkanResultAsError("vkAllocateDescriptorSets", vulkanResult);
SDL_stack_free(descriptorSetLayouts); SDL_stack_free(descriptorSetLayouts);
return 0; return 0;
} }
@ -4427,7 +4544,7 @@ static VkDescriptorSetLayout VULKAN_INTERNAL_FetchDescriptorSetLayout(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateDescriptorSetLayout", vulkanResult); LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult);
return NULL_DESC_LAYOUT; return NULL_DESC_LAYOUT;
} }
@ -4504,7 +4621,7 @@ static VulkanGraphicsPipelineLayout* VULKAN_INTERNAL_FetchGraphicsPipelineLayout
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreatePipelineLayout", vulkanResult); LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult);
return NULL; return NULL;
} }
@ -4891,7 +5008,7 @@ static Refresh_GraphicsPipeline* VULKAN_CreateGraphicsPipeline(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateGraphicsPipelines", vulkanResult); LogVulkanResultAsError("vkCreateGraphicsPipelines", vulkanResult);
Refresh_LogError("Failed to create graphics pipeline!"); Refresh_LogError("Failed to create graphics pipeline!");
SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputBindingDescriptions);
@ -5053,7 +5170,7 @@ static VulkanComputePipelineLayout* VULKAN_INTERNAL_FetchComputePipelineLayout(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreatePipelineLayout", vulkanResult); LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult);
return NULL; return NULL;
} }
@ -5254,7 +5371,7 @@ static Refresh_Sampler* VULKAN_CreateSampler(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateSampler", vulkanResult); LogVulkanResultAsError("vkCreateSampler", vulkanResult);
return NULL; return NULL;
} }
@ -5312,7 +5429,7 @@ static Refresh_Framebuffer* VULKAN_CreateFramebuffer(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateFramebuffer", vulkanResult); LogVulkanResultAsError("vkCreateFramebuffer", vulkanResult);
SDL_stack_free(imageViews); SDL_stack_free(imageViews);
return NULL; return NULL;
} }
@ -5358,7 +5475,7 @@ static Refresh_ShaderModule* VULKAN_CreateShaderModule(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateShaderModule", vulkanResult); LogVulkanResultAsError("vkCreateShaderModule", vulkanResult);
Refresh_LogError("Failed to create shader module!"); Refresh_LogError("Failed to create shader module!");
return NULL; return NULL;
} }
@ -5377,7 +5494,6 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
uint32_t levelCount, uint32_t levelCount,
VkFormat format, VkFormat format,
VkImageAspectFlags aspectMask, VkImageAspectFlags aspectMask,
VkImageTiling tiling,
VkImageType imageType, VkImageType imageType,
VkImageUsageFlags imageUsageFlags, VkImageUsageFlags imageUsageFlags,
VulkanTexture *texture VulkanTexture *texture
@ -5389,6 +5505,9 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
uint8_t findMemoryResult; uint8_t findMemoryResult;
uint8_t is3D = depth > 1 ? 1 : 0; uint8_t is3D = depth > 1 ? 1 : 0;
uint8_t layerCount = isCube ? 6 : 1; uint8_t layerCount = isCube ? 6 : 1;
uint8_t isRenderTarget =
((imageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0) ||
((imageUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0);
VkComponentMapping swizzle = IDENTITY_SWIZZLE; VkComponentMapping swizzle = IDENTITY_SWIZZLE;
texture->isCube = 0; texture->isCube = 0;
@ -5416,9 +5535,8 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
imageCreateInfo.mipLevels = levelCount; imageCreateInfo.mipLevels = levelCount;
imageCreateInfo.arrayLayers = layerCount; imageCreateInfo.arrayLayers = layerCount;
imageCreateInfo.samples = samples; imageCreateInfo.samples = samples;
imageCreateInfo.tiling = tiling; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.usage = imageUsageFlags;
// FIXME: would this interfere with pixel data sharing?
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.queueFamilyIndexCount = 0; imageCreateInfo.queueFamilyIndexCount = 0;
imageCreateInfo.pQueueFamilyIndices = NULL; imageCreateInfo.pQueueFamilyIndices = NULL;
@ -5433,24 +5551,77 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateImage", vulkanResult); LogVulkanResultAsError("vkCreateImage", vulkanResult);
Refresh_LogError("Failed to create texture!"); Refresh_LogError("Failed to create texture!");
} }
findMemoryResult = VULKAN_INTERNAL_FindAvailableMemory( /* Prefer GPU allocation */
findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory(
renderer, renderer,
VK_NULL_HANDLE,
texture->image, texture->image,
0,
&texture->allocation, &texture->allocation,
&texture->offset, &texture->offset,
&texture->memorySize &texture->memorySize
); );
/* No device memory available, time to die */ /* No device local memory available */
if (findMemoryResult == 0 || findMemoryResult == 2) if (findMemoryResult == 2)
{ {
Refresh_LogError("Failed to find texture memory!"); if (isRenderTarget || !ImageFormatCanBeCPUAllocated(format))
return 0; {
Refresh_LogError("Out of device local memory and cannot allocate to host memory!");
return 0;
}
Refresh_LogWarn("Out of device local memory, falling back to host memory");
/* CPU-allocated images need linear tiling
* so we have to destroy our original image and recreate
*/
renderer->vkDestroyImage(
renderer->logicalDevice,
texture->image,
NULL
);
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
vulkanResult = renderer->vkCreateImage(
renderer->logicalDevice,
&imageCreateInfo,
NULL,
&texture->image
);
if (vulkanResult != VK_SUCCESS)
{
LogVulkanResultAsError("vkCreateImage", vulkanResult);
Refresh_LogError("Failed to create image with linear tiling");
return 0;
}
/* Attempt CPU allocation */
findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory(
renderer,
texture->image,
1,
&texture->allocation,
&texture->offset,
&texture->memorySize
);
/* Memory alloc completely failed, time to die */
if (findMemoryResult == 0)
{
Refresh_LogError("Something went very wrong allocating memory!");
return 0;
}
else if (findMemoryResult == 2)
{
Refresh_LogError("Out of memory!");
return 0;
}
} }
SDL_LockMutex(texture->allocation->memoryLock); SDL_LockMutex(texture->allocation->memoryLock);
@ -5466,7 +5637,7 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkBindImageMemory", vulkanResult); LogVulkanResultAsError("vkBindImageMemory", vulkanResult);
Refresh_LogError("Failed to bind texture memory!"); Refresh_LogError("Failed to bind texture memory!");
return 0; return 0;
} }
@ -5509,7 +5680,7 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateImageView", vulkanResult); LogVulkanResultAsError("vkCreateImageView", vulkanResult);
Refresh_LogError("Failed to create texture image view"); Refresh_LogError("Failed to create texture image view");
return 0; return 0;
} }
@ -5565,12 +5736,10 @@ static Refresh_Texture* VULKAN_CreateTexture(
textureCreateInfo->levelCount, textureCreateInfo->levelCount,
RefreshToVK_SurfaceFormat[textureCreateInfo->format], RefreshToVK_SurfaceFormat[textureCreateInfo->format],
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
imageUsageFlags, imageUsageFlags,
result result
); );
result->refreshFormat = textureCreateInfo->format;
return (Refresh_Texture*) result; return (Refresh_Texture*) result;
} }
@ -5592,11 +5761,11 @@ static Refresh_RenderTarget* VULKAN_CreateRenderTarget(
renderTarget->multisampleTexture = NULL; renderTarget->multisampleTexture = NULL;
renderTarget->multisampleCount = 1; renderTarget->multisampleCount = 1;
if (IsDepthFormat(renderTarget->texture->refreshFormat)) if (IsDepthFormat(renderTarget->texture->format))
{ {
aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
if (IsStencilFormat(renderTarget->texture->refreshFormat)) if (IsStencilFormat(renderTarget->texture->format))
{ {
aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
} }
@ -5623,12 +5792,10 @@ static Refresh_RenderTarget* VULKAN_CreateRenderTarget(
1, 1,
renderTarget->texture->format, renderTarget->texture->format,
aspectFlags, aspectFlags,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_TYPE_2D, VK_IMAGE_TYPE_2D,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
renderTarget->multisampleTexture renderTarget->multisampleTexture
); );
renderTarget->multisampleTexture->refreshFormat = renderTarget->texture->refreshFormat;
renderTarget->multisampleCount = multisampleCount; renderTarget->multisampleCount = multisampleCount;
} }
@ -5663,7 +5830,7 @@ static Refresh_RenderTarget* VULKAN_CreateRenderTarget(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult( LogVulkanResultAsError(
"vkCreateImageView", "vkCreateImageView",
vulkanResult vulkanResult
); );
@ -5815,7 +5982,7 @@ static void VULKAN_INTERNAL_FlushTransfers(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkWaitForFences", vulkanResult); LogVulkanResultAsError("vkWaitForFences", vulkanResult);
return; return;
} }
@ -5835,7 +6002,7 @@ static void VULKAN_INTERNAL_FlushTransfers(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkQueueSubmit", vulkanResult); LogVulkanResultAsError("vkQueueSubmit", vulkanResult);
return; return;
} }
@ -5850,7 +6017,7 @@ static void VULKAN_INTERNAL_FlushTransfers(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkWaitForFences", vulkanResult); LogVulkanResultAsError("vkWaitForFences", vulkanResult);
return; return;
} }
@ -7142,7 +7309,7 @@ static void VULKAN_BeginRenderPass(
{ {
depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
if (IsStencilFormat( if (IsStencilFormat(
vulkanFramebuffer->depthStencilTarget->texture->refreshFormat vulkanFramebuffer->depthStencilTarget->texture->format
)) { )) {
depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
} }
@ -7494,7 +7661,7 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkAllocateCommandBuffers", vulkanResult); LogVulkanResultAsError("vkAllocateCommandBuffers", vulkanResult);
SDL_stack_free(commandBuffers); SDL_stack_free(commandBuffers);
return; return;
} }
@ -7551,7 +7718,7 @@ static VulkanCommandPool* VULKAN_INTERNAL_FetchCommandPool(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
Refresh_LogError("Failed to create command pool!"); Refresh_LogError("Failed to create command pool!");
LogVulkanResult("vkCreateCommandPool", vulkanResult); LogVulkanResultAsError("vkCreateCommandPool", vulkanResult);
return NULL; return NULL;
} }
@ -7886,7 +8053,7 @@ static void VULKAN_INTERNAL_ResetCommandBuffer(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkResetCommandBuffer", vulkanResult); LogVulkanResultAsError("vkResetCommandBuffer", vulkanResult);
} }
commandBuffer->submitted = 0; commandBuffer->submitted = 0;
@ -7981,7 +8148,7 @@ static void VULKAN_Submit(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkWaitForFences", vulkanResult); LogVulkanResultAsError("vkWaitForFences", vulkanResult);
return; return;
} }
@ -8019,7 +8186,7 @@ static void VULKAN_Submit(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkQueueSubmit", vulkanResult); LogVulkanResultAsError("vkQueueSubmit", vulkanResult);
return; return;
} }
} }
@ -8034,7 +8201,7 @@ static void VULKAN_Submit(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkQueueSubmit", vulkanResult); LogVulkanResultAsError("vkQueueSubmit", vulkanResult);
return; return;
} }
@ -8857,7 +9024,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateSemaphore", vulkanResult); LogVulkanResultAsError("vkCreateSemaphore", vulkanResult);
return NULL; return NULL;
} }
@ -8870,7 +9037,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateSemaphore", vulkanResult); LogVulkanResultAsError("vkCreateSemaphore", vulkanResult);
return NULL; return NULL;
} }
@ -8883,7 +9050,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateSemaphore", vulkanResult); LogVulkanResultAsError("vkCreateSemaphore", vulkanResult);
return NULL; return NULL;
} }
@ -8896,7 +9063,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateFence", vulkanResult); LogVulkanResultAsError("vkCreateFence", vulkanResult);
return NULL; return NULL;
} }
@ -8925,7 +9092,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkCreateCommandPool", vulkanResult); LogVulkanResultAsError("vkCreateCommandPool", vulkanResult);
return NULL; return NULL;
} }
@ -8943,7 +9110,7 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
if (vulkanResult != VK_SUCCESS) if (vulkanResult != VK_SUCCESS)
{ {
LogVulkanResult("vkAllocateCommandBuffers", vulkanResult); LogVulkanResultAsError("vkAllocateCommandBuffers", vulkanResult);
return NULL; return NULL;
} }