diff --git a/include/Refresh.h b/include/Refresh.h index a0ce516..1d5a232 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -1184,26 +1184,14 @@ REFRESHAPI void REFRESH_AddDisposeSampler( REFRESH_Sampler *sampler ); -/* Sends a vertex buffer to be destroyed by the renderer. Note that we call it +/* Sends a buffer to be destroyed by the renderer. Note that we call it * "AddDispose" because it may not be immediately destroyed by the renderer if * this is not called from the main thread (for example, if a garbage collector * deletes the resource instead of the programmer). * * buffer: The REFRESH_Buffer to be destroyed. */ -REFRESHAPI void REFRESH_AddDisposeVertexBuffer( - REFRESH_Device *device, - REFRESH_Buffer *buffer -); - -/* Sends an index buffer to be destroyed by the renderer. Note that we call it - * "AddDispose" because it may not be immediately destroyed by the renderer if - * this is not called from the main thread (for example, if a garbage collector - * deletes the resource instead of the programmer). - * - * buffer: The REFRESH_Buffer to be destroyed. - */ -REFRESHAPI void REFRESH_AddDisposeIndexBuffer( +REFRESHAPI void REFRESH_AddDisposeBuffer( REFRESH_Device *device, REFRESH_Buffer *buffer ); diff --git a/src/Refresh.c b/src/Refresh.c index b7b22a2..88e557d 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -721,23 +721,12 @@ void REFRESH_AddDisposeSampler( ); } -void REFRESH_AddDisposeVertexBuffer( +void REFRESH_AddDisposeBuffer( REFRESH_Device *device, REFRESH_Buffer *buffer ) { NULL_RETURN(device); - device->AddDisposeVertexBuffer( - device->driverData, - buffer - ); -} - -void REFRESH_AddDisposeIndexBuffer( - REFRESH_Device *device, - REFRESH_Buffer *buffer -) { - NULL_RETURN(device); - device->AddDisposeIndexBuffer( + device->AddDisposeBuffer( device->driverData, buffer ); diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 2195beb..4b39763 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -446,12 +446,7 @@ struct REFRESH_Device REFRESH_Sampler *sampler ); - void(*AddDisposeVertexBuffer)( - REFRESH_Renderer *driverData, - REFRESH_Buffer *buffer - ); - - void(*AddDisposeIndexBuffer)( + void(*AddDisposeBuffer)( REFRESH_Renderer *driverData, REFRESH_Buffer *buffer ); @@ -609,8 +604,7 @@ struct REFRESH_Device ASSIGN_DRIVER_FUNC(CopyTextureDataCube, name) \ ASSIGN_DRIVER_FUNC(AddDisposeTexture, name) \ ASSIGN_DRIVER_FUNC(AddDisposeSampler, name) \ - ASSIGN_DRIVER_FUNC(AddDisposeVertexBuffer, name) \ - ASSIGN_DRIVER_FUNC(AddDisposeIndexBuffer, name) \ + ASSIGN_DRIVER_FUNC(AddDisposeBuffer, name) \ ASSIGN_DRIVER_FUNC(AddDisposeColorTarget, name) \ ASSIGN_DRIVER_FUNC(AddDisposeDepthStencilTarget, name) \ ASSIGN_DRIVER_FUNC(AddDisposeFramebuffer, name) \ diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 2bb5a02..105310d 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -72,6 +72,7 @@ static uint32_t deviceExtensionCount = SDL_arraysize(deviceExtensionNames); #define STARTING_ALLOCATION_SIZE 64000000 /* 64MB */ #define MAX_ALLOCATION_SIZE 256000000 /* 256MB */ #define TEXTURE_STAGING_SIZE 8000000 /* 8MB */ +#define MAX_TEXTURE_STAGING_SIZE 128000000 /* 128MB */ #define UBO_BUFFER_SIZE 8000000 /* 8MB */ #define UBO_ACTUAL_SIZE (UBO_BUFFER_SIZE * 2) #define DESCRIPTOR_POOL_STARTING_SIZE 128 @@ -1324,6 +1325,7 @@ typedef struct VulkanRenderer VulkanBuffer *dummyComputeUniformBuffer; VulkanBuffer *textureStagingBuffer; + uint32_t textureStagingBufferOffset; VulkanBuffer** buffersInUse; uint32_t buffersInUseCount; @@ -1448,6 +1450,7 @@ typedef struct VulkanRenderer static void VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); static void VULKAN_Submit(REFRESH_Renderer *driverData, REFRESH_CommandBuffer **pCommandBuffers, uint32_t commandBufferCount); +static void VULKAN_INTERNAL_FlushTransfers(VulkanRenderer *renderer); /* Error Handling */ @@ -2141,31 +2144,6 @@ static void VULKAN_INTERNAL_ImageMemoryBarrier( /* Resource Disposal */ -static void VULKAN_INTERNAL_RemoveBuffer( - REFRESH_Renderer *driverData, - REFRESH_Buffer *buffer -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->buffersToDestroy, - VulkanBuffer*, - renderer->buffersToDestroyCount + 1, - renderer->buffersToDestroyCapacity, - renderer->buffersToDestroyCapacity * 2 - ) - - renderer->buffersToDestroy[ - renderer->buffersToDestroyCount - ] = vulkanBuffer; - renderer->buffersToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - static void VULKAN_INTERNAL_DestroyTexture( VulkanRenderer* renderer, VulkanTexture* texture @@ -2299,10 +2277,10 @@ static void VULKAN_INTERNAL_DestroyCommandPool( VulkanRenderer *renderer, VulkanCommandPool *commandPool ) { - renderer->vkResetCommandPool( + renderer->vkDestroyCommandPool( renderer->logicalDevice, commandPool->commandPool, - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT + NULL ); SDL_free(commandPool->inactiveCommandBuffers); @@ -3488,6 +3466,12 @@ static void VULKAN_DestroyDevice( } } + renderer->vkDestroyCommandPool( + renderer->logicalDevice, + renderer->transferCommandPool, + NULL + ); + for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) { graphicsPipelineLayoutHashArray = renderer->graphicsPipelineLayoutHashTable.buckets[i]; @@ -5847,27 +5831,36 @@ static REFRESH_Buffer* VULKAN_CreateBuffer( static void VULKAN_INTERNAL_MaybeExpandStagingBuffer( VulkanRenderer *renderer, - VkDeviceSize size + uint32_t textureSize ) { - if (size <= renderer->textureStagingBuffer->size) + VkDeviceSize currentStagingSize = renderer->textureStagingBuffer->size; + + if (renderer->textureStagingBufferOffset + textureSize <= renderer->textureStagingBuffer->size) { return; } - VULKAN_INTERNAL_DestroyTextureStagingBuffer(renderer); + /* not enough room in the staging buffer, time to flush */ + VULKAN_INTERNAL_FlushTransfers(renderer); - renderer->textureStagingBuffer = (VulkanBuffer*) SDL_malloc(sizeof(VulkanBuffer)); + /* double staging buffer size up to max */ + if (currentStagingSize * 2 <= MAX_TEXTURE_STAGING_SIZE) + { + VULKAN_INTERNAL_DestroyTextureStagingBuffer(renderer); - if (!VULKAN_INTERNAL_CreateBuffer( - renderer, - size, - RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - 1, - renderer->textureStagingBuffer - )) { - REFRESH_LogError("Failed to expand texture staging buffer!"); - return; + renderer->textureStagingBuffer = (VulkanBuffer*) SDL_malloc(sizeof(VulkanBuffer)); + + if (!VULKAN_INTERNAL_CreateBuffer( + renderer, + currentStagingSize * 2, + RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + 1, + renderer->textureStagingBuffer + )) { + REFRESH_LogError("Failed to expand texture staging buffer!"); + return; + } } } @@ -5903,6 +5896,88 @@ static void VULKAN_INTERNAL_EndTransferCommandBuffer( } } +/* Hard sync point! */ +static void VULKAN_INTERNAL_FlushTransfers( + VulkanRenderer *renderer +) { + VkSubmitInfo transferSubmitInfo; + VkResult vulkanResult; + + if (renderer->pendingTransfer) + { + VULKAN_INTERNAL_EndTransferCommandBuffer(renderer); + + transferSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + transferSubmitInfo.pNext = NULL; + transferSubmitInfo.commandBufferCount = 1; + transferSubmitInfo.pCommandBuffers = &renderer->transferCommandBuffers[renderer->frameIndex]; + transferSubmitInfo.pWaitDstStageMask = NULL; + transferSubmitInfo.pWaitSemaphores = NULL; + transferSubmitInfo.waitSemaphoreCount = 0; + transferSubmitInfo.pSignalSemaphores = NULL; + transferSubmitInfo.signalSemaphoreCount = 0; + + /* Wait for the previous submission to complete */ + vulkanResult = renderer->vkWaitForFences( + renderer->logicalDevice, + 1, + &renderer->inFlightFence, + VK_TRUE, + UINT64_MAX + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResult("vkWaitForFences", vulkanResult); + return; + } + + renderer->vkResetFences( + renderer->logicalDevice, + 1, + &renderer->inFlightFence + ); + + /* Submit transfers */ + vulkanResult = renderer->vkQueueSubmit( + renderer->transferQueue, + 1, + &transferSubmitInfo, + NULL + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResult("vkQueueSubmit", vulkanResult); + return; + } + + /* Wait again */ + vulkanResult = renderer->vkWaitForFences( + renderer->logicalDevice, + 1, + &renderer->inFlightFence, + VK_TRUE, + UINT64_MAX + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResult("vkWaitForFences", vulkanResult); + return; + } + + renderer->vkResetFences( + renderer->logicalDevice, + 1, + &renderer->inFlightFence + ); + + renderer->pendingTransfer = 0; + renderer->textureStagingBufferOffset = 0; + } +} + static void VULKAN_SetTextureData2D( REFRESH_Renderer *driverData, REFRESH_Texture *texture, @@ -5922,13 +5997,13 @@ static void VULKAN_SetTextureData2D( VkBufferImageCopy imageCopy; uint8_t *mapPointer; - VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLengthInBytes); + VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); vulkanResult = renderer->vkMapMemory( renderer->logicalDevice, renderer->textureStagingBuffer->subBuffers[0]->allocation->memory, - renderer->textureStagingBuffer->subBuffers[0]->offset, + renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset, renderer->textureStagingBuffer->subBuffers[0]->size, 0, (void**) &mapPointer @@ -5971,7 +6046,7 @@ static void VULKAN_SetTextureData2D( imageCopy.imageSubresource.baseArrayLayer = 0; imageCopy.imageSubresource.layerCount = 1; imageCopy.imageSubresource.mipLevel = level; - imageCopy.bufferOffset = 0; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset; imageCopy.bufferRowLength = 0; imageCopy.bufferImageHeight = 0; @@ -5984,6 +6059,8 @@ static void VULKAN_SetTextureData2D( &imageCopy ); + renderer->textureStagingBufferOffset += dataLengthInBytes; + if (vulkanTexture->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT) { VULKAN_INTERNAL_ImageMemoryBarrier( @@ -6023,13 +6100,13 @@ static void VULKAN_SetTextureData3D( VkBufferImageCopy imageCopy; uint8_t *mapPointer; - VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength); + VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); vulkanResult = renderer->vkMapMemory( renderer->logicalDevice, renderer->textureStagingBuffer->subBuffers[0]->allocation->memory, - renderer->textureStagingBuffer->subBuffers[0]->offset, + renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset, renderer->textureStagingBuffer->subBuffers[0]->size, 0, (void**) &mapPointer @@ -6072,7 +6149,7 @@ static void VULKAN_SetTextureData3D( imageCopy.imageSubresource.baseArrayLayer = 0; imageCopy.imageSubresource.layerCount = 1; imageCopy.imageSubresource.mipLevel = level; - imageCopy.bufferOffset = 0; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset; imageCopy.bufferRowLength = 0; imageCopy.bufferImageHeight = 0; @@ -6085,6 +6162,8 @@ static void VULKAN_SetTextureData3D( &imageCopy ); + renderer->textureStagingBufferOffset += dataLength; + if (vulkanTexture->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT) { VULKAN_INTERNAL_ImageMemoryBarrier( @@ -6123,13 +6202,13 @@ static void VULKAN_SetTextureDataCube( VkBufferImageCopy imageCopy; uint8_t *mapPointer; - VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength); + VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); vulkanResult = renderer->vkMapMemory( renderer->logicalDevice, renderer->textureStagingBuffer->subBuffers[0]->allocation->memory, - renderer->textureStagingBuffer->subBuffers[0]->offset, + renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset, renderer->textureStagingBuffer->subBuffers[0]->size, 0, (void**) &mapPointer @@ -6172,7 +6251,7 @@ static void VULKAN_SetTextureDataCube( imageCopy.imageSubresource.baseArrayLayer = cubeMapFace; imageCopy.imageSubresource.layerCount = 1; imageCopy.imageSubresource.mipLevel = level; - imageCopy.bufferOffset = 0; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset; imageCopy.bufferRowLength = 0; /* assumes tightly packed data */ imageCopy.bufferImageHeight = 0; /* assumes tightly packed data */ @@ -6185,6 +6264,8 @@ static void VULKAN_SetTextureDataCube( &imageCopy ); + renderer->textureStagingBufferOffset += dataLength; + if (vulkanTexture->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT) { VULKAN_INTERNAL_ImageMemoryBarrier( @@ -6226,8 +6307,8 @@ static void VULKAN_SetTextureDataYUV( uint8_t *mapPointer; VkResult vulkanResult; - VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength); + VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer); /* Initialize values that are the same for Y, U, and V */ @@ -6239,7 +6320,6 @@ static void VULKAN_SetTextureDataYUV( imageCopy.imageSubresource.baseArrayLayer = 0; imageCopy.imageSubresource.layerCount = 1; imageCopy.imageSubresource.mipLevel = 0; - imageCopy.bufferOffset = 0; /* Y */ @@ -6248,7 +6328,7 @@ static void VULKAN_SetTextureDataYUV( vulkanResult = renderer->vkMapMemory( renderer->logicalDevice, renderer->textureStagingBuffer->subBuffers[0]->allocation->memory, - renderer->textureStagingBuffer->subBuffers[0]->offset, + renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset, renderer->textureStagingBuffer->subBuffers[0]->size, 0, (void**) &mapPointer @@ -6280,8 +6360,10 @@ static void VULKAN_SetTextureDataYUV( &tex->resourceAccessType ); + imageCopy.imageExtent.width = yWidth; imageCopy.imageExtent.height = yHeight; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset; imageCopy.bufferRowLength = yWidth; imageCopy.bufferImageHeight = yHeight; @@ -6303,7 +6385,7 @@ static void VULKAN_SetTextureDataYUV( /* U */ - imageCopy.bufferOffset = yDataLength; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset + yDataLength; tex = (VulkanTexture*) u; @@ -6338,7 +6420,7 @@ static void VULKAN_SetTextureDataYUV( /* V */ - imageCopy.bufferOffset = yDataLength + uvDataLength; + imageCopy.bufferOffset = renderer->textureStagingBufferOffset + uvDataLength; tex = (VulkanTexture*) v; @@ -6376,6 +6458,8 @@ static void VULKAN_SetTextureDataYUV( &imageCopy ); + renderer->textureStagingBufferOffset += dataLength; + if (tex->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT) { VULKAN_INTERNAL_ImageMemoryBarrier( @@ -7154,18 +7238,29 @@ static void VULKAN_AddDisposeSampler( SDL_UnlockMutex(renderer->disposeLock); } -static void VULKAN_AddDisposeVertexBuffer( +static void VULKAN_AddDisposeBuffer( REFRESH_Renderer *driverData, REFRESH_Buffer *buffer ) { - VULKAN_INTERNAL_RemoveBuffer(driverData, buffer); -} + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; -static void VULKAN_AddDisposeIndexBuffer( - REFRESH_Renderer *driverData, - REFRESH_Buffer *buffer -) { - VULKAN_INTERNAL_RemoveBuffer(driverData, buffer); + SDL_LockMutex(renderer->disposeLock); + + EXPAND_ARRAY_IF_NEEDED( + renderer->buffersToDestroy, + VulkanBuffer*, + renderer->buffersToDestroyCount + 1, + renderer->buffersToDestroyCapacity, + renderer->buffersToDestroyCapacity * 2 + ) + + renderer->buffersToDestroy[ + renderer->buffersToDestroyCount + ] = vulkanBuffer; + renderer->buffersToDestroyCount += 1; + + SDL_UnlockMutex(renderer->disposeLock); } static void VULKAN_AddDisposeColorTarget( @@ -8216,7 +8311,9 @@ static void VULKAN_Submit( uint32_t i; uint8_t present; - VkPipelineStageFlags waitStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSemaphore waitSemaphores[2]; + uint32_t waitSemaphoreCount = 0; VkPresentInfoKHR presentInfo; if (renderer->pendingTransfer) @@ -8232,6 +8329,9 @@ static void VULKAN_Submit( transferSubmitInfo.waitSemaphoreCount = 0; transferSubmitInfo.pSignalSemaphores = &renderer->transferFinishedSemaphore; transferSubmitInfo.signalSemaphoreCount = 1; + + waitSemaphores[waitSemaphoreCount] = renderer->transferFinishedSemaphore; + waitSemaphoreCount += 1; } present = !renderer->headless && renderer->shouldPresent; @@ -8252,21 +8352,23 @@ static void VULKAN_Submit( if (present) { - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &renderer->imageAvailableSemaphore; - submitInfo.pWaitDstStageMask = &waitStages; + waitSemaphores[waitSemaphoreCount] = renderer->imageAvailableSemaphore; + waitSemaphoreCount += 1; + + submitInfo.pWaitDstStageMask = &waitStage; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &renderer->renderFinishedSemaphore; } else { - submitInfo.waitSemaphoreCount = 0; - submitInfo.pWaitSemaphores = NULL; submitInfo.pWaitDstStageMask = NULL; submitInfo.signalSemaphoreCount = 0; submitInfo.pSignalSemaphores = NULL; } + submitInfo.waitSemaphoreCount = waitSemaphoreCount; + submitInfo.pWaitSemaphores = waitSemaphores; + /* Wait for the previous submission to complete */ vulkanResult = renderer->vkWaitForFences( renderer->logicalDevice, @@ -8394,6 +8496,7 @@ static void VULKAN_Submit( renderer->swapChainImageAcquired = 0; renderer->shouldPresent = 0; renderer->pendingTransfer = 0; + renderer->textureStagingBufferOffset = 0; SDL_stack_free(commandBuffers); } @@ -8901,12 +9004,11 @@ static uint8_t VULKAN_INTERNAL_CreateLogicalDevice( VkDeviceCreateInfo deviceCreateInfo; VkPhysicalDeviceFeatures deviceFeatures; - VkDeviceQueueCreateInfo queueCreateInfos[3]; + VkDeviceQueueCreateInfo queueCreateInfos[2]; VkDeviceQueueCreateInfo queueCreateInfoGraphics; VkDeviceQueueCreateInfo queueCreateInfoPresent; - VkDeviceQueueCreateInfo queueCreateInfoTransfer; - int32_t queueInfoCount = 2; + int32_t queueInfoCount = 1; float queuePriority = 1.0f; queueCreateInfoGraphics.sType = @@ -8920,17 +9022,6 @@ static uint8_t VULKAN_INTERNAL_CreateLogicalDevice( queueCreateInfos[0] = queueCreateInfoGraphics; - queueCreateInfoTransfer.sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfoTransfer.pNext = NULL; - queueCreateInfoTransfer.flags = 0; - queueCreateInfoTransfer.queueFamilyIndex = - renderer->queueFamilyIndices.transferFamily; - queueCreateInfoTransfer.queueCount = 1; - queueCreateInfoTransfer.pQueuePriorities = &queuePriority; - - queueCreateInfos[1] = queueCreateInfoTransfer; - if (renderer->queueFamilyIndices.presentFamily != renderer->queueFamilyIndices.graphicsFamily) { queueCreateInfoPresent.sType = @@ -9606,6 +9697,8 @@ static REFRESH_Device* VULKAN_CreateDevice( return NULL; } + renderer->textureStagingBufferOffset = 0; + /* Dummy Uniform Buffers */ renderer->dummyVertexUniformBuffer = (VulkanBuffer*) SDL_malloc(sizeof(VulkanBuffer));