Skip to content

Commit

Permalink
[dxvk] Support arbitrary source formats for color<->depth copies
Browse files Browse the repository at this point in the history
Fixes rendering bugs in War Thunder.
  • Loading branch information
doitsujin committed Mar 20, 2024
1 parent c5aeb0f commit 70e34dc
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 66 deletions.
104 changes: 62 additions & 42 deletions src/dxvk/dxvk_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3563,69 +3563,90 @@ namespace dxvk {
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
dstSubresource.aspectMask,
srcSubresource.aspectMask,
srcImage->info().format);
DxvkMetaCopyFormats viewFormats = m_common->metaCopy().getFormats(
dstImage->info().format, dstSubresource.aspectMask,
srcImage->info().format, srcSubresource.aspectMask);

if (!viewFormat) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}

// 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
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
// create a temporary image to draw to, and then copy to the actual
// 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))
&& (dstImage->isViewCompatible(viewFormat));
bool dstIsCompatible = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (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(
dstImage, dstSubresource, dstOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
} else {
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
} else if (dstIsCompatible || srcIsCompatible) {
DxvkImageCreateInfo imageInfo = dstImage->info();
imageInfo.format = viewFormat;
imageInfo.flags = 0;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.extent = extent;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.mipLevels = 1;
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;

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;
if (!dstIsCompatible) {
imageInfo.format = viewFormats.dstFormat;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_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,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

VkImageSubresourceLayers tmpSubresource = dstSubresource;
VkImageSubresourceLayers tmpSubresource = { };
tmpSubresource.aspectMask = tmpImage->formatInfo()->aspectMask;
tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0;
tmpSubresource.layerCount = imageInfo.numLayers;

VkOffset3D tmpOffset = { 0, 0, 0 };

this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);

this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
if (!dstIsCompatible) {
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);

this->copyImageHw(
dstImage, dstSubresource, dstOffset,
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, ")"));
}
}

Expand All @@ -3638,6 +3659,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent) {
this->invalidateState();

Expand Down Expand Up @@ -3701,8 +3723,6 @@ namespace dxvk {
m_execAcquires.recordCommands(m_cmd);

// Create source and destination image views
VkFormat srcFormat = srcImage->info().format;

Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
dstImage, dstSubresource, dstFormat,
srcImage, srcSubresource, srcFormat);
Expand Down
1 change: 1 addition & 0 deletions src/dxvk/dxvk_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent);

bool copyImageClear(
Expand Down
37 changes: 17 additions & 20 deletions src/dxvk/dxvk_meta_copy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,32 +120,29 @@ namespace dxvk {
}


VkFormat DxvkMetaCopyObjects::getCopyDestinationFormat(
DxvkMetaCopyFormats DxvkMetaCopyObjects::getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect,
VkFormat srcFormat) const {
if (srcAspect == dstAspect)
return srcFormat;

if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT
&& srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
switch (srcFormat) {
case VK_FORMAT_D16_UNORM: return VK_FORMAT_R16_UNORM;
case VK_FORMAT_D32_SFLOAT: return VK_FORMAT_R32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
}
}
VkFormat srcFormat,
VkImageAspectFlags srcAspect) const {
if (dstAspect == srcAspect)
return { dstFormat, srcFormat };

if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT
&& srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT && srcAspect == VK_IMAGE_ASPECT_DEPTH_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;
case VK_FORMAT_D16_UNORM: return { VK_FORMAT_R16_UNORM, VK_FORMAT_D16_UNORM };
case VK_FORMAT_D32_SFLOAT: return { VK_FORMAT_R32_SFLOAT, VK_FORMAT_D32_SFLOAT };
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 };
}
}

return VK_FORMAT_UNDEFINED;
return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
}


Expand Down
20 changes: 16 additions & 4 deletions src/dxvk/dxvk_meta_copy.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ namespace dxvk {
VkExtent2D srcSize;
};

/**
* \brief Pair of view formats for copy operation
*/
struct DxvkMetaCopyFormats {
VkFormat dstFormat;
VkFormat srcFormat;
};

/**
* \brief Copy pipeline
*
Expand Down Expand Up @@ -122,13 +130,17 @@ namespace dxvk {
* Returns the color format that we need to use
* as the destination image view format in case
* 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
*/
VkFormat getCopyDestinationFormat(
DxvkMetaCopyFormats getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect,
VkFormat srcFormat) const;
VkFormat srcFormat,
VkImageAspectFlags srcAspect) const;

/**
* \brief Creates pipeline for meta copy operation
Expand Down

0 comments on commit 70e34dc

Please sign in to comment.