alter vulkan defrag strategy
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
2361cec274
commit
695abd4139
|
@ -77,12 +77,9 @@ typedef struct VulkanExtensions
|
|||
#define STARTING_ALLOCATION_SIZE 64000000 /* 64MB */
|
||||
#define MAX_ALLOCATION_SIZE 256000000 /* 256MB */
|
||||
#define ALLOCATION_INCREMENT 16000000 /* 16MB */
|
||||
#define TRANSFER_BUFFER_STARTING_SIZE 8000000 /* 8MB */
|
||||
#define POOLED_TRANSFER_BUFFER_SIZE 16000000 /* 16MB */
|
||||
#define UBO_BUFFER_SIZE 16777216 /* 16MB */
|
||||
#define MAX_UBO_SECTION_SIZE 4096 /* 4KB */
|
||||
#define DESCRIPTOR_POOL_STARTING_SIZE 128
|
||||
#define DEFRAG_TIME 200
|
||||
#define WINDOW_DATA "Refresh_VulkanWindowData"
|
||||
|
||||
#define IDENTITY_SWIZZLE \
|
||||
|
@ -1620,10 +1617,10 @@ typedef struct VulkanCommandBuffer
|
|||
uint32_t usedFramebufferCount;
|
||||
uint32_t usedFramebufferCapacity;
|
||||
|
||||
/* Shader modules have references tracked by pipelines */
|
||||
|
||||
VkFence inFlightFence;
|
||||
uint8_t autoReleaseFence;
|
||||
|
||||
uint8_t isDefrag; /* Whether this CB was created for defragging */
|
||||
} VulkanCommandBuffer;
|
||||
|
||||
struct VulkanCommandPool
|
||||
|
@ -1809,10 +1806,12 @@ typedef struct VulkanRenderer
|
|||
SDL_mutex *framebufferFetchLock;
|
||||
SDL_mutex *renderTargetFetchLock;
|
||||
|
||||
uint8_t needDefrag;
|
||||
uint64_t defragTimestamp;
|
||||
uint8_t defragInProgress;
|
||||
|
||||
VulkanMemoryAllocation **allocationsToDefrag;
|
||||
uint32_t allocationsToDefragCount;
|
||||
uint32_t allocationsToDefragCapacity;
|
||||
|
||||
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
|
||||
vkfntype_##func func;
|
||||
#define VULKAN_DEVICE_FUNCTION(ext, ret, func, params) \
|
||||
|
@ -2127,6 +2126,45 @@ static void VULKAN_INTERNAL_MakeMemoryUnavailable(
|
|||
}
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_MarkAllocationsForDefrag(
|
||||
VulkanRenderer *renderer
|
||||
) {
|
||||
uint32_t memoryType, allocationIndex;
|
||||
VulkanMemorySubAllocator *currentAllocator;
|
||||
|
||||
for (memoryType = 0; memoryType < VK_MAX_MEMORY_TYPES; memoryType += 1)
|
||||
{
|
||||
currentAllocator = &renderer->memoryAllocator->subAllocators[memoryType];
|
||||
|
||||
for (allocationIndex = 0; allocationIndex < currentAllocator->allocationCount; allocationIndex += 1)
|
||||
{
|
||||
if (currentAllocator->allocations[allocationIndex]->availableForAllocation == 1)
|
||||
{
|
||||
if (currentAllocator->allocations[allocationIndex]->freeRegionCount > 1)
|
||||
{
|
||||
EXPAND_ARRAY_IF_NEEDED(
|
||||
renderer->allocationsToDefrag,
|
||||
VulkanMemoryAllocation*,
|
||||
renderer->allocationsToDefragCount + 1,
|
||||
renderer->allocationsToDefragCapacity,
|
||||
renderer->allocationsToDefragCapacity * 2
|
||||
);
|
||||
|
||||
renderer->allocationsToDefrag[renderer->allocationsToDefragCount] =
|
||||
currentAllocator->allocations[allocationIndex];
|
||||
|
||||
renderer->allocationsToDefragCount += 1;
|
||||
|
||||
VULKAN_INTERNAL_MakeMemoryUnavailable(
|
||||
renderer,
|
||||
currentAllocator->allocations[allocationIndex]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void VULKAN_INTERNAL_RemoveMemoryFreeRegion(
|
||||
VulkanRenderer *renderer,
|
||||
VulkanMemoryFreeRegion *freeRegion
|
||||
|
@ -2348,12 +2386,6 @@ static void VULKAN_INTERNAL_RemoveMemoryUsedRegion(
|
|||
usedRegion->size
|
||||
);
|
||||
|
||||
if (!usedRegion->allocation->dedicated)
|
||||
{
|
||||
renderer->needDefrag = 1;
|
||||
renderer->defragTimestamp = SDL_GetTicks64() + DEFRAG_TIME; /* reset timer so we batch defrags */
|
||||
}
|
||||
|
||||
SDL_free(usedRegion);
|
||||
|
||||
SDL_UnlockMutex(renderer->allocatorLock);
|
||||
|
@ -2762,6 +2794,15 @@ static uint8_t VULKAN_INTERNAL_BindResourceMemory(
|
|||
|
||||
/* No suitable free regions exist, allocate a new memory region */
|
||||
|
||||
if (
|
||||
!shouldAllocDedicated &&
|
||||
renderer->allocationsToDefragCount == 0 &&
|
||||
!renderer->defragInProgress
|
||||
) {
|
||||
/* Mark currently fragmented allocations for defrag */
|
||||
VULKAN_INTERNAL_MarkAllocationsForDefrag(renderer);
|
||||
}
|
||||
|
||||
if (shouldAllocDedicated)
|
||||
{
|
||||
allocationSize = requiredSize;
|
||||
|
@ -3081,30 +3122,6 @@ static uint8_t VULKAN_INTERNAL_BindMemoryForBuffer(
|
|||
return bindResult;
|
||||
}
|
||||
|
||||
static uint8_t VULKAN_INTERNAL_FindAllocationToDefragment(
|
||||
VulkanRenderer *renderer,
|
||||
VulkanMemorySubAllocator *allocator,
|
||||
uint32_t *allocationIndexToDefrag
|
||||
) {
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1)
|
||||
{
|
||||
*allocator = renderer->memoryAllocator->subAllocators[i];
|
||||
|
||||
for (j = 0; j < allocator->allocationCount; j += 1)
|
||||
{
|
||||
if (allocator->allocations[j]->availableForAllocation == 1 && allocator->allocations[j]->freeRegionCount > 1)
|
||||
{
|
||||
*allocationIndexToDefrag = j;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory Barriers */
|
||||
|
||||
static void VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
|
@ -9406,6 +9423,8 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer(
|
|||
commandBuffer->renderPassColorTargetCount = 0;
|
||||
commandBuffer->autoReleaseFence = 1;
|
||||
|
||||
commandBuffer->isDefrag = 0;
|
||||
|
||||
/* Reset the command buffer here to avoid resets being called
|
||||
* from a separate thread than where the command buffer was acquired
|
||||
*/
|
||||
|
@ -9976,6 +9995,13 @@ static void VULKAN_INTERNAL_CleanCommandBuffer(
|
|||
commandBuffer->waitSemaphoreCount = 0;
|
||||
commandBuffer->signalSemaphoreCount = 0;
|
||||
|
||||
/* Reset defrag state */
|
||||
|
||||
if (commandBuffer->isDefrag)
|
||||
{
|
||||
renderer->defragInProgress = 0;
|
||||
}
|
||||
|
||||
/* Return command buffer to pool */
|
||||
|
||||
SDL_LockMutex(renderer->acquireCommandBufferLock);
|
||||
|
@ -10211,16 +10237,12 @@ static void VULKAN_Submit(
|
|||
}
|
||||
|
||||
/* Check pending destroys */
|
||||
|
||||
VULKAN_INTERNAL_PerformPendingDestroys(renderer);
|
||||
|
||||
/* Defrag! */
|
||||
if (renderer->needDefrag && !renderer->defragInProgress)
|
||||
if (renderer->allocationsToDefragCount > 0 && !renderer->defragInProgress)
|
||||
{
|
||||
if (SDL_GetTicks64() >= renderer->defragTimestamp)
|
||||
{
|
||||
VULKAN_INTERNAL_DefragmentMemory(renderer);
|
||||
}
|
||||
VULKAN_INTERNAL_DefragmentMemory(renderer);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(renderer->submitLock);
|
||||
|
@ -10229,9 +10251,7 @@ static void VULKAN_Submit(
|
|||
static uint8_t VULKAN_INTERNAL_DefragmentMemory(
|
||||
VulkanRenderer *renderer
|
||||
) {
|
||||
VulkanMemorySubAllocator allocator;
|
||||
VulkanMemoryAllocation *allocation;
|
||||
uint32_t allocationIndexToDefrag;
|
||||
VulkanMemoryUsedRegion *currentRegion;
|
||||
VulkanBuffer* newBuffer;
|
||||
VulkanTexture* newTexture;
|
||||
|
@ -10244,131 +10264,124 @@ static uint8_t VULKAN_INTERNAL_DefragmentMemory(
|
|||
|
||||
SDL_LockMutex(renderer->allocatorLock);
|
||||
|
||||
renderer->needDefrag = 0;
|
||||
renderer->defragInProgress = 1;
|
||||
|
||||
commandBuffer = (VulkanCommandBuffer*) VULKAN_AcquireCommandBuffer((Refresh_Renderer *) renderer);
|
||||
commandBuffer->isDefrag = 1;
|
||||
|
||||
if (VULKAN_INTERNAL_FindAllocationToDefragment(
|
||||
renderer,
|
||||
&allocator,
|
||||
&allocationIndexToDefrag
|
||||
)) {
|
||||
allocation = allocator.allocations[allocationIndexToDefrag];
|
||||
allocation = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1];
|
||||
renderer->allocationsToDefragCount -= 1;
|
||||
|
||||
VULKAN_INTERNAL_MakeMemoryUnavailable(
|
||||
renderer,
|
||||
allocation
|
||||
);
|
||||
/* For each used region in the allocation
|
||||
* create a new resource, copy the data
|
||||
* and re-point the resource containers
|
||||
*/
|
||||
for (i = 0; i < allocation->usedRegionCount; i += 1)
|
||||
{
|
||||
currentRegion = allocation->usedRegions[i];
|
||||
copyResourceAccessType = RESOURCE_ACCESS_NONE;
|
||||
|
||||
/* For each used region in the allocation
|
||||
* create a new resource, copy the data
|
||||
* and re-point the resource containers
|
||||
*/
|
||||
for (i = 0; i < allocation->usedRegionCount; i += 1)
|
||||
if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy)
|
||||
{
|
||||
currentRegion = allocation->usedRegions[i];
|
||||
copyResourceAccessType = RESOURCE_ACCESS_NONE;
|
||||
currentRegion->vulkanBuffer->usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy)
|
||||
newBuffer = VULKAN_INTERNAL_CreateBuffer(
|
||||
renderer,
|
||||
currentRegion->vulkanBuffer->size,
|
||||
RESOURCE_ACCESS_NONE,
|
||||
currentRegion->vulkanBuffer->usage,
|
||||
currentRegion->vulkanBuffer->requireHostVisible,
|
||||
currentRegion->vulkanBuffer->preferHostLocal,
|
||||
currentRegion->vulkanBuffer->preferDeviceLocal,
|
||||
0,
|
||||
currentRegion->vulkanBuffer->preserveContentsOnDefrag
|
||||
);
|
||||
|
||||
if (newBuffer == NULL)
|
||||
{
|
||||
currentRegion->vulkanBuffer->usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
newBuffer = VULKAN_INTERNAL_CreateBuffer(
|
||||
renderer,
|
||||
currentRegion->vulkanBuffer->size,
|
||||
RESOURCE_ACCESS_NONE,
|
||||
currentRegion->vulkanBuffer->usage,
|
||||
currentRegion->vulkanBuffer->requireHostVisible,
|
||||
currentRegion->vulkanBuffer->preferHostLocal,
|
||||
currentRegion->vulkanBuffer->preferDeviceLocal,
|
||||
0,
|
||||
currentRegion->vulkanBuffer->preserveContentsOnDefrag
|
||||
);
|
||||
|
||||
if (newBuffer == NULL)
|
||||
{
|
||||
Refresh_LogError("Failed to create defrag buffer!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy buffer contents if necessary */
|
||||
if (currentRegion->vulkanBuffer->preserveContentsOnDefrag)
|
||||
{
|
||||
originalResourceAccessType = currentRegion->vulkanBuffer->resourceAccessType;
|
||||
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
RESOURCE_ACCESS_TRANSFER_READ,
|
||||
currentRegion->vulkanBuffer
|
||||
);
|
||||
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
RESOURCE_ACCESS_TRANSFER_WRITE,
|
||||
newBuffer
|
||||
);
|
||||
|
||||
bufferCopy.srcOffset = 0;
|
||||
bufferCopy.dstOffset = 0;
|
||||
bufferCopy.size = currentRegion->resourceSize;
|
||||
|
||||
renderer->vkCmdCopyBuffer(
|
||||
commandBuffer->commandBuffer,
|
||||
currentRegion->vulkanBuffer->buffer,
|
||||
newBuffer->buffer,
|
||||
1,
|
||||
&bufferCopy
|
||||
);
|
||||
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
originalResourceAccessType,
|
||||
newBuffer
|
||||
);
|
||||
|
||||
VULKAN_INTERNAL_TrackBuffer(renderer, commandBuffer, currentRegion->vulkanBuffer);
|
||||
VULKAN_INTERNAL_TrackBuffer(renderer, commandBuffer, newBuffer);
|
||||
}
|
||||
|
||||
/* re-point original container to new buffer */
|
||||
if (currentRegion->vulkanBuffer->container != NULL)
|
||||
{
|
||||
newBuffer->container = currentRegion->vulkanBuffer->container;
|
||||
newBuffer->container->vulkanBuffer = newBuffer;
|
||||
currentRegion->vulkanBuffer->container = NULL;
|
||||
}
|
||||
|
||||
VULKAN_INTERNAL_QueueDestroyBuffer(renderer, currentRegion->vulkanBuffer);
|
||||
|
||||
renderer->needDefrag = 1;
|
||||
Refresh_LogError("Failed to create defrag buffer!");
|
||||
return 0;
|
||||
}
|
||||
else if (!currentRegion->vulkanTexture->markedForDestroy)
|
||||
{
|
||||
newTexture = VULKAN_INTERNAL_CreateTexture(
|
||||
|
||||
originalResourceAccessType = currentRegion->vulkanBuffer->resourceAccessType;
|
||||
|
||||
/* Copy buffer contents if necessary */
|
||||
if (
|
||||
originalResourceAccessType != RESOURCE_ACCESS_NONE &&
|
||||
currentRegion->vulkanBuffer->preserveContentsOnDefrag
|
||||
) {
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
currentRegion->vulkanTexture->dimensions.width,
|
||||
currentRegion->vulkanTexture->dimensions.height,
|
||||
currentRegion->vulkanTexture->depth,
|
||||
currentRegion->vulkanTexture->isCube,
|
||||
currentRegion->vulkanTexture->levelCount,
|
||||
currentRegion->vulkanTexture->sampleCount,
|
||||
currentRegion->vulkanTexture->format,
|
||||
currentRegion->vulkanTexture->aspectFlags,
|
||||
currentRegion->vulkanTexture->usageFlags
|
||||
commandBuffer->commandBuffer,
|
||||
RESOURCE_ACCESS_TRANSFER_READ,
|
||||
currentRegion->vulkanBuffer
|
||||
);
|
||||
|
||||
if (newTexture == NULL)
|
||||
{
|
||||
Refresh_LogError("Failed to create defrag texture!");
|
||||
return 0;
|
||||
}
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
RESOURCE_ACCESS_TRANSFER_WRITE,
|
||||
newBuffer
|
||||
);
|
||||
|
||||
originalResourceAccessType = currentRegion->vulkanTexture->resourceAccessType;
|
||||
bufferCopy.srcOffset = 0;
|
||||
bufferCopy.dstOffset = 0;
|
||||
bufferCopy.size = currentRegion->resourceSize;
|
||||
|
||||
renderer->vkCmdCopyBuffer(
|
||||
commandBuffer->commandBuffer,
|
||||
currentRegion->vulkanBuffer->buffer,
|
||||
newBuffer->buffer,
|
||||
1,
|
||||
&bufferCopy
|
||||
);
|
||||
|
||||
VULKAN_INTERNAL_BufferMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
originalResourceAccessType,
|
||||
newBuffer
|
||||
);
|
||||
|
||||
VULKAN_INTERNAL_TrackBuffer(renderer, commandBuffer, currentRegion->vulkanBuffer);
|
||||
VULKAN_INTERNAL_TrackBuffer(renderer, commandBuffer, newBuffer);
|
||||
}
|
||||
|
||||
/* re-point original container to new buffer */
|
||||
if (currentRegion->vulkanBuffer->container != NULL)
|
||||
{
|
||||
newBuffer->container = currentRegion->vulkanBuffer->container;
|
||||
newBuffer->container->vulkanBuffer = newBuffer;
|
||||
currentRegion->vulkanBuffer->container = NULL;
|
||||
}
|
||||
|
||||
VULKAN_INTERNAL_QueueDestroyBuffer(renderer, currentRegion->vulkanBuffer);
|
||||
}
|
||||
else if (!currentRegion->vulkanTexture->markedForDestroy)
|
||||
{
|
||||
originalResourceAccessType = currentRegion->vulkanTexture->resourceAccessType;
|
||||
|
||||
newTexture = VULKAN_INTERNAL_CreateTexture(
|
||||
renderer,
|
||||
currentRegion->vulkanTexture->dimensions.width,
|
||||
currentRegion->vulkanTexture->dimensions.height,
|
||||
currentRegion->vulkanTexture->depth,
|
||||
currentRegion->vulkanTexture->isCube,
|
||||
currentRegion->vulkanTexture->levelCount,
|
||||
currentRegion->vulkanTexture->sampleCount,
|
||||
currentRegion->vulkanTexture->format,
|
||||
currentRegion->vulkanTexture->aspectFlags,
|
||||
currentRegion->vulkanTexture->usageFlags
|
||||
);
|
||||
|
||||
if (newTexture == NULL)
|
||||
{
|
||||
Refresh_LogError("Failed to create defrag texture!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (originalResourceAccessType != RESOURCE_ACCESS_NONE)
|
||||
{
|
||||
VULKAN_INTERNAL_ImageMemoryBarrier(
|
||||
renderer,
|
||||
commandBuffer->commandBuffer,
|
||||
|
@ -10448,30 +10461,24 @@ static uint8_t VULKAN_INTERNAL_DefragmentMemory(
|
|||
|
||||
VULKAN_INTERNAL_TrackTexture(renderer, commandBuffer, currentRegion->vulkanTexture);
|
||||
VULKAN_INTERNAL_TrackTexture(renderer, commandBuffer, newTexture);
|
||||
|
||||
/* re-point original container to new texture */
|
||||
newTexture->container = currentRegion->vulkanTexture->container;
|
||||
newTexture->container->vulkanTexture = newTexture;
|
||||
currentRegion->vulkanTexture->container = NULL;
|
||||
|
||||
VULKAN_INTERNAL_QueueDestroyTexture(renderer, currentRegion->vulkanTexture);
|
||||
|
||||
renderer->needDefrag = 1;
|
||||
}
|
||||
|
||||
/* re-point original container to new texture */
|
||||
newTexture->container = currentRegion->vulkanTexture->container;
|
||||
newTexture->container->vulkanTexture = newTexture;
|
||||
currentRegion->vulkanTexture->container = NULL;
|
||||
|
||||
VULKAN_INTERNAL_QueueDestroyTexture(renderer, currentRegion->vulkanTexture);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(renderer->allocatorLock);
|
||||
|
||||
renderer->defragTimestamp = SDL_GetTicks64() + DEFRAG_TIME;
|
||||
|
||||
VULKAN_Submit(
|
||||
(Refresh_Renderer*) renderer,
|
||||
(Refresh_CommandBuffer*) commandBuffer
|
||||
);
|
||||
|
||||
renderer->defragInProgress = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -11849,10 +11856,16 @@ static Refresh_Device* VULKAN_CreateDevice(
|
|||
renderer->framebuffersToDestroyCapacity
|
||||
);
|
||||
|
||||
renderer->needDefrag = 0;
|
||||
renderer->defragTimestamp = 0;
|
||||
/* Defrag state */
|
||||
|
||||
renderer->defragInProgress = 0;
|
||||
|
||||
renderer->allocationsToDefragCount = 0;
|
||||
renderer->allocationsToDefragCapacity = 4;
|
||||
renderer->allocationsToDefrag = SDL_malloc(
|
||||
renderer->allocationsToDefragCapacity * sizeof(VulkanMemoryAllocation*)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue