diff --git a/include/Refresh.h b/include/Refresh.h index 3ef21e9..5a5f573 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -1063,7 +1063,6 @@ REFRESHAPI void REFRESH_SetFragmentSamplers( * h: The height of the subregion being read. * level: The mipmap level being read. * data: The pointer being filled with the image data. - * dataLength: The size of the image data in bytes. */ REFRESHAPI void REFRESH_GetTextureData2D( REFRESH_Device *device, @@ -1073,8 +1072,7 @@ REFRESHAPI void REFRESH_GetTextureData2D( uint32_t w, uint32_t h, uint32_t level, - void* data, - uint32_t dataLength + void* data ); /* Pulls image data from a single face of a texture cube object into client @@ -1082,15 +1080,14 @@ REFRESHAPI void REFRESH_GetTextureData2D( * point, don't call this unless there's absolutely no other way to use the * image data! * - * texture: The texture object being read. - * x: The x offset of the subregion being read. - * y: The y offset of the subregion being read. - * w: The width of the subregion being read. - * h: The height of the subregion being read. + * texture: The texture object being read. + * x: The x offset of the subregion being read. + * y: The y offset of the subregion being read. + * w: The width of the subregion being read. + * 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. - * dataLength: The size of the image data in bytes. + * level: The mipmap level being read. + * data: The pointer being filled with the image data. */ REFRESHAPI void REFRESH_GetTextureDataCube( REFRESH_Device *device, @@ -1101,8 +1098,7 @@ REFRESHAPI void REFRESH_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data, - uint32_t dataLength + void* data ); /* Disposal */ diff --git a/src/Refresh.c b/src/Refresh.c index 6cf040a..1cb830e 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -607,8 +607,7 @@ void REFRESH_GetTextureData2D( uint32_t w, uint32_t h, uint32_t level, - void* data, - uint32_t dataLength + void* data ) { NULL_RETURN(device); device->GetTextureData2D( @@ -619,8 +618,7 @@ void REFRESH_GetTextureData2D( w, h, level, - data, - dataLength + data ); } @@ -633,8 +631,7 @@ void REFRESH_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data, - uint32_t dataLength + void* data ) { NULL_RETURN(device); device->GetTextureDataCube( @@ -646,8 +643,7 @@ void REFRESH_GetTextureDataCube( h, cubeMapFace, level, - data, - dataLength + data ); } diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 9a09f9a..dc3558a 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -395,8 +395,7 @@ struct REFRESH_Device uint32_t w, uint32_t h, uint32_t level, - void* data, - uint32_t dataLength + void* data ); void(*GetTextureDataCube)( @@ -408,8 +407,7 @@ struct REFRESH_Device uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data, - uint32_t dataLength + void* data ); /* Disposal */ diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index b2326d2..575db81 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -713,8 +713,14 @@ typedef struct VulkanTexture uint32_t layerCount; uint32_t levelCount; VkFormat format; + REFRESH_SurfaceFormat refreshFormat; VulkanResourceAccessType resourceAccessType; REFRESH_TextureUsageFlags usageFlags; + REFRESHNAMELESS union + { + REFRESH_SurfaceFormat colorFormat; + REFRESH_DepthFormat depthStencilFormat; + }; } VulkanTexture; typedef struct VulkanColorTarget @@ -4805,6 +4811,7 @@ static REFRESH_Texture* VULKAN_CreateTexture2D( usageFlags, result ); + result->colorFormat = format; return (REFRESH_Texture*) result; } @@ -4849,6 +4856,7 @@ static REFRESH_Texture* VULKAN_CreateTexture3D( usageFlags, result ); + result->colorFormat = format; return (REFRESH_Texture*) result; } @@ -4891,6 +4899,7 @@ static REFRESH_Texture* VULKAN_CreateTextureCube( usageFlags, result ); + result->colorFormat = format; return (REFRESH_Texture*) result; } @@ -4925,7 +4934,7 @@ static REFRESH_ColorTarget* VULKAN_CreateColorTarget( 0, RefreshToVK_SampleCount[multisampleCount], 1, - RefreshToVK_SurfaceFormat[colorTarget->texture->format], + colorTarget->texture->format, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TYPE_2D, @@ -4933,6 +4942,7 @@ static REFRESH_ColorTarget* VULKAN_CreateColorTarget( REFRESH_TEXTUREUSAGE_COLOR_TARGET_BIT, colorTarget->multisampleTexture ); + colorTarget->multisampleTexture->colorFormat = colorTarget->texture->colorFormat; colorTarget->multisampleCount = multisampleCount; VULKAN_INTERNAL_ImageMemoryBarrier( @@ -5027,6 +5037,7 @@ static REFRESH_DepthStencilTarget* VULKAN_CreateDepthStencilTarget( 0, texture ); + texture->depthStencilFormat = format; depthStencilTarget->texture = texture; depthStencilTarget->view = texture->view; @@ -5960,6 +5971,124 @@ static void VULKAN_SetFragmentSamplers( ); } +static void VULKAN_INTERNAL_GetTextureData( + REFRESH_Renderer *driverData, + REFRESH_Texture *texture, + int32_t x, + int32_t y, + int32_t w, + int32_t h, + int32_t level, + int32_t layer, + void* data +) { + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanTexture *vulkanTexture = (VulkanTexture*) texture; + 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, + RESOURCE_ACCESS_TRANSFER_READ, + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + vulkanTexture->layerCount, + 0, + vulkanTexture->levelCount, + 0, + vulkanTexture->image, + &vulkanTexture->resourceAccessType + ); + + /* Save texture data to staging buffer */ + + imageCopy.imageExtent.width = w; + imageCopy.imageExtent.height = h; + imageCopy.imageExtent.depth = 1; + imageCopy.bufferRowLength = w; + imageCopy.bufferImageHeight = h; + imageCopy.imageOffset.x = x; + imageCopy.imageOffset.y = y; + imageCopy.imageOffset.z = 0; + imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopy.imageSubresource.baseArrayLayer = layer; + imageCopy.imageSubresource.layerCount = 1; + imageCopy.imageSubresource.mipLevel = level; + imageCopy.bufferOffset = 0; + + RECORD_CMD(renderer->vkCmdCopyImageToBuffer( + renderer->currentCommandBuffer, + vulkanTexture->image, + AccessMap[vulkanTexture->resourceAccessType].imageLayout, + renderer->textureStagingBuffer->subBuffers[0]->buffer, + 1, + &imageCopy + )); + + /* Restore the image layout and wait for completion of the render pass */ + + VULKAN_INTERNAL_ImageMemoryBarrier( + renderer, + prevResourceAccess, + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + vulkanTexture->layerCount, + 0, + vulkanTexture->levelCount, + 0, + vulkanTexture->image, + &vulkanTexture->resourceAccessType + ); + + /* hard sync point */ + VULKAN_Submit(driverData); + + renderer->vkWaitForFences( + renderer->logicalDevice, + 1, + &renderer->inFlightFence, + VK_TRUE, + UINT64_MAX + ); + + /* 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( REFRESH_Renderer *driverData, REFRESH_Texture *texture, @@ -5968,10 +6097,19 @@ static void VULKAN_GetTextureData2D( uint32_t w, uint32_t h, uint32_t level, - void* data, - uint32_t dataLength + void* data ) { - SDL_assert(0); + VULKAN_INTERNAL_GetTextureData( + driverData, + texture, + x, + y, + w, + h, + level, + 0, + data + ); } static void VULKAN_GetTextureDataCube( @@ -5983,10 +6121,19 @@ static void VULKAN_GetTextureDataCube( uint32_t h, REFRESH_CubeMapFace cubeMapFace, uint32_t level, - void* data, - uint32_t dataLength + void* data ) { - SDL_assert(0); + VULKAN_INTERNAL_GetTextureData( + driverData, + texture, + x, + y, + w, + h, + level, + cubeMapFace, + data + ); } static void VULKAN_AddDisposeTexture(