1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-01 16:24:12 +01:00

[dxvk] Support multi-plane formats in copyBufferToImage

This commit is contained in:
Philip Rebohle 2021-05-18 20:24:32 +02:00
parent cd2ea98670
commit 86542248df
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
4 changed files with 111 additions and 25 deletions

View File

@ -516,7 +516,7 @@ namespace dxvk {
if (cPackedFormat == VK_FORMAT_UNDEFINED) {
ctx->copyBufferToImage(cDstImage, cDstLayers,
VkOffset3D { 0, 0, 0 }, cDstLevelExtent,
cSrcBuffer, 0, { 0u, 0u });
cSrcBuffer, 0, 0);
} else {
ctx->copyPackedBufferToDepthStencilImage(
cDstImage, cDstLayers,

View File

@ -707,8 +707,7 @@ namespace dxvk {
] (DxvkContext* ctx) {
ctx->copyBufferToImage(
cDstImage, cDstLayers, cDstOffset, cCopyExtent,
cSrcSlice.buffer(), cSrcSlice.offset(),
VkExtent2D { 0, 0 });
cSrcSlice.buffer(), cSrcSlice.offset(), 0);
});
dstTextureInfo->SetWrittenByGPU(dst->GetSubresource(), true);
@ -801,8 +800,7 @@ namespace dxvk {
ctx->copyBufferToImage(
cDstImage, cDstLayers,
cOffset, cExtent,
cSrcSlice.buffer(), cSrcSlice.offset(),
VkExtent2D { 0, 0 });
cSrcSlice.buffer(), cSrcSlice.offset(), 0);
});
dstTexInfo->SetWrittenByGPU(dstTexInfo->CalcSubresource(a, m), true);
@ -4359,8 +4357,7 @@ namespace dxvk {
ctx->copyBufferToImage(
cDstImage, cDstLayers,
cOffset, cDstLevelExtent,
cSrcSlice.buffer(), cSrcSlice.offset(),
VkExtent2D { 0, 0 });
cSrcSlice.buffer(), cSrcSlice.offset(), 0);
});
}
else {

View File

@ -704,14 +704,14 @@ namespace dxvk {
VkExtent3D dstExtent,
const Rc<DxvkBuffer>& srcBuffer,
VkDeviceSize srcOffset,
VkExtent2D srcExtent) {
VkDeviceSize rowAlignment) {
this->spillRenderPass(true);
this->prepareImage(m_execBarriers, dstImage, vk::makeSubresourceRange(dstSubresource));
auto srcSlice = srcBuffer->getSliceHandle(srcOffset, 0);
// We may copy to only one aspect of a depth-stencil image,
// but pipeline barriers need to have all aspect bits set
// 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);
@ -739,19 +739,10 @@ namespace dxvk {
}
m_execAcquires.recordCommands(m_cmd);
VkBufferImageCopy copyRegion;
copyRegion.bufferOffset = srcSlice.offset;
copyRegion.bufferRowLength = srcExtent.width;
copyRegion.bufferImageHeight = srcExtent.height;
copyRegion.imageSubresource = dstSubresource;
copyRegion.imageOffset = dstOffset;
copyRegion.imageExtent = dstExtent;
m_cmd->cmdCopyBufferToImage(DxvkCmdBuffer::ExecBuffer,
srcSlice.handle, dstImage->handle(),
dstImageLayoutTransfer, 1, &copyRegion);
this->copyImageBufferData<true>(DxvkCmdBuffer::ExecBuffer, dstImage, dstSubresource,
dstOffset, dstExtent, dstImageLayoutTransfer, srcSlice, rowAlignment, 0);
m_execBarriers.accessImage(
dstImage, dstSubresourceRange,
dstImageLayoutTransfer,
@ -2754,6 +2745,91 @@ namespace dxvk {
}
template<bool ToImage>
void DxvkContext::copyImageBufferData(
DxvkCmdBuffer cmd,
const Rc<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
VkImageLayout imageLayout,
const DxvkBufferSliceHandle& bufferSlice,
VkDeviceSize bufferRowAlignment,
VkDeviceSize bufferSliceAlignment) {
auto formatInfo = image->formatInfo();
auto layers = imageSubresource.layerCount;
VkDeviceSize bufferOffset = bufferSlice.offset;
// Do one copy region per layer in case the buffer memory layout is weird
if (bufferSliceAlignment || formatInfo->flags.test(DxvkFormatFlag::MultiPlane))
layers = 1;
for (uint32_t i = 0; i < imageSubresource.layerCount; i += layers) {
auto aspectOffset = bufferOffset;
for (auto aspects = imageSubresource.aspectMask; aspects; ) {
auto aspect = vk::getNextAspect(aspects);
auto elementSize = formatInfo->elementSize;
VkBufferImageCopy copyRegion = { };
copyRegion.imageSubresource.aspectMask = aspect;
copyRegion.imageSubresource.baseArrayLayer = imageSubresource.baseArrayLayer + i;
copyRegion.imageSubresource.layerCount = layers;
copyRegion.imageSubresource.mipLevel = imageSubresource.mipLevel;
copyRegion.imageOffset = imageOffset;
copyRegion.imageExtent = imageExtent;
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane)) {
auto plane = &formatInfo->planes[vk::getPlaneIndex(aspect)];
copyRegion.imageOffset.x /= plane->blockSize.width;
copyRegion.imageOffset.y /= plane->blockSize.height;
copyRegion.imageExtent.width /= plane->blockSize.width;
copyRegion.imageExtent.height /= plane->blockSize.height;
elementSize = plane->elementSize;
}
// Vulkan can't really express row pitch in the same way that client APIs
// may expect, so we'll need to do some heroics here and hope that it works
VkExtent3D blockCount = util::computeBlockCount(copyRegion.imageExtent, formatInfo->blockSize);
VkDeviceSize rowPitch = blockCount.width * elementSize;
if (bufferRowAlignment > elementSize)
rowPitch = bufferRowAlignment > rowPitch ? bufferRowAlignment : align(rowPitch, bufferRowAlignment);
VkDeviceSize slicePitch = blockCount.height * rowPitch;
if (image->info().type == VK_IMAGE_TYPE_3D && bufferSliceAlignment > elementSize)
slicePitch = bufferSliceAlignment > slicePitch ? bufferSliceAlignment : align(slicePitch, bufferSliceAlignment);
copyRegion.bufferOffset = aspectOffset;
copyRegion.bufferRowLength = formatInfo->blockSize.width * rowPitch / elementSize;
copyRegion.bufferImageHeight = formatInfo->blockSize.height * slicePitch / rowPitch;
// Perform the actual copy
if constexpr (ToImage) {
m_cmd->cmdCopyBufferToImage(cmd, bufferSlice.handle,
image->handle(), imageLayout, 1, &copyRegion);
} else {
m_cmd->cmdCopyImageToBuffer(cmd, image->handle(), imageLayout,
bufferSlice.handle, 1, &copyRegion);
}
aspectOffset += blockCount.depth * slicePitch;
}
// Advance to next layer. This is non-trivial for multi-plane formats
// since plane data for each layer is expected to be packed.
VkDeviceSize layerPitch = aspectOffset - bufferOffset;
if (bufferSliceAlignment)
layerPitch = bufferSliceAlignment > layerPitch ? bufferSliceAlignment : align(layerPitch, bufferSliceAlignment);
bufferOffset += layerPitch;
}
}
void DxvkContext::clearImageViewFb(
const Rc<DxvkImageView>& imageView,
VkOffset3D offset,

View File

@ -341,13 +341,14 @@ namespace dxvk {
/**
* \brief Copies data from a buffer to an image
*
* Source data must be packed, except for the row alignment.
* \param [in] dstImage Destination image
* \param [in] dstSubresource Destination subresource
* \param [in] dstOffset Destination area offset
* \param [in] dstExtent Destination area size
* \param [in] srcBuffer Source buffer
* \param [in] srcOffset Source offset, in bytes
* \param [in] srcExtent Source data extent
* \param [in] rowAlignment Row alignment, in bytes
*/
void copyBufferToImage(
const Rc<DxvkImage>& dstImage,
@ -356,7 +357,7 @@ namespace dxvk {
VkExtent3D dstExtent,
const Rc<DxvkBuffer>& srcBuffer,
VkDeviceSize srcOffset,
VkExtent2D srcExtent);
VkDeviceSize rowAlignment);
/**
* \brief Copies data from one image to another
@ -1061,6 +1062,18 @@ namespace dxvk {
const VkImageBlit& region,
VkFilter filter);
template<bool ToImage>
void copyImageBufferData(
DxvkCmdBuffer cmd,
const Rc<DxvkImage>& image,
const VkImageSubresourceLayers& imageSubresource,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
VkImageLayout imageLayout,
const DxvkBufferSliceHandle& bufferSlice,
VkDeviceSize bufferRowAlignment,
VkDeviceSize bufferSliceAlignment);
void clearImageViewFb(
const Rc<DxvkImageView>& imageView,
VkOffset3D offset,