diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index cfade3305..2dafdd693 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1790,11 +1790,66 @@ namespace dxvk { dstImage, srcImage, region); } else { this->resolveImageFb( - dstImage, srcImage, region, format); + dstImage, srcImage, region, format, + VK_RESOLVE_MODE_NONE_KHR, + VK_RESOLVE_MODE_NONE_KHR); } } - - + + + void DxvkContext::resolveDepthStencilImage( + const Rc& dstImage, + const Rc& srcImage, + const VkImageResolve& region, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode) { + this->spillRenderPass(); + + // Technically legal, but no-op + if (!depthMode && !stencilMode) + return; + + // Subsequent functions expect stencil mode to be None + // if either of the images have no stencil aspect + if (!(region.dstSubresource.aspectMask + & region.srcSubresource.aspectMask + & VK_IMAGE_ASPECT_STENCIL_BIT)) + stencilMode = VK_RESOLVE_MODE_NONE_KHR; + + // We can only use the depth-stencil resolve path if the + // extension is supported, if we are resolving a full + // subresource, and both images have the same format. + bool useFb = !m_device->extensions().khrDepthStencilResolve + || !dstImage->isFullSubresource(region.dstSubresource, region.extent) + || !srcImage->isFullSubresource(region.srcSubresource, region.extent) + || dstImage->info().format != srcImage->info().format; + + if (useFb) { + // Additionally, the given mode combination must be supported. + const auto& properties = m_device->properties().khrDepthStencilResolve; + + useFb |= (properties.supportedDepthResolveModes & depthMode) != depthMode + || (properties.supportedStencilResolveModes & stencilMode) != stencilMode; + + if (depthMode != stencilMode) { + useFb |= (!depthMode || !stencilMode) + ? !properties.independentResolveNone + : !properties.independentResolve; + } + } + + if (useFb) { + this->resolveImageFb( + dstImage, srcImage, region, VK_FORMAT_UNDEFINED, + depthMode, stencilMode); + } else { + this->resolveImageDs( + dstImage, srcImage, region, + depthMode, stencilMode); + } + } + + void DxvkContext::transformImage( const Rc& dstImage, const VkImageSubresourceRange& dstSubresources, @@ -2919,12 +2974,97 @@ namespace dxvk { m_cmd->trackResource(srcImage); } - + + void DxvkContext::resolveImageDs( + const Rc& dstImage, + const Rc& srcImage, + const VkImageResolve& region, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode) { + auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource); + auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource); + + if (m_execBarriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write) + || m_execBarriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)) + m_execBarriers.recordCommands(m_cmd); + + // Create image views covering the requested subresourcs + DxvkImageViewCreateInfo dstViewInfo; + dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + dstViewInfo.format = dstImage->info().format; + dstViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + dstViewInfo.aspect = region.dstSubresource.aspectMask; + dstViewInfo.minLevel = region.dstSubresource.mipLevel; + dstViewInfo.numLevels = 1; + dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer; + dstViewInfo.numLayers = region.dstSubresource.layerCount; + + DxvkImageViewCreateInfo srcViewInfo; + srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + srcViewInfo.format = srcImage->info().format; + srcViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + srcViewInfo.aspect = region.srcSubresource.aspectMask; + srcViewInfo.minLevel = region.srcSubresource.mipLevel; + srcViewInfo.numLevels = 1; + srcViewInfo.minLayer = region.srcSubresource.baseArrayLayer; + srcViewInfo.numLayers = region.srcSubresource.layerCount; + + Rc dstImageView = m_device->createImageView(dstImage, dstViewInfo); + Rc srcImageView = m_device->createImageView(srcImage, srcViewInfo); + + // Create a framebuffer for the resolve op + VkExtent3D passExtent = dstImageView->mipLevelExtent(0); + + Rc fb = new DxvkMetaResolveRenderPass( + m_device->vkd(), dstImageView, srcImageView, depthMode, stencilMode); + + VkRenderPassBeginInfo info; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.pNext = nullptr; + info.renderPass = fb->renderPass(); + info.framebuffer = fb->framebuffer(); + info.renderArea.offset = { 0, 0 }; + info.renderArea.extent = { passExtent.width, passExtent.height }; + info.clearValueCount = 0; + info.pClearValues = nullptr; + + m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); + m_cmd->cmdEndRenderPass(); + + m_execBarriers.accessImage( + dstImage, dstSubresourceRange, + dstImage->info().layout, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + dstImage->info().layout, + dstImage->info().stages, + dstImage->info().access); + + m_execBarriers.accessImage( + srcImage, srcSubresourceRange, + srcImage->info().layout, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + srcImage->info().layout, + srcImage->info().stages, + srcImage->info().access); + + m_cmd->trackResource(fb); + m_cmd->trackResource(dstImage); + m_cmd->trackResource(srcImage); + } + + void DxvkContext::resolveImageFb( const Rc& dstImage, const Rc& srcImage, const VkImageResolve& region, - VkFormat format) { + VkFormat format, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode) { auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource); auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource); @@ -2949,7 +3089,7 @@ namespace dxvk { // Create image views covering the requested subresourcs DxvkImageViewCreateInfo dstViewInfo; dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - dstViewInfo.format = format; + dstViewInfo.format = format ? format : dstImage->info().format; dstViewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; dstViewInfo.aspect = region.dstSubresource.aspectMask; dstViewInfo.minLevel = region.dstSubresource.mipLevel; @@ -2957,11 +3097,14 @@ namespace dxvk { dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer; dstViewInfo.numLayers = region.dstSubresource.layerCount; + if (region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) + dstViewInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + DxvkImageViewCreateInfo srcViewInfo; srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - srcViewInfo.format = format; + srcViewInfo.format = format ? format : srcImage->info().format; srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - srcViewInfo.aspect = region.srcSubresource.aspectMask; + srcViewInfo.aspect = region.srcSubresource.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_COLOR_BIT); srcViewInfo.minLevel = region.srcSubresource.mipLevel; srcViewInfo.numLevels = 1; srcViewInfo.minLayer = region.srcSubresource.baseArrayLayer; @@ -2969,18 +3112,22 @@ namespace dxvk { Rc dstImageView = m_device->createImageView(dstImage, dstViewInfo); Rc srcImageView = m_device->createImageView(srcImage, srcViewInfo); + Rc srcStencilView = nullptr; + + if ((region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) && stencilMode != VK_RESOLVE_MODE_NONE_KHR) { + srcViewInfo.aspect = VK_IMAGE_ASPECT_STENCIL_BIT; + srcStencilView = m_device->createImageView(srcImage, srcViewInfo); + } // Create a framebuffer and pipeline for the resolve op VkExtent3D passExtent = dstImageView->mipLevelExtent(0); Rc fb = new DxvkMetaResolveRenderPass( - m_device->vkd(), dstImageView, srcImageView, + m_device->vkd(), dstImageView, srcImageView, srcStencilView, dstImage->isFullSubresource(region.dstSubresource, region.extent)); auto pipeInfo = m_common->metaResolve().getPipeline( - format, srcImage->info().sampleCount, - VK_RESOLVE_MODE_NONE_KHR, - VK_RESOLVE_MODE_NONE_KHR); + dstViewInfo.format, srcImage->info().sampleCount, depthMode, stencilMode); VkDescriptorImageInfo descriptorImage; descriptorImage.sampler = VK_NULL_HANDLE; @@ -3001,6 +3148,12 @@ namespace dxvk { descriptorWrite.dstSet = allocateDescriptorSet(pipeInfo.dsetLayout); m_cmd->updateDescriptorSets(1, &descriptorWrite); + if (srcStencilView != nullptr) { + descriptorWrite.dstBinding = 1; + descriptorImage.imageView = srcStencilView->handle(); + m_cmd->updateDescriptorSets(1, &descriptorWrite); + } + VkViewport viewport; viewport.x = float(region.dstOffset.x); viewport.y = float(region.dstOffset.y); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index bb5b8a6fc..9299a6f9c 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -682,6 +682,22 @@ namespace dxvk { const VkImageResolve& region, VkFormat format); + /** + * \brief Resolves a multisampled depth-stencil resource + * + * \param [in] dstImage Destination image + * \param [in] srcImage Source image + * \param [in] region Region to resolve + * \param [in] depthMode Resolve mode for depth aspect + * \param [in] stencilMode Resolve mode for stencil aspect + */ + void resolveDepthStencilImage( + const Rc& dstImage, + const Rc& srcImage, + const VkImageResolve& region, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode); + /** * \brief Transforms image subresource layouts * @@ -1052,11 +1068,20 @@ namespace dxvk { const Rc& srcImage, const VkImageResolve& region); + void resolveImageDs( + const Rc& dstImage, + const Rc& srcImage, + const VkImageResolve& region, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode); + void resolveImageFb( const Rc& dstImage, const Rc& srcImage, const VkImageResolve& region, - VkFormat format); + VkFormat format, + VkResolveModeFlagBitsKHR depthMode, + VkResolveModeFlagBitsKHR stencilMode); void updatePredicate( const DxvkBufferSliceHandle& predicate, diff --git a/src/dxvk/dxvk_meta_resolve.cpp b/src/dxvk/dxvk_meta_resolve.cpp index 0f1f4775f..68bde159f 100644 --- a/src/dxvk/dxvk_meta_resolve.cpp +++ b/src/dxvk/dxvk_meta_resolve.cpp @@ -18,10 +18,12 @@ namespace dxvk { const Rc& vkd, const Rc& dstImageView, const Rc& srcImageView, + const Rc& srcStencilView, bool discardDst) : m_vkd(vkd), m_dstImageView(dstImageView), m_srcImageView(srcImageView), + m_srcStencilView(srcStencilView), m_renderPass (createShaderRenderPass(discardDst)), m_framebuffer (createShaderFramebuffer()) { } diff --git a/src/dxvk/dxvk_meta_resolve.h b/src/dxvk/dxvk_meta_resolve.h index 06d42c3cd..099782756 100644 --- a/src/dxvk/dxvk_meta_resolve.h +++ b/src/dxvk/dxvk_meta_resolve.h @@ -65,6 +65,7 @@ namespace dxvk { const Rc& vkd, const Rc& dstImageView, const Rc& srcImageView, + const Rc& srcStencilView, bool discardDst); DxvkMetaResolveRenderPass( @@ -90,6 +91,7 @@ namespace dxvk { const Rc m_dstImageView; const Rc m_srcImageView; + const Rc m_srcStencilView; VkRenderPass m_renderPass = VK_NULL_HANDLE; VkFramebuffer m_framebuffer = VK_NULL_HANDLE;