From f67c8dd1da7f99cae022809bc9f5205f27bd6722 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 5 Oct 2024 20:22:52 +0200 Subject: [PATCH] [dxvk] Support format conversion in copyBufferToImage --- src/d3d11/d3d11_context.cpp | 39 +++------- src/d3d11/d3d11_context_imm.cpp | 18 +---- src/d3d9/d3d9_device.cpp | 21 ++--- src/dxvk/dxvk_context.cpp | 134 +++++++++++++++++++------------- src/dxvk/dxvk_context.h | 15 +++- 5 files changed, 113 insertions(+), 114 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 9e42b96f4..15a0c9f84 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -3990,25 +3990,16 @@ namespace dxvk { cDstLayers = dstLayer, cDstOffset = DstOffset, cDstExtent = dstExtent, + cDstFormat = pDstTexture->GetPackedFormat(), cSrcBuffer = pSrcTexture->GetMappedBuffer(srcSubresource), cSrcLayout = pSrcTexture->GetSubresourceLayout(srcAspectMask, srcSubresource), cSrcOffset = pSrcTexture->ComputeMappedOffset(srcSubresource, j, SrcOffset), cSrcCoord = SrcOffset, - cSrcExtent = srcMipExtent, - cSrcFormat = pSrcTexture->GetPackedFormat() + cSrcExtent = srcMipExtent ] (DxvkContext* ctx) { - if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->copyBufferToImage(cDstImage, cDstLayers, cDstOffset, cDstExtent, - cSrcBuffer, cSrcOffset, cSrcLayout.RowPitch, cSrcLayout.DepthPitch); - } else { - ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers, - VkOffset2D { cDstOffset.x, cDstOffset.y }, - VkExtent2D { cDstExtent.width, cDstExtent.height }, - cSrcBuffer, cSrcLayout.Offset, - VkOffset2D { cSrcCoord.x, cSrcCoord.y }, - VkExtent2D { cSrcExtent.width, cSrcExtent.height }, - cSrcFormat); - } + ctx->copyBufferToImage(cDstImage, cDstLayers, cDstOffset, cDstExtent, + cSrcBuffer, cSrcOffset, cSrcLayout.RowPitch, cSrcLayout.DepthPitch, + cDstFormat); }); } else if (srcIsImage) { VkImageSubresourceLayers srcLayer = { srcAspectMask, @@ -5194,21 +5185,11 @@ namespace dxvk { cStagingSlice = std::move(StagingBuffer), cPackedFormat = pDstTexture->GetPackedFormat() ] (DxvkContext* ctx) { - if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->copyBufferToImage(cDstImage, - cDstLayers, cDstOffset, cDstExtent, - cStagingSlice.buffer(), - cStagingSlice.offset(), 0, 0); - } else { - ctx->copyPackedBufferToDepthStencilImage(cDstImage, cDstLayers, - VkOffset2D { cDstOffset.x, cDstOffset.y }, - VkExtent2D { cDstExtent.width, cDstExtent.height }, - cStagingSlice.buffer(), - cStagingSlice.offset(), - VkOffset2D { 0, 0 }, - VkExtent2D { cDstExtent.width, cDstExtent.height }, - cPackedFormat); - } + ctx->copyBufferToImage(cDstImage, + cDstLayers, cDstOffset, cDstExtent, + cStagingSlice.buffer(), + cStagingSlice.offset(), 0, 0, + cPackedFormat); }); } else { // If the destination image is backed only by a buffer, we need to use diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 0d3a0156b..f5e83aa96 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -675,20 +675,10 @@ namespace dxvk { cSrcDepthPitch = subresourceLayout.DepthPitch, cPackedFormat = pResource->GetPackedFormat() ] (DxvkContext* ctx) { - if (cDstSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->copyBufferToImage( - cDstImage, cDstSubresource, cDstOffset, cDstExtent, - cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch); - } else { - ctx->copyPackedBufferToDepthStencilImage( - cDstImage, cDstSubresource, - VkOffset2D { cDstOffset.x, cDstOffset.y }, - VkExtent2D { cDstExtent.width, cDstExtent.height }, - cSrcBuffer, 0, - VkOffset2D { cDstOffset.x, cDstOffset.y }, - VkExtent2D { cDstExtent.width, cDstExtent.height }, - cPackedFormat); - } + ctx->copyBufferToImage( + cDstImage, cDstSubresource, cDstOffset, cDstExtent, + cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch, + cPackedFormat); }); } diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index cab434332..93780d16b 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -5082,22 +5082,11 @@ namespace dxvk { cOffset = alignedDestOffset, cPackedDSFormat = packedDSFormat ] (DxvkContext* ctx) { - if (cDstLayers.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->copyBufferToImage( - cDstImage, cDstLayers, - cOffset, cDstLevelExtent, - cSrcSlice.buffer(), cSrcSlice.offset(), - 1, 1); - } else { - ctx->copyPackedBufferToDepthStencilImage( - cDstImage, cDstLayers, - VkOffset2D { cOffset.x, cOffset.y }, - VkExtent2D { cDstLevelExtent.width, cDstLevelExtent.height }, - cSrcSlice.buffer(), cSrcSlice.offset(), - VkOffset2D { 0, 0 }, - VkExtent2D { cDstLevelExtent.width, cDstLevelExtent.height }, - cPackedDSFormat); - } + ctx->copyBufferToImage( + cDstImage, cDstLayers, + cOffset, cDstLevelExtent, + cSrcSlice.buffer(), cSrcSlice.offset(), + 0, 0, cPackedDSFormat); }); TrackTextureMappingBufferSequenceNumber(pSrcTexture, SrcSubresource); diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 3fd213b2e..ebde2feb4 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -500,62 +500,19 @@ namespace dxvk { const Rc& srcBuffer, VkDeviceSize srcOffset, VkDeviceSize rowAlignment, - VkDeviceSize sliceAlignment) { - this->spillRenderPass(true); - this->prepareImage(dstImage, vk::makeSubresourceRange(dstSubresource)); + VkDeviceSize sliceAlignment, + VkFormat srcFormat) { + bool useFb = (srcFormat && srcFormat != dstImage->info().format) || + (dstImage->formatInfo()->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); - auto srcSlice = srcBuffer->getSliceHandle(srcOffset, 0); - - // We may copy to only one aspect at a time, but pipeline - // barriers need to have all available aspect bits set - auto dstFormatInfo = dstImage->formatInfo(); - - auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresource); - dstSubresourceRange.aspectMask = dstFormatInfo->aspectMask; - - if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write) - || m_execBarriers.isBufferDirty(srcSlice, DxvkAccess::Read)) - m_execBarriers.recordCommands(m_cmd); - - // Initialize the image if the entire subresource is covered - VkImageLayout dstImageLayoutInitial = dstImage->info().layout; - VkImageLayout dstImageLayoutTransfer = dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - if (dstImage->isFullSubresource(dstSubresource, dstExtent)) - dstImageLayoutInitial = VK_IMAGE_LAYOUT_UNDEFINED; - - if (dstImageLayoutTransfer != dstImageLayoutInitial) { - m_execAcquires.accessImage( - dstImage, dstSubresourceRange, - dstImageLayoutInitial, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - dstImageLayoutTransfer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT); + if (useFb) { + copyBufferToImageFb(dstImage, dstSubresource, dstOffset, dstExtent, + srcBuffer, srcOffset, rowAlignment, sliceAlignment, + srcFormat ? srcFormat : dstImage->info().format); + } else { + copyBufferToImageHw(dstImage, dstSubresource, dstOffset, dstExtent, + srcBuffer, srcOffset, rowAlignment, sliceAlignment); } - - m_execAcquires.recordCommands(m_cmd); - - this->copyImageBufferData(DxvkCmdBuffer::ExecBuffer, dstImage, dstSubresource, - dstOffset, dstExtent, dstImageLayoutTransfer, srcSlice, rowAlignment, sliceAlignment); - - m_execBarriers.accessImage( - dstImage, dstSubresourceRange, - dstImageLayoutTransfer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - dstImage->info().layout, - dstImage->info().stages, - dstImage->info().access); - - m_execBarriers.accessBuffer(srcSlice, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - srcBuffer->info().stages, - srcBuffer->info().access); - - m_cmd->trackResource(dstImage); - m_cmd->trackResource(srcBuffer); } @@ -3366,6 +3323,75 @@ namespace dxvk { } + void DxvkContext::copyBufferToImageHw( + const Rc& image, + const VkImageSubresourceLayers& imageSubresource, + VkOffset3D imageOffset, + VkExtent3D imageExtent, + const Rc& buffer, + VkDeviceSize bufferOffset, + VkDeviceSize bufferRowAlignment, + VkDeviceSize bufferSliceAlignment) { + this->spillRenderPass(true); + this->prepareImage(image, vk::makeSubresourceRange(imageSubresource)); + + VkDeviceSize dataSize = imageSubresource.layerCount * util::computeImageDataSize( + image->info().format, imageExtent, imageSubresource.aspectMask); + + auto bufferSlice = buffer->getSliceHandle(bufferOffset, dataSize); + + // We may copy to only one aspect at a time, but pipeline + // barriers need to have all available aspect bits set + auto dstFormatInfo = image->formatInfo(); + + auto dstSubresourceRange = vk::makeSubresourceRange(imageSubresource); + dstSubresourceRange.aspectMask = dstFormatInfo->aspectMask; + + if (m_execBarriers.isImageDirty(image, dstSubresourceRange, DxvkAccess::Write) + || m_execBarriers.isBufferDirty(bufferSlice, DxvkAccess::Read)) + m_execBarriers.recordCommands(m_cmd); + + // Initialize the image if the entire subresource is covered + VkImageLayout dstImageLayoutInitial = image->info().layout; + VkImageLayout dstImageLayoutTransfer = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + if (image->isFullSubresource(imageSubresource, imageExtent)) + dstImageLayoutInitial = VK_IMAGE_LAYOUT_UNDEFINED; + + m_execAcquires.accessImage( + image, dstSubresourceRange, + dstImageLayoutInitial, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + dstImageLayoutTransfer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT); + + m_execAcquires.recordCommands(m_cmd); + + this->copyImageBufferData(DxvkCmdBuffer::ExecBuffer, + image, imageSubresource, imageOffset, imageExtent, dstImageLayoutTransfer, + bufferSlice, bufferRowAlignment, bufferSliceAlignment); + + m_execBarriers.accessImage( + image, dstSubresourceRange, + dstImageLayoutTransfer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + image->info().layout, + image->info().stages, + image->info().access); + + m_execBarriers.accessBuffer(bufferSlice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + buffer->info().stages, + buffer->info().access); + + m_cmd->trackResource(image); + m_cmd->trackResource(buffer); + } + + void DxvkContext::copyBufferToImageFb( const Rc& image, const VkImageSubresourceLayers& imageSubresource, diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 7096b05d0..feaa00892 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -547,6 +547,8 @@ namespace dxvk { * \param [in] srcOffset Source offset, in bytes * \param [in] rowAlignment Row alignment, in bytes * \param [in] sliceAlignment Slice alignment, in bytes + * \param [in] srcFormat Buffer data format. May be + * \c VK_FORMAT_UNKNOWN to use the image format. */ void copyBufferToImage( const Rc& dstImage, @@ -556,7 +558,8 @@ namespace dxvk { const Rc& srcBuffer, VkDeviceSize srcOffset, VkDeviceSize rowAlignment, - VkDeviceSize sliceAlignment); + VkDeviceSize sliceAlignment, + VkFormat srcFormat); /** * \brief Copies data from one image to another @@ -1508,6 +1511,16 @@ namespace dxvk { VkDeviceSize bufferRowAlignment, VkDeviceSize bufferSliceAlignment); + void copyBufferToImageHw( + const Rc& image, + const VkImageSubresourceLayers& imageSubresource, + VkOffset3D imageOffset, + VkExtent3D imageExtent, + const Rc& buffer, + VkDeviceSize bufferOffset, + VkDeviceSize bufferRowAlignment, + VkDeviceSize bufferSliceAlignment); + void copyBufferToImageFb( const Rc& image, const VkImageSubresourceLayers& imageSubresource,