mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-21 22:54:16 +01:00
[dxvk] Implement depth-stencil unpacking
This commit is contained in:
parent
de45ffd749
commit
0d889e0dcd
@ -1072,6 +1072,182 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkContext::copyPackedBufferToDepthStencilImage(
|
||||||
|
const Rc<DxvkImage>& dstImage,
|
||||||
|
VkImageSubresourceLayers dstSubresource,
|
||||||
|
VkOffset2D dstOffset,
|
||||||
|
VkExtent2D dstExtent,
|
||||||
|
const Rc<DxvkBuffer>& srcBuffer,
|
||||||
|
VkDeviceSize srcOffset,
|
||||||
|
VkFormat format) {
|
||||||
|
this->spillRenderPass();
|
||||||
|
this->unbindComputePipeline();
|
||||||
|
|
||||||
|
if (m_barriers.isBufferDirty(srcBuffer->getSliceHandle(), DxvkAccess::Read))
|
||||||
|
m_barriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
|
// Retrieve compute pipeline for the given format
|
||||||
|
auto pipeInfo = m_metaPack->getUnpackPipeline(
|
||||||
|
dstImage->info().format, format);
|
||||||
|
|
||||||
|
if (!pipeInfo.pipeHandle) {
|
||||||
|
Logger::err(str::format(
|
||||||
|
"DxvkContext: copyPackedBufferToDepthStencilImage: Unhandled formats"
|
||||||
|
"\n dstFormat = ", dstImage->info().format,
|
||||||
|
"\n srcFormat = ", format));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick depth and stencil data formats
|
||||||
|
VkFormat dataFormatD = VK_FORMAT_UNDEFINED;
|
||||||
|
VkFormat dataFormatS = VK_FORMAT_UNDEFINED;
|
||||||
|
|
||||||
|
const std::array<std::tuple<VkFormat, VkFormat, VkFormat>, 2> formats = {{
|
||||||
|
{ VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_UINT },
|
||||||
|
{ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R8_UINT },
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (const auto& e : formats) {
|
||||||
|
if (std::get<0>(e) == dstImage->info().format) {
|
||||||
|
dataFormatD = std::get<1>(e);
|
||||||
|
dataFormatS = std::get<2>(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temporary buffer for depth/stencil data
|
||||||
|
VkDeviceSize pixelCount = dstExtent.width * dstExtent.height * dstSubresource.layerCount;
|
||||||
|
VkDeviceSize dataSizeD = align(pixelCount * imageFormatInfo(dataFormatD)->elementSize, 256);
|
||||||
|
VkDeviceSize dataSizeS = align(pixelCount * imageFormatInfo(dataFormatS)->elementSize, 256);
|
||||||
|
|
||||||
|
DxvkBufferCreateInfo tmpBufferInfo;
|
||||||
|
tmpBufferInfo.size = dataSizeD + dataSizeS;
|
||||||
|
tmpBufferInfo.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
|
||||||
|
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
tmpBufferInfo.stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
|
||||||
|
| VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
tmpBufferInfo.access = VK_ACCESS_SHADER_WRITE_BIT
|
||||||
|
| VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
|
||||||
|
auto tmpBuffer = m_device->createBuffer(tmpBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
|
// Create formatted buffer views
|
||||||
|
DxvkBufferViewCreateInfo tmpViewInfoD;
|
||||||
|
tmpViewInfoD.format = dataFormatD;
|
||||||
|
tmpViewInfoD.rangeOffset = 0;
|
||||||
|
tmpViewInfoD.rangeLength = dataSizeD;
|
||||||
|
|
||||||
|
DxvkBufferViewCreateInfo tmpViewInfoS;
|
||||||
|
tmpViewInfoS.format = dataFormatS;
|
||||||
|
tmpViewInfoS.rangeOffset = dataSizeD;
|
||||||
|
tmpViewInfoS.rangeLength = dataSizeS;
|
||||||
|
|
||||||
|
auto tmpBufferViewD = m_device->createBufferView(tmpBuffer, tmpViewInfoD);
|
||||||
|
auto tmpBufferViewS = m_device->createBufferView(tmpBuffer, tmpViewInfoS);
|
||||||
|
|
||||||
|
// Create descriptor set for the unpack operation
|
||||||
|
DxvkMetaUnpackDescriptors descriptors;
|
||||||
|
descriptors.dstDepth = tmpBufferViewD->handle();
|
||||||
|
descriptors.dstStencil = tmpBufferViewS->handle();
|
||||||
|
descriptors.srcBuffer = srcBuffer->getDescriptor(srcOffset, VK_WHOLE_SIZE).buffer;
|
||||||
|
|
||||||
|
VkDescriptorSet dset = allocateDescriptorSet(pipeInfo.dsetLayout);
|
||||||
|
m_cmd->updateDescriptorSetWithTemplate(dset, pipeInfo.dsetTemplate, &descriptors);
|
||||||
|
|
||||||
|
// Unpack the source buffer to temporary buffers
|
||||||
|
DxvkMetaUnpackArgs args;
|
||||||
|
args.dstExtent = dstExtent;
|
||||||
|
args.srcExtent = dstExtent;
|
||||||
|
|
||||||
|
m_cmd->cmdBindPipeline(
|
||||||
|
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
|
pipeInfo.pipeHandle);
|
||||||
|
|
||||||
|
m_cmd->cmdBindDescriptorSet(
|
||||||
|
VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
|
pipeInfo.pipeLayout, dset,
|
||||||
|
0, nullptr);
|
||||||
|
|
||||||
|
m_cmd->cmdPushConstants(
|
||||||
|
pipeInfo.pipeLayout,
|
||||||
|
VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
0, sizeof(args), &args);
|
||||||
|
|
||||||
|
m_cmd->cmdDispatch(
|
||||||
|
(dstExtent.width + 63) / 64,
|
||||||
|
dstExtent.height,
|
||||||
|
dstSubresource.layerCount);
|
||||||
|
|
||||||
|
m_barriers.accessBuffer(
|
||||||
|
tmpBuffer->getSliceHandle(),
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT);
|
||||||
|
|
||||||
|
m_barriers.accessBuffer(
|
||||||
|
srcBuffer->getSliceHandle(),
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
|
VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
srcBuffer->info().stages,
|
||||||
|
srcBuffer->info().access);
|
||||||
|
|
||||||
|
// Prepare image for the data transfer operation
|
||||||
|
VkOffset3D dstOffset3D = { dstOffset.x, dstOffset.y, 0 };
|
||||||
|
VkExtent3D dstExtent3D = { dstExtent.width, dstExtent.height, 1 };
|
||||||
|
|
||||||
|
VkImageLayout initialImageLayout = dstImage->info().layout;
|
||||||
|
|
||||||
|
if (dstImage->isFullSubresource(dstSubresource, dstExtent3D))
|
||||||
|
initialImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
|
m_barriers.accessImage(
|
||||||
|
dstImage, vk::makeSubresourceRange(dstSubresource),
|
||||||
|
initialImageLayout,
|
||||||
|
dstImage->info().stages,
|
||||||
|
dstImage->info().access,
|
||||||
|
dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||||
|
|
||||||
|
m_barriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
|
// Copy temporary buffer data to depth-stencil image
|
||||||
|
VkImageSubresourceLayers dstSubresourceD = dstSubresource;
|
||||||
|
dstSubresourceD.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
|
||||||
|
VkImageSubresourceLayers dstSubresourceS = dstSubresource;
|
||||||
|
dstSubresourceS.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
|
||||||
|
std::array<VkBufferImageCopy, 2> copyRegions = {{
|
||||||
|
{ tmpBufferViewD->info().rangeOffset, 0, 0, dstSubresourceD, dstOffset3D, dstExtent3D },
|
||||||
|
{ tmpBufferViewS->info().rangeOffset, 0, 0, dstSubresourceS, dstOffset3D, dstExtent3D },
|
||||||
|
}};
|
||||||
|
|
||||||
|
m_cmd->cmdCopyBufferToImage(
|
||||||
|
tmpBuffer->getSliceHandle().handle,
|
||||||
|
dstImage->handle(),
|
||||||
|
dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||||
|
copyRegions.size(),
|
||||||
|
copyRegions.data());
|
||||||
|
|
||||||
|
m_barriers.accessImage(
|
||||||
|
dstImage, vk::makeSubresourceRange(dstSubresource),
|
||||||
|
dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
dstImage->info().layout,
|
||||||
|
dstImage->info().stages,
|
||||||
|
dstImage->info().access);
|
||||||
|
|
||||||
|
// Track all involved resources
|
||||||
|
m_cmd->trackResource(dstImage);
|
||||||
|
m_cmd->trackResource(srcBuffer);
|
||||||
|
|
||||||
|
m_cmd->trackResource(tmpBufferViewD);
|
||||||
|
m_cmd->trackResource(tmpBufferViewS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::discardBuffer(
|
void DxvkContext::discardBuffer(
|
||||||
const Rc<DxvkBuffer>& buffer) {
|
const Rc<DxvkBuffer>& buffer) {
|
||||||
if (m_barriers.isBufferDirty(buffer->getSliceHandle(), DxvkAccess::Write))
|
if (m_barriers.isBufferDirty(buffer->getSliceHandle(), DxvkAccess::Write))
|
||||||
|
@ -425,6 +425,29 @@ namespace dxvk {
|
|||||||
VkExtent2D srcExtent,
|
VkExtent2D srcExtent,
|
||||||
VkFormat format);
|
VkFormat format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unpacks buffer data to a depth-stencil image
|
||||||
|
*
|
||||||
|
* Writes the packed depth-stencil data to an image.
|
||||||
|
* See \ref copyDepthStencilImageToPackedBuffer for
|
||||||
|
* which formats are supported and how they are packed.
|
||||||
|
* \param [in] dstImage Destination image
|
||||||
|
* \param [in] dstSubresource Destination subresource
|
||||||
|
* \param [in] dstOffset Image area offset
|
||||||
|
* \param [in] dstExtent Image area size
|
||||||
|
* \param [in] srcBuffer Packed data buffer
|
||||||
|
* \param [in] srcOffset Packed data offset
|
||||||
|
* \param [in] format Packed data format
|
||||||
|
*/
|
||||||
|
void copyPackedBufferToDepthStencilImage(
|
||||||
|
const Rc<DxvkImage>& dstImage,
|
||||||
|
VkImageSubresourceLayers dstSubresource,
|
||||||
|
VkOffset2D dstOffset,
|
||||||
|
VkExtent2D dstExtent,
|
||||||
|
const Rc<DxvkBuffer>& srcBuffer,
|
||||||
|
VkDeviceSize srcOffset,
|
||||||
|
VkFormat format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Discards a buffer
|
* \brief Discards a buffer
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user