diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 9bb9c92c..dcaa7cb7 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -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 tmpImage = m_device->createImage(imageInfo, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + Rc 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); + if (!dstIsCompatible) { + this->copyImageFbDirect( + tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat, + srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent); - this->copyImageHw( - dstImage, dstSubresource, dstOffset, - tmpImage, tmpSubresource, tmpOffset, 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, ")")); } } @@ -3638,6 +3659,7 @@ namespace dxvk { const Rc& srcImage, VkImageSubresourceLayers srcSubresource, VkOffset3D srcOffset, + VkFormat srcFormat, VkExtent3D extent) { this->invalidateState(); @@ -3701,8 +3723,6 @@ namespace dxvk { m_execAcquires.recordCommands(m_cmd); // Create source and destination image views - VkFormat srcFormat = srcImage->info().format; - Rc views = new DxvkMetaCopyViews(m_device->vkd(), dstImage, dstSubresource, dstFormat, srcImage, srcSubresource, srcFormat); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index b1fbc7df..3b61d474 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1506,6 +1506,7 @@ namespace dxvk { const Rc& srcImage, VkImageSubresourceLayers srcSubresource, VkOffset3D srcOffset, + VkFormat srcFormat, VkExtent3D extent); bool copyImageClear( diff --git a/src/dxvk/dxvk_meta_copy.cpp b/src/dxvk/dxvk_meta_copy.cpp index 45339af7..5b33d0f8 100644 --- a/src/dxvk/dxvk_meta_copy.cpp +++ b/src/dxvk/dxvk_meta_copy.cpp @@ -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) { + VkFormat srcFormat, + VkImageAspectFlags srcAspect) const { + if (dstAspect == srcAspect) + return { dstFormat, 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; + 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 }; } } - if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT - && 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; + return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED }; } diff --git a/src/dxvk/dxvk_meta_copy.h b/src/dxvk/dxvk_meta_copy.h index c32dbc0d..3584ad7e 100644 --- a/src/dxvk/dxvk_meta_copy.h +++ b/src/dxvk/dxvk_meta_copy.h @@ -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 * @@ -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