[dxvk] Support arbitrary source formats for color<->depth copies

Fixes rendering bugs in War Thunder.
This commit is contained in:
Philip Rebohle 2024-03-19 18:55:34 +01:00
parent c5aeb0f87a
commit 70e34dc31c
4 changed files with 96 additions and 66 deletions

View File

@ -3563,69 +3563,90 @@ namespace dxvk {
VkImageSubresourceLayers srcSubresource, VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset, VkOffset3D srcOffset,
VkExtent3D extent) { VkExtent3D extent) {
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat( DxvkMetaCopyFormats viewFormats = m_common->metaCopy().getFormats(
dstSubresource.aspectMask, dstImage->info().format, dstSubresource.aspectMask,
srcSubresource.aspectMask, srcImage->info().format, srcSubresource.aspectMask);
srcImage->info().format);
if (!viewFormat) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}
// Usually we should be able to draw directly to the destination image, // Usually we should be able to draw directly to the destination image,
// but in some cases this might not be possible, e.g. if when copying // but in some cases this might not be possible, e.g. if when copying
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations, // from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
// create a temporary image to draw to, and then copy to the actual // create a temporary image to draw to, and then copy to the actual
// destination image using a regular Vulkan transfer function. // destination image using a regular Vulkan transfer function.
bool useDirectCopy = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) bool dstIsCompatible = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormat)); && (dstImage->isViewCompatible(viewFormats.dstFormat));
bool srcIsCompatible = (srcImage->info().usage & (VK_IMAGE_USAGE_SAMPLED_BIT))
&& (srcImage->isViewCompatible(viewFormats.srcFormat));
if (useDirectCopy) { if (dstIsCompatible && srcIsCompatible) {
this->copyImageFbDirect( this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormat, dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, extent); srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
} else { } else if (dstIsCompatible || srcIsCompatible) {
DxvkImageCreateInfo imageInfo = dstImage->info(); DxvkImageCreateInfo imageInfo = dstImage->info();
imageInfo.format = viewFormat;
imageInfo.flags = 0; imageInfo.flags = 0;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.extent = extent; imageInfo.extent = extent;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.mipLevels = 1; imageInfo.mipLevels = 1;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
imageInfo.viewFormatCount = 0; imageInfo.viewFormatCount = 0;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { if (!dstIsCompatible) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; imageInfo.format = viewFormats.dstFormat;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
} else { imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
} else /* if (!srcIsCompatible) */ {
imageInfo.format = viewFormats.srcFormat;
imageInfo.numLayers = srcSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
} }
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkImageSubresourceLayers tmpSubresource = dstSubresource; VkImageSubresourceLayers tmpSubresource = { };
tmpSubresource.aspectMask = tmpImage->formatInfo()->aspectMask;
tmpSubresource.mipLevel = 0; tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0; tmpSubresource.baseArrayLayer = 0;
tmpSubresource.layerCount = imageInfo.numLayers;
VkOffset3D tmpOffset = { 0, 0, 0 }; VkOffset3D tmpOffset = { 0, 0, 0 };
this->copyImageFbDirect( if (!dstIsCompatible) {
tmpImage, tmpSubresource, tmpOffset, viewFormat, this->copyImageFbDirect(
srcImage, srcSubresource, srcOffset, extent); tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
this->copyImageHw( this->copyImageHw(
dstImage, dstSubresource, dstOffset, dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent); tmpImage, tmpSubresource, tmpOffset, extent);
} else /* if (!srcIsCompatible) */ {
this->copyImageHw(
tmpImage, tmpSubresource, tmpOffset,
srcImage, srcSubresource, srcOffset, extent);
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
tmpImage, tmpSubresource, tmpOffset, viewFormats.srcFormat, extent);
}
} else {
Logger::err(str::format("DxvkContext: copyImageFb: Unsupported operation:\n"
" srcFormat = ", srcImage->info().format, " (aspect ", srcSubresource.aspectMask, ")\n",
" dstFormat = ", dstImage->info().format, " (aspect ", dstSubresource.aspectMask, ")"));
} }
} }
@ -3638,6 +3659,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage, const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource, VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset, VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent) { VkExtent3D extent) {
this->invalidateState(); this->invalidateState();
@ -3701,8 +3723,6 @@ namespace dxvk {
m_execAcquires.recordCommands(m_cmd); m_execAcquires.recordCommands(m_cmd);
// Create source and destination image views // Create source and destination image views
VkFormat srcFormat = srcImage->info().format;
Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(), Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
dstImage, dstSubresource, dstFormat, dstImage, dstSubresource, dstFormat,
srcImage, srcSubresource, srcFormat); srcImage, srcSubresource, srcFormat);

View File

@ -1506,6 +1506,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage, const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource, VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset, VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent); VkExtent3D extent);
bool copyImageClear( bool copyImageClear(

View File

@ -120,32 +120,29 @@ namespace dxvk {
} }
VkFormat DxvkMetaCopyObjects::getCopyDestinationFormat( DxvkMetaCopyFormats DxvkMetaCopyObjects::getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect, VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect, VkFormat srcFormat,
VkFormat srcFormat) const { VkImageAspectFlags srcAspect) const {
if (srcAspect == dstAspect) if (dstAspect == srcAspect)
return srcFormat; return { dstFormat, srcFormat };
if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT && srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
&& srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
switch (srcFormat) { switch (srcFormat) {
case VK_FORMAT_D16_UNORM: return VK_FORMAT_R16_UNORM; case VK_FORMAT_D16_UNORM: return { VK_FORMAT_R16_UNORM, VK_FORMAT_D16_UNORM };
case VK_FORMAT_D32_SFLOAT: return VK_FORMAT_R32_SFLOAT; case VK_FORMAT_D32_SFLOAT: return { VK_FORMAT_R32_SFLOAT, VK_FORMAT_D32_SFLOAT };
default: return VK_FORMAT_UNDEFINED; default: return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
}
} else if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT && srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
switch (dstFormat) {
case VK_FORMAT_D16_UNORM: return { VK_FORMAT_D16_UNORM, VK_FORMAT_R16_UNORM };
case VK_FORMAT_D32_SFLOAT: return { VK_FORMAT_D32_SFLOAT, VK_FORMAT_R32_SFLOAT };
default: return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
} }
} }
if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
&& srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
switch (srcFormat) {
case VK_FORMAT_R16_UNORM: return VK_FORMAT_D16_UNORM;
case VK_FORMAT_R32_SFLOAT: return VK_FORMAT_D32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
}
}
return VK_FORMAT_UNDEFINED;
} }

View File

@ -25,6 +25,14 @@ namespace dxvk {
VkExtent2D srcSize; VkExtent2D srcSize;
}; };
/**
* \brief Pair of view formats for copy operation
*/
struct DxvkMetaCopyFormats {
VkFormat dstFormat;
VkFormat srcFormat;
};
/** /**
* \brief Copy pipeline * \brief Copy pipeline
* *
@ -122,13 +130,17 @@ namespace dxvk {
* Returns the color format that we need to use * Returns the color format that we need to use
* as the destination image view format in case * as the destination image view format in case
* of depth to color image copies. * of depth to color image copies.
* \param [in] format Depth format * \param [in] dstFormat Destination image format
* \param [in] dstAspect Destination aspect mask
* \param [in] srcFormat Source image format
* \param [in] srcAspect Source aspect mask
* \returns Corresponding color format * \returns Corresponding color format
*/ */
VkFormat getCopyDestinationFormat( DxvkMetaCopyFormats getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect, VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect, VkFormat srcFormat,
VkFormat srcFormat) const; VkImageAspectFlags srcAspect) const;
/** /**
* \brief Creates pipeline for meta copy operation * \brief Creates pipeline for meta copy operation