From e0dea48dae1fcfa6f904be9a6c65fc870b714e0c Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 10 Mar 2025 20:40:02 +0100 Subject: [PATCH] [dxvk] Extend resolveImage to support depth-stencil resolves Also require the format to be defined. --- src/d3d11/d3d11_context.cpp | 7 ++- src/d3d9/d3d9_device.cpp | 12 ++--- src/d3d9/d3d9_swapchain.cpp | 5 +- src/dxvk/dxvk_context.cpp | 105 ++++++++++++++++++++++++++++-------- src/dxvk/dxvk_context.h | 8 ++- 5 files changed, 103 insertions(+), 34 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index cad645607..1f0b605df 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -909,7 +909,7 @@ namespace dxvk { cDstImage->mipLevelExtent(cDstLayers.mipLevel)); }); } else { - const VkFormat format = m_parent->LookupFormat( + VkFormat format = m_parent->LookupFormat( Format, DXGI_VK_FORMAT_MODE_ANY).Format; EmitCs([ @@ -919,6 +919,8 @@ namespace dxvk { cSrcSubres = srcSubresourceLayers, cFormat = format ] (DxvkContext* ctx) { + VkFormat format = cFormat ? cFormat : cSrcImage->info().format; + VkImageResolve region; region.srcSubresource = cSrcSubres; region.srcOffset = VkOffset3D { 0, 0, 0 }; @@ -926,7 +928,8 @@ namespace dxvk { region.dstOffset = VkOffset3D { 0, 0, 0 }; region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel); - ctx->resolveImage(cDstImage, cSrcImage, region, cFormat); + ctx->resolveImage(cDstImage, cSrcImage, region, format, + getDefaultResolveMode(format), VK_RESOLVE_MODE_NONE); }); if constexpr (!IsDeferred) diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index dd5f4f399..dfda984f1 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -1353,9 +1353,8 @@ namespace dxvk { cRegion = region ] (DxvkContext* ctx) { if (cRegion.srcSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->resolveImage( - cDstImage, cSrcImage, cRegion, - VK_FORMAT_UNDEFINED); + ctx->resolveImage(cDstImage, cSrcImage, cRegion, cSrcImage->info().format, + VK_RESOLVE_MODE_AVERAGE_BIT, VK_RESOLVE_MODE_SAMPLE_ZERO_BIT); } else { ctx->resolveDepthStencilImage( @@ -4935,6 +4934,8 @@ namespace dxvk { cResolveImage = mappedImage, cSubresource = subresourceLayers ] (DxvkContext* ctx) { + VkFormat format = cMainImage->info().format; + VkImageResolve region; region.srcSubresource = cSubresource; region.srcOffset = VkOffset3D { 0, 0, 0 }; @@ -4943,9 +4944,8 @@ namespace dxvk { region.extent = cMainImage->mipLevelExtent(cSubresource.mipLevel); if (cSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->resolveImage( - cResolveImage, cMainImage, region, - cMainImage->info().format); + ctx->resolveImage(cResolveImage, cMainImage, region, format, + getDefaultResolveMode(format), VK_RESOLVE_MODE_NONE); } else { ctx->resolveDepthStencilImage( diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 776c400d8..e51357f4b 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -327,9 +327,8 @@ namespace dxvk { resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 }; resolveRegion.extent = cSrcImage->info().extent; - ctx->resolveImage( - cDstImage, cSrcImage, - resolveRegion, VK_FORMAT_UNDEFINED); + ctx->resolveImage(cDstImage, cSrcImage, resolveRegion, + cSrcImage->info().format, VK_RESOLVE_MODE_AVERAGE_BIT, VK_RESOLVE_MODE_NONE); }); srcImage = std::move(resolvedSrc); diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 84266ab71..b66ed0d64 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1939,34 +1939,97 @@ namespace dxvk { const Rc& dstImage, const Rc& srcImage, const VkImageResolve& region, - VkFormat format) { - if (format == VK_FORMAT_UNDEFINED) - format = srcImage->info().format; + VkFormat format, + VkResolveModeFlagBits mode, + VkResolveModeFlagBits stencilMode) { + auto formatInfo = lookupFormatInfo(format); - if (resolveImageInline(dstImage, srcImage, region, format, VK_RESOLVE_MODE_AVERAGE_BIT, VK_RESOLVE_MODE_NONE)) + // Normalize resolve modes to available subresources + VkImageAspectFlags aspects = region.srcSubresource.aspectMask + & region.dstSubresource.aspectMask; + + if (!(aspects & VK_IMAGE_ASPECT_STENCIL_BIT)) + stencilMode = VK_RESOLVE_MODE_NONE; + + // No-op, but legal + if (!mode && !stencilMode) + return; + + // Check whether the given resolve modes are supported for render pass resolves + bool useFb = false; + + if (formatInfo->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + const auto& properties = m_device->properties().vk12; + + useFb |= (properties.supportedDepthResolveModes & mode) != mode + || (properties.supportedStencilResolveModes & stencilMode) != stencilMode; + + if (mode != stencilMode && (formatInfo->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) { + useFb |= (!mode || !stencilMode) + ? !properties.independentResolveNone + : !properties.independentResolve; + } + } else { + // For color images, only the default mode is supported + useFb |= mode != getDefaultResolveMode(formatInfo); + } + + // Also fall back to framebuffer path if this is a partial resolve, + // or if two depth-stencil images are not format-compatible. + if (!useFb) { + useFb |= !dstImage->isFullSubresource(region.dstSubresource, region.extent) + || !srcImage->isFullSubresource(region.srcSubresource, region.extent); + + if (formatInfo->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) + useFb |= dstImage->info().format != srcImage->info().format; + } + + // Ensure that we can actually use both images as intended + DxvkImageUsageInfo dstUsage = { }; + dstUsage.viewFormatCount = 1; + dstUsage.viewFormats = &format; + + if (formatInfo->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + dstUsage.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + dstUsage.stages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dstUsage.access = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } else { + dstUsage.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + dstUsage.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dstUsage.access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + } + + DxvkImageUsageInfo srcUsage = dstUsage; + + if (useFb) { + srcUsage.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + srcUsage.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + srcUsage.access = VK_ACCESS_SHADER_READ_BIT; + } + + bool useHw = !ensureImageCompatibility(dstImage, dstUsage) + || !ensureImageCompatibility(srcImage, srcUsage); + + // If possible, fold resolve into active render pass + if (!useHw && !useFb && resolveImageInline(dstImage, srcImage, region, format, mode, stencilMode)) return; this->spillRenderPass(true); this->prepareImage(dstImage, vk::makeSubresourceRange(region.dstSubresource)); this->prepareImage(srcImage, vk::makeSubresourceRange(region.srcSubresource)); - auto formatInfo = lookupFormatInfo(format); - - bool useRp = srcImage->info().format != format - || dstImage->info().format != format; - - useRp |= (srcImage->info().usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) - && (dstImage->info().usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - - if (useRp) { - // Work out resolve mode based on format properties. For color images, - // we must use AVERAGE unless the resolve uses an integer format. - VkResolveModeFlagBits mode = getDefaultResolveMode(formatInfo); - - this->resolveImageRp(dstImage, srcImage, region, - format, mode, mode); - } else { + if (unlikely(useHw)) { + // Only used as a fallback if we can't use the images any other way, + // format and resolve mode might not match what the app requests. this->resolveImageHw(dstImage, srcImage, region); + } else if (unlikely(useFb)) { + // Only used for weird resolve modes or partial resolves + this->resolveImageFb(dstImage, srcImage, + region, format, mode, stencilMode); + } else { + // Default path, use a resolve attachment + this->resolveImageRp(dstImage, srcImage, + region, format, mode, stencilMode); } } @@ -2486,7 +2549,7 @@ namespace dxvk { attachment.view->image(), region, resolve.depthMode, resolve.stencilMode); } else { resolveImage(resolve.imageView->image(), attachment.view->image(), - region, attachment.view->info().format); + region, attachment.view->info().format, resolve.depthMode, resolve.stencilMode); } resolve.layerMask &= ~0u << (layerIndex + layerCount); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 86fe31bdc..583797b1a 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1046,13 +1046,17 @@ namespace dxvk { * \param [in] srcImage Source image * \param [in] region Region to resolve * \param [in] format Format for the resolve operation + * \param [in] mode Image resolve mode + * \param [in] stencilMode Stencil resolve mode */ void resolveImage( const Rc& dstImage, const Rc& srcImage, const VkImageResolve& region, - VkFormat format); - + VkFormat format, + VkResolveModeFlagBits mode, + VkResolveModeFlagBits stencilMode); + /** * \brief Resolves a multisampled depth-stencil resource *