diff --git a/include/Refresh.h b/include/Refresh.h index 4e3b722..c4be92d 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -1193,46 +1193,6 @@ REFRESHAPI void Refresh_UploadToBuffer( Refresh_WriteOptions writeOption ); -/* GPU-to-CPU copies occur on the GPU timeline. - * - * You may NOT assume that the data in the TransferBuffer is fully copied - * until the command buffer has finished execution. - */ - -/* - * transferOption: - * SAFEDISCARD: - * If this TransferBuffer has been used in commands that have not completed, - * the issued commands will still be valid at the cost of increased memory usage. - * You may NOT assume that any of the previous data is retained. - * If the TransferBuffer was not in use, this option is equivalent to OVERWRITE. - * It is not recommended to use this option with large TransferBuffers. - * - * OVERWRITE: - * Overwrites the data regardless of whether a command has been issued. - * Use this option with great care, as it can cause data races to occur! - */ - -/* Downloads data from a texture to a TransferBuffer. */ -REFRESHAPI void Refresh_DownloadFromTexture( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_TextureRegion *textureRegion, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferImageCopy *copyParams, - Refresh_TransferOptions transferOption -); - -/* Downloads data from a GpuBuffer object. */ -REFRESHAPI void Refresh_DownloadFromBuffer( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_GpuBuffer *gpuBuffer, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferCopy *copyParams, - Refresh_TransferOptions transferOption -); - /* GPU-to-GPU copies occur on the GPU timeline, * and you may assume the copy has finished in subsequent commands. */ @@ -1401,6 +1361,49 @@ REFRESHAPI void Refresh_ReleaseFence( Refresh_Fence *fence ); +/* Readback */ + +/* GPU-to-CPU copies occur immediately on the CPU timeline. + * + * If you modify data on the GPU and then call these functions without calling Wait or WaitForFences first, + * the data will be undefined! + * + * Readback forces a sync point and is generally a bad thing to do. + * Only use these functions if you have exhausted all other options. + */ + +/* + * transferOption: + * SAFEDISCARD: + * If this TransferBuffer has been used in commands that have not completed, + * the issued commands will still be valid at the cost of increased memory usage. + * You may NOT assume that any of the previous data is retained. + * If the TransferBuffer was not in use, this option is equivalent to OVERWRITE. + * It is not recommended to use this option with large TransferBuffers. + * + * OVERWRITE: + * Overwrites the data regardless of whether a command has been issued. + * Use this option with great care, as it can cause data races to occur! + */ + +/* Downloads data from a texture to a TransferBuffer. */ +REFRESHAPI void Refresh_DownloadFromTexture( + Refresh_Device *device, + Refresh_TextureRegion *textureRegion, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferImageCopy *copyParams, + Refresh_TransferOptions transferOption +); + +/* Downloads data from a GpuBuffer object. */ +REFRESHAPI void Refresh_DownloadFromBuffer( + Refresh_Device *device, + Refresh_GpuBuffer *gpuBuffer, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferCopy *copyParams, + Refresh_TransferOptions transferOption +); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/Refresh.c b/src/Refresh.c index 267f47d..e6ac313 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -824,44 +824,6 @@ void Refresh_UploadToBuffer( ); } -void Refresh_DownloadFromTexture( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_TextureRegion *textureRegion, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferImageCopy *copyParams, - Refresh_TransferOptions transferOption -) { - NULL_RETURN(device); - device->DownloadFromTexture( - device->driverData, - commandBuffer, - textureRegion, - transferBuffer, - copyParams, - transferOption - ); -} - -void Refresh_DownloadFromBuffer( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_GpuBuffer *gpuBuffer, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferCopy *copyParams, - Refresh_TransferOptions transferOption -) { - NULL_RETURN(device); - device->DownloadFromBuffer( - device->driverData, - commandBuffer, - gpuBuffer, - transferBuffer, - copyParams, - transferOption - ); -} - void Refresh_CopyTextureToTexture( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, @@ -1067,4 +1029,38 @@ void Refresh_ReleaseFence( ); } +void Refresh_DownloadFromTexture( + Refresh_Device *device, + Refresh_TextureRegion *textureRegion, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferImageCopy *copyParams, + Refresh_TransferOptions transferOption +) { + NULL_RETURN(device); + device->DownloadFromTexture( + device->driverData, + textureRegion, + transferBuffer, + copyParams, + transferOption + ); +} + +void Refresh_DownloadFromBuffer( + Refresh_Device *device, + Refresh_GpuBuffer *gpuBuffer, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferCopy *copyParams, + Refresh_TransferOptions transferOption +) { + NULL_RETURN(device); + device->DownloadFromBuffer( + device->driverData, + gpuBuffer, + transferBuffer, + copyParams, + transferOption + ); +} + /* vim: set noexpandtab shiftwidth=8 tabstop=8: */ diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 18d0785..bb6d60f 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -506,24 +506,6 @@ struct Refresh_Device Refresh_WriteOptions writeOption ); - void (*DownloadFromTexture)( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_TextureRegion *textureSlice, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferImageCopy *copyParams, - Refresh_TransferOptions transferOption - ); - - void (*DownloadFromBuffer)( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_GpuBuffer *gpuBuffer, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferCopy *copyParams, - Refresh_TransferOptions transferOption - ); - void (*CopyTextureToTexture)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -619,6 +601,22 @@ struct Refresh_Device Refresh_Fence *fence ); + void (*DownloadFromTexture)( + Refresh_Renderer *driverData, + Refresh_TextureRegion *textureSlice, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferImageCopy *copyParams, + Refresh_TransferOptions transferOption + ); + + void (*DownloadFromBuffer)( + Refresh_Renderer *driverData, + Refresh_GpuBuffer *gpuBuffer, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferCopy *copyParams, + Refresh_TransferOptions transferOption + ); + /* Opaque pointer for the Driver */ Refresh_Renderer *driverData; }; diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index b9477f9..ae15513 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -2069,14 +2069,12 @@ static void D3D11_UploadToBuffer( static void D3D11_DownloadFromTexture( Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, Refresh_TextureRegion *textureRegion, Refresh_TransferBuffer *transferBuffer, Refresh_BufferImageCopy *copyParams, Refresh_TransferOptions transferOption ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; - D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer*) commandBuffer; D3D11TransferBufferContainer *container = (D3D11TransferBufferContainer*) transferBuffer; D3D11TransferBuffer *d3d11TransferBuffer = container->activeBuffer; D3D11Texture *d3d11Texture = (D3D11Texture*) textureRegion->textureSlice.texture; @@ -2126,8 +2124,10 @@ static void D3D11_DownloadFromTexture( ); ERROR_CHECK_RETURN("Staging texture creation failed",) - ID3D11DeviceContext1_CopySubresourceRegion1( - d3d11CommandBuffer->context, + /* Readback is only possible on CPU timeline in D3D11 */ + SDL_LockMutex(renderer->contextLock); + ID3D11DeviceContext_CopySubresourceRegion( + renderer->immediateContext, stagingTexture, 0, 0, @@ -2135,13 +2135,12 @@ static void D3D11_DownloadFromTexture( 0, d3d11Texture->handle, subresourceIndex, - &srcBox, - D3D11_COPY_NO_OVERWRITE + &srcBox ); /* Read from the staging texture */ - res = ID3D11DeviceContext1_Map( - d3d11CommandBuffer->context, + res = ID3D11DeviceContext_Map( + renderer->immediateContext, stagingTexture, subresourceIndex, D3D11_MAP_READ, @@ -2170,24 +2169,24 @@ static void D3D11_DownloadFromTexture( } ID3D11DeviceContext1_Unmap( - d3d11CommandBuffer->context, + renderer->immediateContext, stagingTexture, 0 ); + SDL_UnlockMutex(renderer->contextLock); + /* Clean up the staging texture */ ID3D11Texture2D_Release(stagingTexture); } static void D3D11_DownloadFromBuffer( Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, Refresh_GpuBuffer *gpuBuffer, Refresh_TransferBuffer *transferBuffer, Refresh_BufferCopy *copyParams, Refresh_TransferOptions transferOption ) { D3D11Renderer *renderer = (D3D11Renderer*) driverData; - D3D11CommandBuffer *d3d11CommandBuffer = (D3D11CommandBuffer*) commandBuffer; D3D11TransferBufferContainer *container = (D3D11TransferBufferContainer*) transferBuffer; D3D11TransferBuffer *d3d11TransferBuffer = container->activeBuffer; D3D11Buffer *d3d11Buffer = (D3D11Buffer*) gpuBuffer; @@ -2225,8 +2224,10 @@ static void D3D11_DownloadFromBuffer( ); ERROR_CHECK_RETURN("Could not create staging buffer for readback", ); - ID3D11DeviceContext1_CopySubresourceRegion1( - d3d11CommandBuffer->context, + /* Readback is only possible on CPU timeline in D3D11 */ + SDL_LockMutex(renderer->contextLock); + ID3D11DeviceContext_CopySubresourceRegion( + renderer->immediateContext, (ID3D11Resource*) stagingBuffer, 0, 0, @@ -2234,13 +2235,12 @@ static void D3D11_DownloadFromBuffer( 0, (ID3D11Resource*) d3d11Buffer->handle, 0, - &srcBox, - D3D11_COPY_NO_OVERWRITE + &srcBox ); /* Read from the staging buffer */ - res = ID3D11DeviceContext1_Map( - d3d11CommandBuffer->context, + res = ID3D11DeviceContext_Map( + renderer->immediateContext, stagingBuffer, 0, D3D11_MAP_READ, @@ -2265,12 +2265,11 @@ static void D3D11_DownloadFromBuffer( ); ID3D11DeviceContext1_Unmap( - d3d11CommandBuffer->context, + renderer->immediateContext, stagingBuffer, 0 ); - - D3D11_INTERNAL_TrackTransferBuffer(d3d11CommandBuffer, d3d11TransferBuffer); + SDL_UnlockMutex(renderer->contextLock); /* Clean up the staging buffer */ ID3D11Buffer_Release(stagingBuffer); diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 890644a..feb9fa6 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -8550,130 +8550,6 @@ static void VULKAN_UploadToBuffer( VULKAN_INTERNAL_TrackCopiedBuffer(renderer, vulkanCommandBuffer, gpuBufferContainer->activeBufferHandle->vulkanBuffer); } -static void VULKAN_DownloadFromTexture( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_TextureRegion *textureRegion, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferImageCopy *copyParams, - Refresh_TransferOptions transferOption -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - VulkanTextureSlice *vulkanTextureSlice; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer*) transferBuffer; - VkBufferImageCopy imageCopy; - - vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); - - if ( - transferOption == REFRESH_TRANSFEROPTIONS_SAFEDISCARD && - SDL_AtomicGet(&transferBufferContainer->activeBufferHandle->vulkanBuffer->referenceCount) > 0 - ) { - VULKAN_INTERNAL_DiscardActiveBuffer( - renderer, - transferBufferContainer - ); - vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); - } - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_WRITE, - transferBufferContainer->activeBufferHandle->vulkanBuffer - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_READ, - vulkanTextureSlice - ); - - imageCopy.imageExtent.width = textureRegion->w; - imageCopy.imageExtent.height = textureRegion->h; - imageCopy.imageExtent.depth = textureRegion->d; - imageCopy.imageOffset.x = textureRegion->x; - imageCopy.imageOffset.y = textureRegion->y; - imageCopy.imageOffset.z = textureRegion->z; - imageCopy.imageSubresource.aspectMask = vulkanTextureSlice->parent->aspectFlags; - imageCopy.imageSubresource.baseArrayLayer = textureRegion->textureSlice.layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = textureRegion->textureSlice.mipLevel; - imageCopy.bufferOffset = copyParams->bufferOffset; - imageCopy.bufferRowLength = copyParams->bufferStride; - imageCopy.bufferImageHeight = copyParams->bufferImageHeight; - - renderer->vkCmdCopyImageToBuffer( - vulkanCommandBuffer->commandBuffer, - vulkanTextureSlice->parent->image, - AccessMap[vulkanTextureSlice->resourceAccessType].imageLayout, - transferBufferContainer->activeBufferHandle->vulkanBuffer->buffer, - 1, - &imageCopy - ); - - VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, transferBufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); - VULKAN_INTERNAL_TrackCopiedTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); -} - -static void VULKAN_DownloadFromBuffer( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_GpuBuffer *gpuBuffer, - Refresh_TransferBuffer *transferBuffer, - Refresh_BufferCopy *copyParams, - Refresh_TransferOptions transferOption -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - VulkanBufferContainer *gpuBufferContainer = (VulkanBufferContainer*) gpuBuffer; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer*) transferBuffer; - VkBufferCopy bufferCopy; - - if ( - transferOption == REFRESH_TRANSFEROPTIONS_SAFEDISCARD && - SDL_AtomicGet(&transferBufferContainer->activeBufferHandle->vulkanBuffer->referenceCount) > 0 - ) { - VULKAN_INTERNAL_DiscardActiveBuffer( - renderer, - transferBufferContainer - ); - } - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_WRITE, - transferBufferContainer->activeBufferHandle->vulkanBuffer - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_READ, - gpuBufferContainer->activeBufferHandle->vulkanBuffer - ); - - bufferCopy.srcOffset = copyParams->srcOffset; - bufferCopy.dstOffset = copyParams->dstOffset; - bufferCopy.size = copyParams->size; - - renderer->vkCmdCopyBuffer( - vulkanCommandBuffer->commandBuffer, - gpuBufferContainer->activeBufferHandle->vulkanBuffer->buffer, - transferBufferContainer->activeBufferHandle->vulkanBuffer->buffer, - 1, - &bufferCopy - ); - - VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, transferBufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, gpuBufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackCopiedBuffer(renderer, vulkanCommandBuffer, gpuBufferContainer->activeBufferHandle->vulkanBuffer); -} - static void VULKAN_CopyTextureToTexture( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -8751,147 +8627,6 @@ static void VULKAN_CopyTextureToTexture( VULKAN_INTERNAL_TrackCopiedTextureSlice(renderer, vulkanCommandBuffer, dstSlice); } -static void VULKAN_CopyTextureToBuffer( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_TextureRegion *textureRegion, - Refresh_GpuBuffer *gpuBuffer, - Refresh_BufferImageCopy *copyParams, - Refresh_WriteOptions writeOption -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - VulkanTextureSlice *vulkanTextureSlice; - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer*) gpuBuffer; - VkBufferImageCopy imageCopy; - - vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); - - if ( - writeOption == REFRESH_WRITEOPTIONS_SAFEDISCARD && - SDL_AtomicGet(&bufferContainer->activeBufferHandle->vulkanBuffer->referenceCount) > 0 - ) { - VULKAN_INTERNAL_DiscardActiveBuffer( - renderer, - bufferContainer - ); - } - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_READ, - vulkanTextureSlice - ); - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_WRITE, - bufferContainer->activeBufferHandle->vulkanBuffer - ); - - imageCopy.imageExtent.width = textureRegion->w; - imageCopy.imageExtent.height = textureRegion->h; - imageCopy.imageExtent.depth = textureRegion->d; - imageCopy.imageOffset.x = textureRegion->x; - imageCopy.imageOffset.y = textureRegion->y; - imageCopy.imageOffset.z = textureRegion->z; - imageCopy.imageSubresource.aspectMask = vulkanTextureSlice->parent->aspectFlags; - imageCopy.imageSubresource.baseArrayLayer = textureRegion->textureSlice.layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = textureRegion->textureSlice.mipLevel; - imageCopy.bufferOffset = copyParams->bufferOffset; - imageCopy.bufferRowLength = copyParams->bufferStride; - imageCopy.bufferImageHeight = copyParams->bufferImageHeight; - - renderer->vkCmdCopyImageToBuffer( - vulkanCommandBuffer->commandBuffer, - vulkanTextureSlice->parent->image, - AccessMap[vulkanTextureSlice->resourceAccessType].imageLayout, - bufferContainer->activeBufferHandle->vulkanBuffer->buffer, - 1, - &imageCopy - ); - - VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, bufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); - VULKAN_INTERNAL_TrackCopiedBuffer(renderer, vulkanCommandBuffer, bufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackCopiedTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); -} - -static void VULKAN_CopyBufferToTexture( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_GpuBuffer *gpuBuffer, - Refresh_TextureRegion *textureRegion, - Refresh_BufferImageCopy *copyParams, - Refresh_WriteOptions writeOption -) { - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer*) gpuBuffer; - VulkanTextureContainer *textureContainer = (VulkanTextureContainer*) textureRegion->textureSlice.texture; - VulkanTextureSlice *vulkanTextureSlice; - VkBufferImageCopy imageCopy; - - vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); - - if ( - writeOption == REFRESH_WRITEOPTIONS_SAFEDISCARD && - textureContainer->canBeDiscarded && - SDL_AtomicGet(&vulkanTextureSlice->referenceCount) > 0 - ) { - VULKAN_INTERNAL_DiscardActiveTexture( - renderer, - textureContainer - ); - vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); - } - - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_READ, - bufferContainer->activeBufferHandle->vulkanBuffer - ); - - VULKAN_INTERNAL_ImageMemoryBarrier( - renderer, - vulkanCommandBuffer->commandBuffer, - RESOURCE_ACCESS_TRANSFER_WRITE, - vulkanTextureSlice - ); - - imageCopy.imageExtent.width = textureRegion->w; - imageCopy.imageExtent.height = textureRegion->h; - imageCopy.imageExtent.depth = textureRegion->d; - imageCopy.imageOffset.x = textureRegion->x; - imageCopy.imageOffset.y = textureRegion->y; - imageCopy.imageOffset.z = textureRegion->z; - imageCopy.imageSubresource.aspectMask = vulkanTextureSlice->parent->aspectFlags; - imageCopy.imageSubresource.baseArrayLayer = textureRegion->textureSlice.layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = textureRegion->textureSlice.mipLevel; - imageCopy.bufferOffset = copyParams->bufferOffset; - imageCopy.bufferRowLength = copyParams->bufferStride; - imageCopy.bufferImageHeight = copyParams->bufferImageHeight; - - renderer->vkCmdCopyBufferToImage( - vulkanCommandBuffer->commandBuffer, - bufferContainer->activeBufferHandle->vulkanBuffer->buffer, - vulkanTextureSlice->parent->image, - AccessMap[vulkanTextureSlice->resourceAccessType].imageLayout, - 1, - &imageCopy - ); - - VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, bufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); - VULKAN_INTERNAL_TrackCopiedBuffer(renderer, vulkanCommandBuffer, bufferContainer->activeBufferHandle->vulkanBuffer); - VULKAN_INTERNAL_TrackCopiedTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); -} - static void VULKAN_CopyBufferToBuffer( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -10461,6 +10196,137 @@ static void VULKAN_ReleaseFence( VULKAN_INTERNAL_ReturnFenceToPool((VulkanRenderer*) driverData, (VkFence) fence); } +/* Readback */ + +static void VULKAN_DownloadFromTexture( + Refresh_Renderer *driverData, + Refresh_TextureRegion *textureRegion, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferImageCopy *copyParams, + Refresh_TransferOptions transferOption +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanTextureSlice *vulkanTextureSlice; + VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer*) transferBuffer; + VkBufferImageCopy imageCopy; + vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); + Refresh_Fence *fence; + VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) VULKAN_AcquireCommandBuffer(driverData); + + if ( + transferOption == REFRESH_TRANSFEROPTIONS_SAFEDISCARD && + SDL_AtomicGet(&transferBufferContainer->activeBufferHandle->vulkanBuffer->referenceCount) > 0 + ) { + VULKAN_INTERNAL_DiscardActiveBuffer( + renderer, + transferBufferContainer + ); + vulkanTextureSlice = VULKAN_INTERNAL_RefreshToVulkanTextureSlice(&textureRegion->textureSlice); + } + + VULKAN_INTERNAL_BufferMemoryBarrier( + renderer, + vulkanCommandBuffer->commandBuffer, + RESOURCE_ACCESS_TRANSFER_WRITE, + transferBufferContainer->activeBufferHandle->vulkanBuffer + ); + + VULKAN_INTERNAL_ImageMemoryBarrier( + renderer, + vulkanCommandBuffer->commandBuffer, + RESOURCE_ACCESS_TRANSFER_READ, + vulkanTextureSlice + ); + + imageCopy.imageExtent.width = textureRegion->w; + imageCopy.imageExtent.height = textureRegion->h; + imageCopy.imageExtent.depth = textureRegion->d; + imageCopy.imageOffset.x = textureRegion->x; + imageCopy.imageOffset.y = textureRegion->y; + imageCopy.imageOffset.z = textureRegion->z; + imageCopy.imageSubresource.aspectMask = vulkanTextureSlice->parent->aspectFlags; + imageCopy.imageSubresource.baseArrayLayer = textureRegion->textureSlice.layer; + imageCopy.imageSubresource.layerCount = 1; + imageCopy.imageSubresource.mipLevel = textureRegion->textureSlice.mipLevel; + imageCopy.bufferOffset = copyParams->bufferOffset; + imageCopy.bufferRowLength = copyParams->bufferStride; + imageCopy.bufferImageHeight = copyParams->bufferImageHeight; + + renderer->vkCmdCopyImageToBuffer( + vulkanCommandBuffer->commandBuffer, + vulkanTextureSlice->parent->image, + AccessMap[vulkanTextureSlice->resourceAccessType].imageLayout, + transferBufferContainer->activeBufferHandle->vulkanBuffer->buffer, + 1, + &imageCopy + ); + + VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, transferBufferContainer->activeBufferHandle->vulkanBuffer); + VULKAN_INTERNAL_TrackTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); + VULKAN_INTERNAL_TrackCopiedTextureSlice(renderer, vulkanCommandBuffer, vulkanTextureSlice); + + fence = VULKAN_SubmitAndAcquireFence(driverData, (Refresh_CommandBuffer*) vulkanCommandBuffer); + VULKAN_WaitForFences(driverData, 1, 1, &fence); +} + +static void VULKAN_DownloadFromBuffer( + Refresh_Renderer *driverData, + Refresh_GpuBuffer *gpuBuffer, + Refresh_TransferBuffer *transferBuffer, + Refresh_BufferCopy *copyParams, + Refresh_TransferOptions transferOption +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanBufferContainer *gpuBufferContainer = (VulkanBufferContainer*) gpuBuffer; + VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer*) transferBuffer; + VkBufferCopy bufferCopy; + Refresh_Fence *fence; + VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) VULKAN_AcquireCommandBuffer(driverData); + + if ( + transferOption == REFRESH_TRANSFEROPTIONS_SAFEDISCARD && + SDL_AtomicGet(&transferBufferContainer->activeBufferHandle->vulkanBuffer->referenceCount) > 0 + ) { + VULKAN_INTERNAL_DiscardActiveBuffer( + renderer, + transferBufferContainer + ); + } + + VULKAN_INTERNAL_BufferMemoryBarrier( + renderer, + vulkanCommandBuffer->commandBuffer, + RESOURCE_ACCESS_TRANSFER_WRITE, + transferBufferContainer->activeBufferHandle->vulkanBuffer + ); + + VULKAN_INTERNAL_BufferMemoryBarrier( + renderer, + vulkanCommandBuffer->commandBuffer, + RESOURCE_ACCESS_TRANSFER_READ, + gpuBufferContainer->activeBufferHandle->vulkanBuffer + ); + + bufferCopy.srcOffset = copyParams->srcOffset; + bufferCopy.dstOffset = copyParams->dstOffset; + bufferCopy.size = copyParams->size; + + renderer->vkCmdCopyBuffer( + vulkanCommandBuffer->commandBuffer, + gpuBufferContainer->activeBufferHandle->vulkanBuffer->buffer, + transferBufferContainer->activeBufferHandle->vulkanBuffer->buffer, + 1, + &bufferCopy + ); + + VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, transferBufferContainer->activeBufferHandle->vulkanBuffer); + VULKAN_INTERNAL_TrackBuffer(renderer, vulkanCommandBuffer, gpuBufferContainer->activeBufferHandle->vulkanBuffer); + VULKAN_INTERNAL_TrackCopiedBuffer(renderer, vulkanCommandBuffer, gpuBufferContainer->activeBufferHandle->vulkanBuffer); + + fence = VULKAN_SubmitAndAcquireFence(driverData, (Refresh_CommandBuffer*) vulkanCommandBuffer); + VULKAN_WaitForFences(driverData, 1, 1, &fence); +} + /* Device instantiation */ static inline uint8_t CheckDeviceExtensions(