1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 14:52:10 +01:00

[dxvk] Support format conversion in copyBufferToImage

This commit is contained in:
Philip Rebohle 2024-10-05 20:22:52 +02:00 committed by Philip Rebohle
parent 501b0991da
commit f67c8dd1da
5 changed files with 113 additions and 114 deletions

View File

@ -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

View File

@ -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);
});
}

View File

@ -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);

View File

@ -500,62 +500,19 @@ namespace dxvk {
const Rc<DxvkBuffer>& 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<true>(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<DxvkAccess::Write>(dstImage);
m_cmd->trackResource<DxvkAccess::Read>(srcBuffer);
}
@ -3366,6 +3323,75 @@ namespace dxvk {
}
void DxvkContext::copyBufferToImageHw(
const Rc<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
const Rc<DxvkBuffer>& 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<true>(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<DxvkAccess::Write>(image);
m_cmd->trackResource<DxvkAccess::Read>(buffer);
}
void DxvkContext::copyBufferToImageFb(
const Rc<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,

View File

@ -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<DxvkImage>& dstImage,
@ -556,7 +558,8 @@ namespace dxvk {
const Rc<DxvkBuffer>& 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<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
const Rc<DxvkBuffer>& buffer,
VkDeviceSize bufferOffset,
VkDeviceSize bufferRowAlignment,
VkDeviceSize bufferSliceAlignment);
void copyBufferToImageFb(
const Rc<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,