From b4dee16f808d336bfbafafcc239903ba64f006d7 Mon Sep 17 00:00:00 2001
From: thatcosmonaut <2342303+thatcosmonaut@users.noreply.github.com>
Date: Sun, 3 Jan 2021 14:37:02 -0800
Subject: [PATCH] Texture API Refactor (#9)

---
 include/Refresh.h           |  97 +--------
 src/Refresh.c               |  98 +--------
 src/Refresh_Driver.h        |  51 +----
 src/Refresh_Driver_Vulkan.c | 422 ++++++------------------------------
 4 files changed, 97 insertions(+), 571 deletions(-)

diff --git a/include/Refresh.h b/include/Refresh.h
index e802c5b..f9cbe00 100644
--- a/include/Refresh.h
+++ b/include/Refresh.h
@@ -391,7 +391,9 @@ typedef struct REFRESH_Viewport
 typedef struct REFRESH_TextureSlice
 {
 	REFRESH_Texture *texture;
-	uint32_t layer; /* 0-5 for cube, or z-slice for 3D */
+	REFRESH_Rect rectangle;
+	uint32_t depth; /* 0 unless 3D */
+	uint32_t layer; /* 0 unless cube */
 	uint32_t level;
 } REFRESH_TextureSlice;
 
@@ -890,81 +892,19 @@ REFRESHAPI REFRESH_Buffer* REFRESH_CreateBuffer(
 
 /* Setters */
 
-/* Uploads image data to a 2D texture object.
+/* Uploads image data to a texture object.
  *
- * texture:	The texture to be updated.
- * x:		The x offset of the subregion being updated.
- * y:		The y offset of the subregion being updated.
- * w:		The width of the subregion being updated.
- * h:		The height of the subregion being updated.
- * level:	The mipmap level being updated.
- * data:	A pointer to the image data.
- * dataLength:	The size of the image data in bytes.
+ * 	textureSlice:		The texture slice to be updated.
+ * 	data:				A pointer to the image data.
+ * 	dataLengthInBytes:	The size of the image data.
  */
-REFRESHAPI void REFRESH_SetTextureData2D(
+REFRESHAPI void REFRESH_SetTextureData(
 	REFRESH_Device *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	uint32_t level,
+	REFRESH_TextureSlice *textureSlice,
 	void *data,
 	uint32_t dataLengthInBytes
 );
 
-/* Uploads image data to a 3D texture object.
- *
- * texture:	The texture to be updated.
- * x:		The x offset of the subregion being updated.
- * y:		The y offset of the subregion being updated.
- * z:		The z offset of the subregion being updated.
- * w:		The width of the subregion being updated.
- * h:		The height of the subregion being updated.
- * d:		The depth of the subregion being updated.
- * level:	The mipmap level being updated.
- * data:	A pointer to the image data.
- * dataLength:	The size of the image data in bytes.
- */
-REFRESHAPI void REFRESH_SetTextureData3D(
-	REFRESH_Device *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t z,
-	uint32_t w,
-	uint32_t h,
-	uint32_t d,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-);
-
-/* Uploads image data to a single face of a texture cube object.
- *
- * texture:	The texture to be updated.
- * x:		The x offset of the subregion being updated.
- * y:		The y offset of the subregion being updated.
- * w:		The width of the subregion being updated.
- * h:		The height of the subregion being updated.
- * cubeMapFace:	The face of the cube being updated.
- * level:	The mipmap level being updated.
- * data:	A pointer to the image data.
- * dataLength:	The size of the image data in bytes.
- */
-REFRESHAPI void REFRESH_SetTextureDataCube(
-	REFRESH_Device *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	REFRESH_CubeMapFace cubeMapFace,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-);
-
 /* Uploads YUV image data to three R8 texture objects.
  *
  * y:		The texture storing the Y data.
@@ -994,8 +934,6 @@ REFRESHAPI void REFRESH_SetTextureDataYUV(
  *
  * sourceTextureSlice:		The texture slice from which to copy.
  * destinationTextureSlice:	The texture slice to copy to.
- * sourceRectangle:			The region on the source texture slice to copy from. Can be NULL.
- * destinationRectangle:	The region on the destination texture slice to copy to. Can be NULL.
  * filter:					The filter that will be used if the copy requires scaling.
  */
 REFRESHAPI void REFRESH_CopyTextureToTexture(
@@ -1003,8 +941,6 @@ REFRESHAPI void REFRESH_CopyTextureToTexture(
 	REFRESH_CommandBuffer *commandBuffer,
 	REFRESH_TextureSlice *sourceTextureSlice,
 	REFRESH_TextureSlice *destinationTextureSlice,
-	REFRESH_Rect *sourceRectangle,
-	REFRESH_Rect *destinationRectangle,
 	REFRESH_Filter filter
 );
 
@@ -1015,21 +951,12 @@ REFRESHAPI void REFRESH_CopyTextureToTexture(
  * 	is submitted and completed.
  *
  * textureSlice:	The texture object being copied.
- * 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.
- * level:			The mipmap level being read.
  * buffer:			The buffer being filled with the image data.
  */
 REFRESHAPI void REFRESH_CopyTextureToBuffer(
 	REFRESH_Device *device,
 	REFRESH_CommandBuffer *commandBuffer,
-	REFRESH_TextureSlice *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
+	REFRESH_TextureSlice *textureSlice,
 	REFRESH_Buffer *buffer
 );
 
@@ -1392,15 +1319,13 @@ REFRESHAPI REFRESH_CommandBuffer* REFRESH_AcquireCommandBuffer(
  *		It is an error to call this function in headless mode.
  *
  * textureSlice:			The texture slice to present.
- * sourceRectangle:			The region of the image to present (or NULL).
- * destinationRectangle:	The region of the window to update (or NULL).
+ * destinationRectangle:	The region of the window to update. Can be NULL.
  * filter:					The filter to use if scaling is required.
  */
 REFRESHAPI void REFRESH_QueuePresent(
 	REFRESH_Device *device,
 	REFRESH_CommandBuffer *commandBuffer,
 	REFRESH_TextureSlice *textureSlice,
-	REFRESH_Rect *sourceRectangle,
 	REFRESH_Rect *destinationRectangle,
 	REFRESH_Filter filter
 );
diff --git a/src/Refresh.c b/src/Refresh.c
index a5b8af1..bdc97fb 100644
--- a/src/Refresh.c
+++ b/src/Refresh.c
@@ -432,87 +432,21 @@ REFRESH_Buffer* REFRESH_CreateBuffer(
     );
 }
 
-void REFRESH_SetTextureData2D(
+void REFRESH_SetTextureData(
 	REFRESH_Device *device,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	uint32_t level,
+	REFRESH_TextureSlice *textureSlice,
 	void *data,
 	uint32_t dataLengthInBytes
 ) {
     NULL_RETURN(device);
-    device->SetTextureData2D(
+    device->SetTextureData(
         device->driverData,
-        texture,
-        x,
-        y,
-        w,
-        h,
-        level,
+        textureSlice,
         data,
         dataLengthInBytes
     );
 }
 
-void REFRESH_SetTextureData3D(
-	REFRESH_Device *device,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t z,
-	uint32_t w,
-	uint32_t h,
-	uint32_t d,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-) {
-    NULL_RETURN(device);
-    device->SetTextureData3D(
-        device->driverData,
-        texture,
-        x,
-        y,
-        z,
-        w,
-        h,
-        d,
-        level,
-        data,
-        dataLength
-    );
-}
-
-void REFRESH_SetTextureDataCube(
-	REFRESH_Device *device,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	REFRESH_CubeMapFace cubeMapFace,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-) {
-    NULL_RETURN(device);
-    device->SetTextureDataCube(
-        device->driverData,
-        texture,
-        x,
-        y,
-        w,
-        h,
-        cubeMapFace,
-        level,
-        data,
-        dataLength
-    );
-}
-
 void REFRESH_SetTextureDataYUV(
 	REFRESH_Device *device,
 	REFRESH_Texture *y,
@@ -542,12 +476,10 @@ void REFRESH_SetTextureDataYUV(
 
 void REFRESH_CopyTextureToTexture(
     REFRESH_Device *device,
-    REFRESH_CommandBuffer *commandBuffer,
-    REFRESH_TextureSlice *sourceTextureSlice,
+	REFRESH_CommandBuffer *commandBuffer,
+	REFRESH_TextureSlice *sourceTextureSlice,
 	REFRESH_TextureSlice *destinationTextureSlice,
-	REFRESH_Rect *sourceRectangle,
-	REFRESH_Rect *destinationRectangle,
-    REFRESH_Filter filter
+	REFRESH_Filter filter
 ) {
     NULL_RETURN(device);
     device->CopyTextureToTexture(
@@ -555,31 +487,21 @@ void REFRESH_CopyTextureToTexture(
         commandBuffer,
         sourceTextureSlice,
         destinationTextureSlice,
-        sourceRectangle,
-        destinationRectangle,
         filter
     );
 }
 
 void REFRESH_CopyTextureToBuffer(
 	REFRESH_Device *device,
-    REFRESH_CommandBuffer *commandBuffer,
+	REFRESH_CommandBuffer *commandBuffer,
 	REFRESH_TextureSlice *textureSlice,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-    REFRESH_Buffer* buffer
+	REFRESH_Buffer *buffer
 ) {
     NULL_RETURN(device);
     device->CopyTextureToBuffer(
         device->driverData,
         commandBuffer,
         textureSlice,
-        x,
-        y,
-        w,
-        h,
         buffer
     );
 }
@@ -938,7 +860,6 @@ void REFRESH_QueuePresent(
     REFRESH_Device *device,
     REFRESH_CommandBuffer *commandBuffer,
     REFRESH_TextureSlice* textureSlice,
-    REFRESH_Rect *sourceRectangle,
     REFRESH_Rect *destinationRectangle,
     REFRESH_Filter filter
 ) {
@@ -947,7 +868,6 @@ void REFRESH_QueuePresent(
         device->driverData,
         commandBuffer,
         textureSlice,
-        sourceRectangle,
         destinationRectangle,
         filter
     );
diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h
index aa181eb..0024be4 100644
--- a/src/Refresh_Driver.h
+++ b/src/Refresh_Driver.h
@@ -305,45 +305,13 @@ struct REFRESH_Device
 
     /* Setters */
 
-    void(*SetTextureData2D)(
+    void(*SetTextureData)(
         REFRESH_Renderer *driverData,
-        REFRESH_Texture *texture,
-        uint32_t x,
-        uint32_t y,
-        uint32_t w,
-        uint32_t h,
-        uint32_t level,
+        REFRESH_TextureSlice *textureSlice,
         void *data,
         uint32_t dataLengthInBytes
     );
 
-    void(*SetTextureData3D)(
-        REFRESH_Renderer *driverData,
-        REFRESH_Texture *texture,
-        uint32_t x,
-        uint32_t y,
-        uint32_t z,
-        uint32_t w,
-        uint32_t h,
-        uint32_t d,
-        uint32_t level,
-        void* data,
-        uint32_t dataLength
-    );
-
-    void(*SetTextureDataCube)(
-        REFRESH_Renderer *driverData,
-        REFRESH_Texture *texture,
-        uint32_t x,
-        uint32_t y,
-        uint32_t w,
-        uint32_t h,
-        REFRESH_CubeMapFace cubeMapFace,
-        uint32_t level,
-        void* data,
-        uint32_t dataLength
-    );
-
     void(*SetTextureDataYUV)(
         REFRESH_Renderer *driverData,
         REFRESH_Texture *y,
@@ -361,9 +329,7 @@ struct REFRESH_Device
         REFRESH_Renderer *driverData,
         REFRESH_CommandBuffer *commandBuffer,
         REFRESH_TextureSlice *sourceTextureSlice,
-        REFRESH_TextureSlice *destinationTexture,
-        REFRESH_Rect *sourceRectangle,
-        REFRESH_Rect *destinationRectangle,
+        REFRESH_TextureSlice *destinationTextureSlice,
         REFRESH_Filter filter
     );
 
@@ -371,11 +337,7 @@ struct REFRESH_Device
         REFRESH_Renderer *driverData,
         REFRESH_CommandBuffer *commandBuffer,
         REFRESH_TextureSlice *textureSlice,
-        uint32_t x,
-        uint32_t y,
-        uint32_t w,
-        uint32_t h,
-        REFRESH_Buffer* buffer
+        REFRESH_Buffer *buffer
     );
 
     void(*SetBufferData)(
@@ -550,7 +512,6 @@ struct REFRESH_Device
         REFRESH_Renderer *driverData,
         REFRESH_CommandBuffer *commandBuffer,
         REFRESH_TextureSlice *textureSlice,
-        REFRESH_Rect *sourceRectangle,
         REFRESH_Rect *destinationRectangle,
         REFRESH_Filter filter
     );
@@ -590,9 +551,7 @@ struct REFRESH_Device
     ASSIGN_DRIVER_FUNC(CreateColorTarget, name) \
     ASSIGN_DRIVER_FUNC(CreateDepthStencilTarget, name) \
     ASSIGN_DRIVER_FUNC(CreateBuffer, name) \
-    ASSIGN_DRIVER_FUNC(SetTextureData2D, name) \
-    ASSIGN_DRIVER_FUNC(SetTextureData3D, name) \
-    ASSIGN_DRIVER_FUNC(SetTextureDataCube, name) \
+    ASSIGN_DRIVER_FUNC(SetTextureData, name) \
     ASSIGN_DRIVER_FUNC(SetTextureDataYUV, name) \
     ASSIGN_DRIVER_FUNC(CopyTextureToTexture, name) \
     ASSIGN_DRIVER_FUNC(CopyTextureToBuffer, name) \
diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c
index 89b8f5d..ab6a8f4 100644
--- a/src/Refresh_Driver_Vulkan.c
+++ b/src/Refresh_Driver_Vulkan.c
@@ -749,6 +749,10 @@ typedef struct VulkanTexture
 	VkImage image;
 	VkImageView view;
 	VkExtent2D dimensions;
+
+	uint8_t is3D;
+	uint8_t isCube;
+
 	uint32_t depth;
 	uint32_t layerCount;
 	uint32_t levelCount;
@@ -5412,13 +5416,18 @@ static uint8_t VULKAN_INTERNAL_CreateTexture(
 	uint8_t layerCount = isCube ? 6 : 1;
 	VkComponentMapping swizzle = IDENTITY_SWIZZLE;
 
+	texture->isCube = 0;
+	texture->is3D = 0;
+
 	if (isCube)
 	{
 		imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+		texture->isCube = 1;
 	}
 	else if (is3D)
 	{
 		imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
+		texture->is3D = 1;
 	}
 
 	imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
@@ -5727,7 +5736,15 @@ static REFRESH_ColorTarget* VULKAN_CreateColorTarget(
 	imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
 	imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
 	imageViewCreateInfo.subresourceRange.levelCount = 1;
-	imageViewCreateInfo.subresourceRange.baseArrayLayer = textureSlice->layer;
+	imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
+	if (colorTarget->texture->is3D)
+	{
+		imageViewCreateInfo.subresourceRange.baseArrayLayer = textureSlice->depth;
+	}
+	else if (colorTarget->texture->isCube)
+	{
+		imageViewCreateInfo.subresourceRange.baseArrayLayer = textureSlice->layer;
+	}
 	imageViewCreateInfo.subresourceRange.layerCount = 1;
 	imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
 
@@ -5994,23 +6011,18 @@ static void VULKAN_INTERNAL_FlushTransfers(
 	}
 }
 
-static void VULKAN_SetTextureData2D(
+static void VULKAN_SetTextureData(
 	REFRESH_Renderer *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	uint32_t level,
+	REFRESH_TextureSlice *textureSlice,
 	void *data,
 	uint32_t dataLengthInBytes
 ) {
 	VulkanRenderer *renderer = (VulkanRenderer*) driverData;
+	VulkanTexture *vulkanTexture = (VulkanTexture*) textureSlice->texture;
 
 	VkCommandBuffer commandBuffer = renderer->transferCommandBuffers[renderer->frameIndex];
-	VkResult vulkanResult;
-	VulkanTexture *vulkanTexture = (VulkanTexture*) texture;
 	VkBufferImageCopy imageCopy;
+	VkResult vulkanResult;
 	uint8_t *mapPointer;
 
 	SDL_LockMutex(renderer->stagingLock);
@@ -6051,25 +6063,25 @@ static void VULKAN_SetTextureData2D(
 		commandBuffer,
 		RESOURCE_ACCESS_TRANSFER_WRITE,
 		VK_IMAGE_ASPECT_COLOR_BIT,
-		0,
-		vulkanTexture->layerCount,
-		0,
-		vulkanTexture->levelCount,
+		textureSlice->layer,
+		1,
+		textureSlice->level,
+		1,
 		0,
 		vulkanTexture->image,
 		&vulkanTexture->resourceAccessType
 	);
 
-	imageCopy.imageExtent.width = w;
-	imageCopy.imageExtent.height = h;
+	imageCopy.imageExtent.width = textureSlice->rectangle.w;
+	imageCopy.imageExtent.height = textureSlice->rectangle.h;
 	imageCopy.imageExtent.depth = 1;
-	imageCopy.imageOffset.x = x;
-	imageCopy.imageOffset.y = y;
-	imageCopy.imageOffset.z = 0;
+	imageCopy.imageOffset.x = textureSlice->rectangle.x;
+	imageCopy.imageOffset.y = textureSlice->rectangle.y;
+	imageCopy.imageOffset.z = textureSlice->depth;
 	imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	imageCopy.imageSubresource.baseArrayLayer = 0;
+	imageCopy.imageSubresource.baseArrayLayer = textureSlice->layer;
 	imageCopy.imageSubresource.layerCount = 1;
-	imageCopy.imageSubresource.mipLevel = level;
+	imageCopy.imageSubresource.mipLevel = textureSlice->level;
 	imageCopy.bufferOffset = renderer->textureStagingBufferOffset;
 	imageCopy.bufferRowLength = 0;
 	imageCopy.bufferImageHeight = 0;
@@ -6092,235 +6104,10 @@ static void VULKAN_SetTextureData2D(
 			commandBuffer,
 			RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE,
 			VK_IMAGE_ASPECT_COLOR_BIT,
-			0,
-			vulkanTexture->layerCount,
-			0,
-			vulkanTexture->levelCount,
-			0,
-			vulkanTexture->image,
-			&vulkanTexture->resourceAccessType
-		);
-	}
-
-	SDL_UnlockMutex(renderer->stagingLock);
-}
-
-static void VULKAN_SetTextureData3D(
-	REFRESH_Renderer *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t z,
-	uint32_t w,
-	uint32_t h,
-	uint32_t d,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-) {
-	VulkanRenderer *renderer = (VulkanRenderer*) driverData;
-	VulkanTexture *vulkanTexture = (VulkanTexture*) texture;
-
-	VkCommandBuffer commandBuffer = renderer->transferCommandBuffers[renderer->frameIndex];
-	VkResult vulkanResult;
-	VkBufferImageCopy imageCopy;
-	uint8_t *mapPointer;
-
-	SDL_LockMutex(renderer->stagingLock);
-
-	VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength);
-	VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer);
-
-	SDL_LockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-
-	vulkanResult = renderer->vkMapMemory(
-		renderer->logicalDevice,
-		renderer->textureStagingBuffer->subBuffers[0]->allocation->memory,
-		renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset,
-		renderer->textureStagingBuffer->subBuffers[0]->size,
-		0,
-		(void**) &mapPointer
-	);
-
-	if (vulkanResult != VK_SUCCESS)
-	{
-		REFRESH_LogError("Failed to map buffer memory!");
-		SDL_UnlockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-		SDL_UnlockMutex(renderer->stagingLock);
-		return;
-	}
-
-	SDL_memcpy(mapPointer, data, dataLength);
-
-	renderer->vkUnmapMemory(
-		renderer->logicalDevice,
-		renderer->textureStagingBuffer->subBuffers[0]->allocation->memory
-	);
-
-	SDL_UnlockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-
-	VULKAN_INTERNAL_ImageMemoryBarrier(
-		renderer,
-		commandBuffer,
-		RESOURCE_ACCESS_TRANSFER_WRITE,
-		VK_IMAGE_ASPECT_COLOR_BIT,
-		0,
-		vulkanTexture->layerCount,
-		0,
-		vulkanTexture->levelCount,
-		0,
-		vulkanTexture->image,
-		&vulkanTexture->resourceAccessType
-	);
-
-	imageCopy.imageExtent.width = w;
-	imageCopy.imageExtent.height = h;
-	imageCopy.imageExtent.depth = d;
-	imageCopy.imageOffset.x = x;
-	imageCopy.imageOffset.y = y;
-	imageCopy.imageOffset.z = z;
-	imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	imageCopy.imageSubresource.baseArrayLayer = 0;
-	imageCopy.imageSubresource.layerCount = 1;
-	imageCopy.imageSubresource.mipLevel = level;
-	imageCopy.bufferOffset = renderer->textureStagingBufferOffset;
-	imageCopy.bufferRowLength = 0;
-	imageCopy.bufferImageHeight = 0;
-
-	renderer->vkCmdCopyBufferToImage(
-		commandBuffer,
-		renderer->textureStagingBuffer->subBuffers[0]->buffer,
-		vulkanTexture->image,
-		AccessMap[vulkanTexture->resourceAccessType].imageLayout,
-		1,
-		&imageCopy
-	);
-
-	renderer->textureStagingBufferOffset += dataLength;
-
-	if (vulkanTexture->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT)
-	{
-		VULKAN_INTERNAL_ImageMemoryBarrier(
-			renderer,
-			commandBuffer,
-			RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE,
-			VK_IMAGE_ASPECT_COLOR_BIT,
-			0,
-			vulkanTexture->layerCount,
-			0,
-			vulkanTexture->levelCount,
-			0,
-			vulkanTexture->image,
-			&vulkanTexture->resourceAccessType
-		);
-	}
-
-	SDL_UnlockMutex(renderer->stagingLock);
-}
-
-static void VULKAN_SetTextureDataCube(
-	REFRESH_Renderer *driverData,
-	REFRESH_Texture *texture,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	REFRESH_CubeMapFace cubeMapFace,
-	uint32_t level,
-	void* data,
-	uint32_t dataLength
-) {
-	VulkanRenderer *renderer = (VulkanRenderer*) driverData;
-	VulkanTexture *vulkanTexture = (VulkanTexture*) texture;
-
-	VkCommandBuffer commandBuffer = renderer->transferCommandBuffers[renderer->frameIndex];
-	VkResult vulkanResult;
-	VkBufferImageCopy imageCopy;
-	uint8_t *mapPointer;
-
-	SDL_LockMutex(renderer->stagingLock);
-
-	VULKAN_INTERNAL_MaybeExpandStagingBuffer(renderer, dataLength);
-	VULKAN_INTERNAL_MaybeBeginTransferCommandBuffer(renderer);
-
-	SDL_LockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-
-	vulkanResult = renderer->vkMapMemory(
-		renderer->logicalDevice,
-		renderer->textureStagingBuffer->subBuffers[0]->allocation->memory,
-		renderer->textureStagingBuffer->subBuffers[0]->offset + renderer->textureStagingBufferOffset,
-		renderer->textureStagingBuffer->subBuffers[0]->size,
-		0,
-		(void**) &mapPointer
-	);
-
-	if (vulkanResult != VK_SUCCESS)
-	{
-		REFRESH_LogError("Failed to map buffer memory!");
-		SDL_UnlockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-		SDL_UnlockMutex(renderer->stagingLock);
-		return;
-	}
-
-	SDL_memcpy(mapPointer, data, dataLength);
-
-	renderer->vkUnmapMemory(
-		renderer->logicalDevice,
-		renderer->textureStagingBuffer->subBuffers[0]->allocation->memory
-	);
-
-	SDL_UnlockMutex(renderer->textureStagingBuffer->subBuffers[0]->allocation->memoryLock);
-
-	VULKAN_INTERNAL_ImageMemoryBarrier(
-		renderer,
-		commandBuffer,
-		RESOURCE_ACCESS_TRANSFER_WRITE,
-		VK_IMAGE_ASPECT_COLOR_BIT,
-		0,
-		vulkanTexture->layerCount,
-		0,
-		vulkanTexture->levelCount,
-		0,
-		vulkanTexture->image,
-		&vulkanTexture->resourceAccessType
-	);
-
-	imageCopy.imageExtent.width = w;
-	imageCopy.imageExtent.height = h;
-	imageCopy.imageExtent.depth = 1;
-	imageCopy.imageOffset.x = x;
-	imageCopy.imageOffset.y = y;
-	imageCopy.imageOffset.z = 0;
-	imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	imageCopy.imageSubresource.baseArrayLayer = cubeMapFace;
-	imageCopy.imageSubresource.layerCount = 1;
-	imageCopy.imageSubresource.mipLevel = level;
-	imageCopy.bufferOffset = renderer->textureStagingBufferOffset;
-	imageCopy.bufferRowLength = 0; /* assumes tightly packed data */
-	imageCopy.bufferImageHeight = 0; /* assumes tightly packed data */
-
-	renderer->vkCmdCopyBufferToImage(
-		commandBuffer,
-		renderer->textureStagingBuffer->subBuffers[0]->buffer,
-		vulkanTexture->image,
-		AccessMap[vulkanTexture->resourceAccessType].imageLayout,
-		1,
-		&imageCopy
-	);
-
-	renderer->textureStagingBufferOffset += dataLength;
-
-	if (vulkanTexture->usageFlags & REFRESH_TEXTUREUSAGE_SAMPLER_BIT)
-	{
-		VULKAN_INTERNAL_ImageMemoryBarrier(
-			renderer,
-			commandBuffer,
-			RESOURCE_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE,
-			VK_IMAGE_ASPECT_COLOR_BIT,
-			0,
-			vulkanTexture->layerCount,
-			0,
-			vulkanTexture->levelCount,
+			textureSlice->layer,
+			1,
+			textureSlice->level,
+			1,
 			0,
 			vulkanTexture->image,
 			&vulkanTexture->resourceAccessType
@@ -6538,12 +6325,14 @@ static void VULKAN_INTERNAL_BlitImage(
 	VulkanRenderer *renderer,
 	VkCommandBuffer commandBuffer,
 	REFRESH_Rect *sourceRectangle,
+	uint32_t sourceDepth,
 	uint32_t sourceLayer,
 	uint32_t sourceLevel,
 	VkImage sourceImage,
 	VulkanResourceAccessType *currentSourceAccessType,
 	VulkanResourceAccessType nextSourceAccessType,
 	REFRESH_Rect *destinationRectangle,
+	uint32_t destinationDepth,
 	uint32_t destinationLayer,
 	uint32_t destinationLevel,
 	VkImage destinationImage,
@@ -6583,7 +6372,7 @@ static void VULKAN_INTERNAL_BlitImage(
 
 	blit.srcOffsets[0].x = sourceRectangle->x;
 	blit.srcOffsets[0].y = sourceRectangle->y;
-	blit.srcOffsets[0].z = 0;
+	blit.srcOffsets[0].z = sourceDepth;
 	blit.srcOffsets[1].x = sourceRectangle->x + sourceRectangle->w;
 	blit.srcOffsets[1].y = sourceRectangle->y + sourceRectangle->h;
 	blit.srcOffsets[1].z = 1;
@@ -6595,7 +6384,7 @@ static void VULKAN_INTERNAL_BlitImage(
 
 	blit.dstOffsets[0].x = destinationRectangle->x;
 	blit.dstOffsets[0].y = destinationRectangle->y;
-	blit.dstOffsets[0].z = 0;
+	blit.dstOffsets[0].z = destinationDepth;
 	blit.dstOffsets[1].x = destinationRectangle->x + destinationRectangle->w;
 	blit.dstOffsets[1].y = destinationRectangle->y + destinationRectangle->h;
 	blit.dstOffsets[1].z = 1;
@@ -6650,8 +6439,6 @@ REFRESHAPI void VULKAN_CopyTextureToTexture(
 	REFRESH_CommandBuffer *commandBuffer,
 	REFRESH_TextureSlice *sourceTextureSlice,
 	REFRESH_TextureSlice *destinationTextureSlice,
-	REFRESH_Rect *sourceRectangle,
-	REFRESH_Rect *destinationRectangle,
 	REFRESH_Filter filter
 ) {
 	VulkanRenderer *renderer = (VulkanRenderer*)driverData;
@@ -6659,43 +6446,18 @@ REFRESHAPI void VULKAN_CopyTextureToTexture(
 	VulkanTexture *sourceTexture = (VulkanTexture*) sourceTextureSlice->texture;
 	VulkanTexture *destinationTexture = (VulkanTexture*) destinationTextureSlice->texture;
 
-	REFRESH_Rect srcRect;
-	REFRESH_Rect dstRect;
-
-	if (sourceRectangle != NULL)
-	{
-		srcRect = *sourceRectangle;
-	}
-	else
-	{
-		srcRect.x = 0;
-		srcRect.y = 0;
-		srcRect.w = sourceTexture->dimensions.width;
-		srcRect.h = sourceTexture->dimensions.height;
-	}
-
-	if (destinationRectangle != NULL)
-	{
-		dstRect = *destinationRectangle;
-	}
-	else
-	{
-		dstRect.x = 0;
-		dstRect.y = 0;
-		dstRect.w = destinationTexture->dimensions.width;
-		dstRect.h = destinationTexture->dimensions.height;
-	}
-
 	VULKAN_INTERNAL_BlitImage(
 		renderer,
 		vulkanCommandBuffer->commandBuffer,
-		&srcRect,
+		&sourceTextureSlice->rectangle,
+		sourceTextureSlice->depth,
 		sourceTextureSlice->layer,
 		sourceTextureSlice->level,
 		sourceTexture->image,
 		&sourceTexture->resourceAccessType,
 		sourceTexture->resourceAccessType,
-		&dstRect,
+		&destinationTextureSlice->rectangle,
+		destinationTextureSlice->depth,
 		destinationTextureSlice->layer,
 		destinationTextureSlice->level,
 		destinationTexture->image,
@@ -7298,21 +7060,15 @@ static void VULKAN_GetBufferData(
 	SDL_UnlockMutex(vulkanBuffer->subBuffers[vulkanBuffer->currentSubBufferIndex]->allocation->memoryLock);
 }
 
-static void VULKAN_INTERNAL_CopyTextureData(
+static void VULKAN_CopyTextureToBuffer(
 	REFRESH_Renderer *driverData,
 	REFRESH_CommandBuffer *commandBuffer,
-	REFRESH_Texture *texture,
-	int32_t x,
-	int32_t y,
-	int32_t w,
-	int32_t h,
-	int32_t level,
-	int32_t layer,
+	REFRESH_TextureSlice *textureSlice,
 	REFRESH_Buffer *buffer
 ) {
 	VulkanRenderer *renderer = (VulkanRenderer*) driverData;
 	VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer;
-	VulkanTexture *vulkanTexture = (VulkanTexture*) texture;
+	VulkanTexture *vulkanTexture = (VulkanTexture*) textureSlice->texture;
 	VulkanBuffer *vulkanBuffer = (VulkanBuffer*) buffer;
 
 	VulkanResourceAccessType prevResourceAccess;
@@ -7326,10 +7082,10 @@ static void VULKAN_INTERNAL_CopyTextureData(
 		vulkanCommandBuffer->commandBuffer,
 		RESOURCE_ACCESS_TRANSFER_READ,
 		VK_IMAGE_ASPECT_COLOR_BIT,
-		0,
-		vulkanTexture->layerCount,
-		0,
-		vulkanTexture->levelCount,
+		textureSlice->layer,
+		1,
+		textureSlice->level,
+		1,
 		0,
 		vulkanTexture->image,
 		&vulkanTexture->resourceAccessType
@@ -7337,18 +7093,18 @@ static void VULKAN_INTERNAL_CopyTextureData(
 
 	/* Save texture data to buffer */
 
-	imageCopy.imageExtent.width = w;
-	imageCopy.imageExtent.height = h;
+	imageCopy.imageExtent.width = textureSlice->rectangle.w;
+	imageCopy.imageExtent.height = textureSlice->rectangle.h;
 	imageCopy.imageExtent.depth = 1;
-	imageCopy.bufferRowLength = w;
-	imageCopy.bufferImageHeight = h;
-	imageCopy.imageOffset.x = x;
-	imageCopy.imageOffset.y = y;
-	imageCopy.imageOffset.z = 0;
+	imageCopy.bufferRowLength = textureSlice->rectangle.w;
+	imageCopy.bufferImageHeight = textureSlice->rectangle.h;
+	imageCopy.imageOffset.x = textureSlice->rectangle.x;
+	imageCopy.imageOffset.y = textureSlice->rectangle.y;
+	imageCopy.imageOffset.z = textureSlice->depth;
 	imageCopy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-	imageCopy.imageSubresource.baseArrayLayer = layer;
+	imageCopy.imageSubresource.baseArrayLayer = textureSlice->layer;
 	imageCopy.imageSubresource.layerCount = 1;
-	imageCopy.imageSubresource.mipLevel = level;
+	imageCopy.imageSubresource.mipLevel = textureSlice->level;
 	imageCopy.bufferOffset = 0;
 
 	renderer->vkCmdCopyImageToBuffer(
@@ -7367,40 +7123,16 @@ static void VULKAN_INTERNAL_CopyTextureData(
 		vulkanCommandBuffer->commandBuffer,
 		prevResourceAccess,
 		VK_IMAGE_ASPECT_COLOR_BIT,
-		0,
-		vulkanTexture->layerCount,
-		0,
-		vulkanTexture->levelCount,
+		textureSlice->layer,
+		1,
+		textureSlice->level,
+		1,
 		0,
 		vulkanTexture->image,
 		&vulkanTexture->resourceAccessType
 	);
 }
 
-static void VULKAN_CopyTextureToBuffer(
-	REFRESH_Renderer *driverData,
-	REFRESH_CommandBuffer *commandBuffer,
-	REFRESH_TextureSlice *textureSlice,
-	uint32_t x,
-	uint32_t y,
-	uint32_t w,
-	uint32_t h,
-	REFRESH_Buffer *buffer
-) {
-    VULKAN_INTERNAL_CopyTextureData(
-		driverData,
-		commandBuffer,
-		textureSlice->texture,
-		x,
-		y,
-		w,
-		h,
-		textureSlice->level,
-		textureSlice->layer,
-		buffer
-	);
-}
-
 static void VULKAN_AddDisposeTexture(
 	REFRESH_Renderer *driverData,
 	REFRESH_Texture *texture
@@ -8162,14 +7894,12 @@ static void VULKAN_QueuePresent(
 	REFRESH_Renderer *driverData,
 	REFRESH_CommandBuffer *commandBuffer,
 	REFRESH_TextureSlice *textureSlice,
-	REFRESH_Rect *sourceRectangle,
 	REFRESH_Rect *destinationRectangle,
 	REFRESH_Filter filter
 ) {
 	VkResult acquireResult;
 	uint32_t swapChainImageIndex;
 
-	REFRESH_Rect srcRect;
 	REFRESH_Rect dstRect;
 
 	VulkanRenderer* renderer = (VulkanRenderer*) driverData;
@@ -8202,18 +7932,6 @@ static void VULKAN_QueuePresent(
 	renderer->swapChainImageAcquired = 1;
 	renderer->currentSwapChainIndex = swapChainImageIndex;
 
-	if (sourceRectangle != NULL)
-	{
-		srcRect = *sourceRectangle;
-	}
-	else
-	{
-		srcRect.x = 0;
-		srcRect.y = 0;
-		srcRect.w = vulkanTexture->dimensions.width;
-		srcRect.h = vulkanTexture->dimensions.height;
-	}
-
 	if (destinationRectangle != NULL)
 	{
 		dstRect = *destinationRectangle;
@@ -8231,7 +7949,8 @@ static void VULKAN_QueuePresent(
 	VULKAN_INTERNAL_BlitImage(
 		renderer,
 		vulkanCommandBuffer->commandBuffer,
-		&srcRect,
+		&textureSlice->rectangle,
+		textureSlice->depth,
 		textureSlice->layer,
 		textureSlice->level,
 		vulkanTexture->image,
@@ -8240,6 +7959,7 @@ static void VULKAN_QueuePresent(
 		&dstRect,
 		0,
 		0,
+		0,
 		renderer->swapChainImages[swapChainImageIndex],
 		&renderer->swapChainResourceAccessTypes[swapChainImageIndex],
 		RESOURCE_ACCESS_PRESENT,
@@ -8447,7 +8167,7 @@ static void VULKAN_Submit(
 	uint32_t i;
 	uint8_t present;
 
-	VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+	VkPipelineStageFlags waitStages[2];
 	VkSemaphore waitSemaphores[2];
 	uint32_t waitSemaphoreCount = 0;
 	VkPresentInfoKHR presentInfo;
@@ -8467,6 +8187,7 @@ static void VULKAN_Submit(
 		transferSubmitInfo.signalSemaphoreCount = 1;
 
 		waitSemaphores[waitSemaphoreCount] = renderer->transferFinishedSemaphore;
+		waitStages[waitSemaphoreCount] = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
 		waitSemaphoreCount += 1;
 	}
 
@@ -8489,9 +8210,10 @@ static void VULKAN_Submit(
 	if (present)
 	{
 		waitSemaphores[waitSemaphoreCount] = renderer->imageAvailableSemaphore;
+		waitStages[waitSemaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
 		waitSemaphoreCount += 1;
 
-		submitInfo.pWaitDstStageMask = &waitStage;
+		submitInfo.pWaitDstStageMask = waitStages;
 		submitInfo.signalSemaphoreCount = 1;
 		submitInfo.pSignalSemaphores = &renderer->renderFinishedSemaphore;
 	}