diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index d0b83ba5..708d5262 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -286,15 +286,8 @@ namespace dxvk { const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(dstTextureInfo->image->info().format); const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcTextureInfo->image->info().format); - const VkImageSubresource dstSubresource = - GetSubresourceFromIndex( - dstFormatInfo->aspectMask & srcFormatInfo->aspectMask, - dstTextureInfo->image->info().mipLevels, DstSubresource); - - const VkImageSubresource srcSubresource = - GetSubresourceFromIndex( - dstFormatInfo->aspectMask & srcFormatInfo->aspectMask, - srcTextureInfo->image->info().mipLevels, SrcSubresource); + const VkImageSubresource dstSubresource = GetSubresourceFromIndex(dstFormatInfo->aspectMask, dstTextureInfo->image->info().mipLevels, DstSubresource); + const VkImageSubresource srcSubresource = GetSubresourceFromIndex(srcFormatInfo->aspectMask, srcTextureInfo->image->info().mipLevels, SrcSubresource); VkOffset3D srcOffset = { 0, 0, 0 }; VkOffset3D dstOffset = { @@ -391,13 +384,8 @@ namespace dxvk { for (uint32_t i = 0; i < srcTextureInfo->image->info().mipLevels; i++) { VkExtent3D extent = srcTextureInfo->image->mipLevelExtent(i); - const VkImageSubresourceLayers dstLayers = { - dstFormatInfo->aspectMask & srcFormatInfo->aspectMask, - i, 0, dstTextureInfo->image->info().numLayers }; - - const VkImageSubresourceLayers srcLayers = { - dstFormatInfo->aspectMask & srcFormatInfo->aspectMask, - i, 0, srcTextureInfo->image->info().numLayers }; + const VkImageSubresourceLayers dstLayers = { dstFormatInfo->aspectMask, i, 0, dstTextureInfo->image->info().numLayers }; + const VkImageSubresourceLayers srcLayers = { srcFormatInfo->aspectMask, i, 0, srcTextureInfo->image->info().numLayers }; EmitCs([ cDstImage = dstTextureInfo->image, diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 4056f6e9..3764ed5d 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -432,13 +432,11 @@ namespace dxvk { dstImage->info().layout, dstImage->info().stages, dstImage->info().access); - m_barriers.accessBuffer(srcSlice, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, srcBuffer->info().stages, srcBuffer->info().access); - m_barriers.recordCommands(m_cmd); m_cmd->trackResource(dstImage); @@ -478,7 +476,6 @@ namespace dxvk { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); - m_barriers.accessImage( srcImage, srcSubresourceRange, srcImage->info().layout, @@ -487,21 +484,75 @@ namespace dxvk { VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT); - m_barriers.recordCommands(m_cmd); - - VkImageCopy imageRegion; - imageRegion.srcSubresource = srcSubresource; - imageRegion.srcOffset = srcOffset; - imageRegion.dstSubresource = dstSubresource; - imageRegion.dstOffset = dstOffset; - imageRegion.extent = extent; - - m_cmd->cmdCopyImage( - srcImage->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstImage->handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &imageRegion); - + + if (dstSubresource.aspectMask == srcSubresource.aspectMask) { + VkImageCopy imageRegion; + imageRegion.srcSubresource = srcSubresource; + imageRegion.srcOffset = srcOffset; + imageRegion.dstSubresource = dstSubresource; + imageRegion.dstOffset = dstOffset; + imageRegion.extent = extent; + + m_cmd->cmdCopyImage( + srcImage->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage->handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &imageRegion); + } else { + const VkDeviceSize transferBufferSize = std::max( + util::computeImageDataSize(dstImage->info().format, extent), + util::computeImageDataSize(srcImage->info().format, extent)); + + // TODO optimize away buffer creation + DxvkBufferCreateInfo tmpBufferInfo; + tmpBufferInfo.size = transferBufferSize; + tmpBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + tmpBufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT; + tmpBufferInfo.access = VK_ACCESS_TRANSFER_READ_BIT + | VK_ACCESS_TRANSFER_WRITE_BIT; + + Rc tmpBuffer = m_device->createBuffer( + tmpBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + DxvkPhysicalBufferSlice tmpSlice = tmpBuffer->slice(); + + VkBufferImageCopy bufferImageCopy; + bufferImageCopy.bufferOffset = tmpSlice.offset(); + bufferImageCopy.bufferRowLength = 0; + bufferImageCopy.bufferImageHeight = 0; + bufferImageCopy.imageSubresource = srcSubresource; + bufferImageCopy.imageOffset = srcOffset; + bufferImageCopy.imageExtent = extent; + + m_cmd->cmdCopyImageToBuffer( + srcImage->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + tmpSlice.handle(), 1, &bufferImageCopy); + + m_barriers.accessBuffer(tmpSlice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT); + m_barriers.recordCommands(m_cmd); + + bufferImageCopy.imageSubresource = dstSubresource; + bufferImageCopy.imageOffset = dstOffset; + + m_cmd->cmdCopyBufferToImage( + tmpSlice.handle(), dstImage->handle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &bufferImageCopy); + + m_barriers.accessBuffer(tmpSlice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + tmpBuffer->info().stages, + tmpBuffer->info().access); + + m_cmd->trackResource(tmpSlice.resource()); + } + m_barriers.accessImage( dstImage, dstSubresourceRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -510,7 +561,6 @@ namespace dxvk { dstImage->info().layout, dstImage->info().stages, dstImage->info().access); - m_barriers.accessImage( srcImage, srcSubresourceRange, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -519,7 +569,6 @@ namespace dxvk { srcImage->info().layout, srcImage->info().stages, srcImage->info().access); - m_barriers.recordCommands(m_cmd); m_cmd->trackResource(dstImage); @@ -577,13 +626,11 @@ namespace dxvk { srcImage->info().layout, srcImage->info().stages, srcImage->info().access); - m_barriers.accessBuffer(dstSlice, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, dstBuffer->info().stages, dstBuffer->info().access); - m_barriers.recordCommands(m_cmd); m_cmd->trackResource(srcImage); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 41f91624..f39d9d65 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -634,6 +634,8 @@ namespace dxvk { void eraseActiveQuery( const DxvkQueryRevision& query); + Rc getTransferBuffer(VkDeviceSize size); + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_util.cpp b/src/dxvk/dxvk_util.cpp index d3ffe726..a18d8fa8 100644 --- a/src/dxvk/dxvk_util.cpp +++ b/src/dxvk/dxvk_util.cpp @@ -1,5 +1,6 @@ #include +#include "dxvk_format.h" #include "dxvk_util.h" namespace dxvk::util { @@ -68,4 +69,10 @@ namespace dxvk::util { } } + + VkDeviceSize computeImageDataSize(VkFormat format, VkExtent3D extent) { + const DxvkFormatInfo* formatInfo = imageFormatInfo(format); + return formatInfo->elementSize * flattenImageExtent(computeBlockCount(extent, formatInfo->blockSize)); + } + } diff --git a/src/dxvk/dxvk_util.h b/src/dxvk/dxvk_util.h index 41185450..9eac8d49 100644 --- a/src/dxvk/dxvk_util.h +++ b/src/dxvk/dxvk_util.h @@ -66,6 +66,17 @@ namespace dxvk::util { return extent.width * extent.height * extent.depth; } + /** + * \brief Computes image data size, in bytes + * + * Convenience method that can be used to compute the number + * of bytes required to store image data in a given format. + * \param [in] format The image format + * \param [in] extent Image size, in pixels + * \returns Data size, in bytes + */ + VkDeviceSize computeImageDataSize(VkFormat format, VkExtent3D extent); + }