From f8c99c4e18c99b999661954b86659aa39e81c908 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Sat, 2 Jan 2021 17:00:52 -0800 Subject: [PATCH] make gets and sets async --- include/Refresh.h | 43 +++++++---- src/Refresh.c | 33 ++++++-- src/Refresh_Driver.h | 22 ++++-- src/Refresh_Driver_Vulkan.c | 149 ++++++++++++++++-------------------- 4 files changed, 137 insertions(+), 110 deletions(-) diff --git a/include/Refresh.h b/include/Refresh.h index aa2de3f..28788df 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -1092,9 +1092,25 @@ REFRESHAPI void REFRESH_SetFragmentSamplers( /* Getters */ -/* Pulls image data from a 2D texture into client memory. Like any GetData, - * this is generally asking for a massive CPU/GPU sync point, don't call this - * unless there's absolutely no other way to use the image data! +/* Synchronously copies data from a buffer to a pointer. + * You probably want to wait for a sync point to call this. + * + * buffer: The buffer to copy data from. + * data: The pointer to copy data to. + * dataLengthInBytes: The length of data to copy. + */ +REFRESHAPI void REFRESH_GetBufferData( + REFRESH_Device *device, + REFRESH_Buffer *buffer, + void *data, + uint32_t dataLengthInBytes +); + +/* Asynchronously copies image data from a 2D texture into a buffer. + * + * NOTE: + * The buffer will not contain correct data until the command buffer + * is submitted and completed. * * texture: The texture object being read. * x: The x offset of the subregion being read. @@ -1102,23 +1118,23 @@ REFRESHAPI void REFRESH_SetFragmentSamplers( * w: The width of the subregion being read. * h: The height of the subregion being read. * level: The mipmap level being read. - * data: The pointer being filled with the image data. + * buffer: The buffer being filled with the image data. */ -REFRESHAPI void REFRESH_GetTextureData2D( +REFRESHAPI void REFRESH_CopyTextureData2D( REFRESH_Device *device, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t level, - void* data + REFRESH_Buffer *buffer ); -/* Pulls image data from a single face of a texture cube object into client - * memory. Like any GetData, this is generally asking for a massive CPU/GPU sync - * point, don't call this unless there's absolutely no other way to use the - * image data! +/* Asynchronously copies image data from a single face of a texture cube + * object into a buffer. You must wait for the command buffer to be + * submitted and completed before reading the buffer. * * texture: The texture object being read. * x: The x offset of the subregion being read. @@ -1127,10 +1143,11 @@ REFRESHAPI void REFRESH_GetTextureData2D( * h: The height of the subregion being read. * cubeMapFace: The face of the cube being read. * level: The mipmap level being read. - * data: The pointer being filled with the image data. + * buffer: The buffer being filled with the image data. */ -REFRESHAPI void REFRESH_GetTextureDataCube( +REFRESHAPI void REFRESH_CopyTextureDataCube( REFRESH_Device *device, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, @@ -1138,7 +1155,7 @@ REFRESHAPI void REFRESH_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data + REFRESH_Buffer *buffer ); /* Disposal */ diff --git a/src/Refresh.c b/src/Refresh.c index 6505d8b..b7b22a2 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -632,31 +632,49 @@ void REFRESH_SetFragmentSamplers( ); } -void REFRESH_GetTextureData2D( +void REFRESH_GetBufferData( + REFRESH_Device *device, + REFRESH_Buffer *buffer, + void *data, + uint32_t dataLengthInBytes +) { + NULL_RETURN(device); + device->GetBufferData( + device->driverData, + buffer, + data, + dataLengthInBytes + ); +} + +void REFRESH_CopyTextureData2D( REFRESH_Device *device, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t level, - void* data + REFRESH_Buffer* buffer ) { NULL_RETURN(device); - device->GetTextureData2D( + device->CopyTextureData2D( device->driverData, + commandBuffer, texture, x, y, w, h, level, - data + buffer ); } void REFRESH_GetTextureDataCube( REFRESH_Device *device, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, @@ -664,11 +682,12 @@ void REFRESH_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data + REFRESH_Buffer* buffer ) { NULL_RETURN(device); - device->GetTextureDataCube( + device->CopyTextureDataCube( device->driverData, + commandBuffer, texture, x, y, @@ -676,7 +695,7 @@ void REFRESH_GetTextureDataCube( h, cubeMapFace, level, - data + buffer ); } diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 1334aac..2195beb 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -402,19 +402,28 @@ struct REFRESH_Device /* Getters */ - void(*GetTextureData2D)( + void(*GetBufferData)( REFRESH_Renderer *driverData, + REFRESH_Buffer *buffer, + void *data, + uint32_t dataLengthInBytes + ); + + void(*CopyTextureData2D)( + REFRESH_Renderer *driverData, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t level, - void* data + REFRESH_Buffer* buffer ); - void(*GetTextureDataCube)( + void(*CopyTextureDataCube)( REFRESH_Renderer *driverData, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, @@ -422,7 +431,7 @@ struct REFRESH_Device uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data + REFRESH_Buffer* buffer ); /* Disposal */ @@ -595,8 +604,9 @@ struct REFRESH_Device ASSIGN_DRIVER_FUNC(PushComputeShaderParams, name) \ ASSIGN_DRIVER_FUNC(SetVertexSamplers, name) \ ASSIGN_DRIVER_FUNC(SetFragmentSamplers, name) \ - ASSIGN_DRIVER_FUNC(GetTextureData2D, name) \ - ASSIGN_DRIVER_FUNC(GetTextureDataCube, name) \ + ASSIGN_DRIVER_FUNC(GetBufferData, name) \ + ASSIGN_DRIVER_FUNC(CopyTextureData2D, name) \ + ASSIGN_DRIVER_FUNC(CopyTextureDataCube, name) \ ASSIGN_DRIVER_FUNC(AddDisposeTexture, name) \ ASSIGN_DRIVER_FUNC(AddDisposeSampler, name) \ ASSIGN_DRIVER_FUNC(AddDisposeVertexBuffer, name) \ diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 5bb9639..b322f3e 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -1375,7 +1375,6 @@ 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_SubmitTransfer(REFRESH_Renderer *driverData); /* Error Handling */ @@ -5872,8 +5871,6 @@ static void VULKAN_SetTextureData2D( } renderer->pendingTransfer = 1; - - VULKAN_INTERNAL_SubmitTransfer(driverData); } static void VULKAN_SetTextureData3D( @@ -5980,8 +5977,6 @@ static void VULKAN_SetTextureData3D( } renderer->pendingTransfer = 1; - - VULKAN_INTERNAL_SubmitTransfer(driverData); } static void VULKAN_SetTextureDataCube( @@ -6087,8 +6082,6 @@ static void VULKAN_SetTextureDataCube( } renderer->pendingTransfer = 1; - - VULKAN_INTERNAL_SubmitTransfer(driverData); } static void VULKAN_SetTextureDataYUV( @@ -6289,9 +6282,6 @@ static void VULKAN_SetTextureDataYUV( } renderer->pendingTransfer = 1; - - /* Hard sync point */ - VULKAN_INTERNAL_SubmitTransfer(driverData); } static void VULKAN_SetBufferData( @@ -6839,8 +6829,48 @@ static void VULKAN_SetFragmentSamplers( ); } -static void VULKAN_INTERNAL_GetTextureData( +static void VULKAN_GetBufferData( REFRESH_Renderer *driverData, + REFRESH_Buffer *buffer, + void *data, + uint32_t dataLengthInBytes +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; + uint8_t *dataPtr = (uint8_t*) data; + uint8_t *mapPointer; + VkResult vulkanResult; + + vulkanResult = renderer->vkMapMemory( + renderer->logicalDevice, + vulkanBuffer->subBuffers[0]->allocation->memory, + vulkanBuffer->subBuffers[0]->offset, + vulkanBuffer->subBuffers[0]->size, + 0, + (void**) &mapPointer + ); + + if (vulkanResult != VK_SUCCESS) + { + REFRESH_LogError("Failed to map buffer memory!"); + return; + } + + SDL_memcpy( + dataPtr, + mapPointer, + dataLengthInBytes + ); + + renderer->vkUnmapMemory( + renderer->logicalDevice, + vulkanBuffer->subBuffers[0]->allocation->memory + ); +} + +static void VULKAN_INTERNAL_CopyTextureData( + REFRESH_Renderer *driverData, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, int32_t x, int32_t y, @@ -6848,27 +6878,22 @@ static void VULKAN_INTERNAL_GetTextureData( int32_t h, int32_t level, int32_t layer, - void* data + REFRESH_Buffer *buffer ) { VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; VulkanTexture *vulkanTexture = (VulkanTexture*) texture; + VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer; - VkCommandBuffer commandBuffer = renderer->transferCommandBuffers[renderer->frameIndex]; VulkanResourceAccessType prevResourceAccess; VkBufferImageCopy imageCopy; - uint8_t *dataPtr = (uint8_t*) data; - uint8_t *mapPointer; - VkResult vulkanResult; - uint32_t dataLength = BytesPerImage(w, h, vulkanTexture->colorFormat); - - VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength); /* Cache this so we can restore it later */ prevResourceAccess = vulkanTexture->resourceAccessType; VULKAN_INTERNAL_ImageMemoryBarrier( renderer, - commandBuffer, + vulkanCommandBuffer->commandBuffer, RESOURCE_ACCESS_TRANSFER_READ, VK_IMAGE_ASPECT_COLOR_BIT, 0, @@ -6877,12 +6902,12 @@ static void VULKAN_INTERNAL_GetTextureData( vulkanTexture->levelCount, 0, vulkanTexture->image, - renderer->queueFamilyIndices.transferFamily, - &vulkanTexture->queueFamilyIndex, + VK_QUEUE_FAMILY_IGNORED, + NULL, &vulkanTexture->resourceAccessType ); - /* Save texture data to staging buffer */ + /* Save texture data to buffer */ imageCopy.imageExtent.width = w; imageCopy.imageExtent.height = h; @@ -6899,10 +6924,10 @@ static void VULKAN_INTERNAL_GetTextureData( imageCopy.bufferOffset = 0; renderer->vkCmdCopyImageToBuffer( - commandBuffer, + vulkanCommandBuffer->commandBuffer, vulkanTexture->image, AccessMap[vulkanTexture->resourceAccessType].imageLayout, - renderer->textureStagingBuffer->subBuffers[0]->buffer, + vulkanBuffer->subBuffers[vulkanBuffer->currentSubBufferIndex]->buffer, 1, &imageCopy ); @@ -6911,7 +6936,7 @@ static void VULKAN_INTERNAL_GetTextureData( VULKAN_INTERNAL_ImageMemoryBarrier( renderer, - commandBuffer, + vulkanCommandBuffer->commandBuffer, prevResourceAccess, VK_IMAGE_ASPECT_COLOR_BIT, 0, @@ -6920,57 +6945,28 @@ static void VULKAN_INTERNAL_GetTextureData( vulkanTexture->levelCount, 0, vulkanTexture->image, - renderer->queueFamilyIndices.graphicsFamily, - &vulkanTexture->queueFamilyIndex, + VK_QUEUE_FAMILY_IGNORED, + NULL, &vulkanTexture->resourceAccessType ); renderer->pendingTransfer = 1; - - /* Hard sync point */ - VULKAN_INTERNAL_SubmitTransfer(driverData); - - /* Read from staging buffer */ - - vulkanResult = renderer->vkMapMemory( - renderer->logicalDevice, - renderer->textureStagingBuffer->subBuffers[0]->allocation->memory, - renderer->textureStagingBuffer->subBuffers[0]->offset, - renderer->textureStagingBuffer->subBuffers[0]->size, - 0, - (void**) &mapPointer - ); - - if (vulkanResult != VK_SUCCESS) - { - REFRESH_LogError("Failed to map buffer memory!"); - return; - } - - SDL_memcpy( - dataPtr, - mapPointer, - dataLength - ); - - renderer->vkUnmapMemory( - renderer->logicalDevice, - renderer->textureStagingBuffer->subBuffers[0]->allocation->memory - ); } -static void VULKAN_GetTextureData2D( +static void VULKAN_CopyTextureData2D( REFRESH_Renderer *driverData, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t level, - void* data + REFRESH_Buffer *buffer ) { - VULKAN_INTERNAL_GetTextureData( + VULKAN_INTERNAL_CopyTextureData( driverData, + commandBuffer, texture, x, y, @@ -6978,12 +6974,13 @@ static void VULKAN_GetTextureData2D( h, level, 0, - data + buffer ); } -static void VULKAN_GetTextureDataCube( +static void VULKAN_CopyTextureDataCube( REFRESH_Renderer *driverData, + REFRESH_CommandBuffer *commandBuffer, REFRESH_Texture *texture, uint32_t x, uint32_t y, @@ -6991,10 +6988,11 @@ static void VULKAN_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data + REFRESH_Buffer *buffer ) { - VULKAN_INTERNAL_GetTextureData( + VULKAN_INTERNAL_CopyTextureData( driverData, + commandBuffer, texture, x, y, @@ -7002,7 +7000,7 @@ static void VULKAN_GetTextureDataCube( h, level, cubeMapFace, - data + buffer ); } @@ -8029,23 +8027,6 @@ static void VULKAN_INTERNAL_ResetCommandBuffer( commandPool->inactiveCommandBufferCount += 1; } -/* This function triggers a hard sync point */ -static void VULKAN_INTERNAL_SubmitTransfer( - REFRESH_Renderer *driverData -) { - VulkanRenderer* renderer = (VulkanRenderer*)driverData; - - VULKAN_Submit(driverData, NULL, 0); - - renderer->vkWaitForFences( - renderer->logicalDevice, - 1, - &renderer->inFlightFence, - VK_TRUE, - UINT64_MAX - ); -} - static void VULKAN_Submit( REFRESH_Renderer *driverData, REFRESH_CommandBuffer **pCommandBuffers,