From 95bfac84f192347051dc5e5fc4ab7cb111828aa7 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 19 Apr 2019 11:19:14 +0200 Subject: [PATCH] [dxvk] Support image sub-regions for resolve operations Required for legacy graphics APIs. --- src/d3d11/d3d11_context.cpp | 12 ++- src/d3d11/d3d11_swapchain.cpp | 22 +++-- src/dxvk/dxvk_context.cpp | 84 +++++++++---------- src/dxvk/dxvk_context.h | 12 +-- src/dxvk/dxvk_meta_resolve.cpp | 25 ++++-- src/dxvk/dxvk_meta_resolve.h | 5 +- src/dxvk/shaders/dxvk_resolve_frag_f.frag | 7 +- src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag | 7 +- src/dxvk/shaders/dxvk_resolve_frag_i.frag | 7 +- src/dxvk/shaders/dxvk_resolve_frag_u.frag | 7 +- 10 files changed, 113 insertions(+), 75 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 72d25cfdd..9459caaa3 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1321,10 +1321,14 @@ namespace dxvk { cSrcSubres = srcSubresourceLayers, cFormat = format ] (DxvkContext* ctx) { - ctx->resolveImage( - cDstImage, cDstSubres, - cSrcImage, cSrcSubres, - cFormat); + VkImageResolve region; + region.srcSubresource = cSrcSubres; + region.srcOffset = VkOffset3D { 0, 0, 0 }; + region.dstSubresource = cDstSubres; + region.dstOffset = VkOffset3D { 0, 0, 0 }; + region.extent = cDstImage->mipLevelExtent(cDstSubres.mipLevel); + + ctx->resolveImage(cDstImage, cSrcImage, region, cFormat); }); } } diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 55034c3ea..3878e5289 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -213,16 +213,22 @@ namespace dxvk { // Resolve back buffer if it is multisampled. We // only have to do it only for the first frame. if (m_swapImageResolve != nullptr && i == 0) { - VkImageSubresourceLayers resolveSubresources; - resolveSubresources.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolveSubresources.mipLevel = 0; - resolveSubresources.baseArrayLayer = 0; - resolveSubresources.layerCount = 1; + VkImageSubresourceLayers resolveSubresource; + resolveSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolveSubresource.mipLevel = 0; + resolveSubresource.baseArrayLayer = 0; + resolveSubresource.layerCount = 1; + + VkImageResolve resolveRegion; + resolveRegion.srcSubresource = resolveSubresource; + resolveRegion.srcOffset = VkOffset3D { 0, 0, 0 }; + resolveRegion.dstSubresource = resolveSubresource; + resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 }; + resolveRegion.extent = m_swapImage->info().extent; m_context->resolveImage( - m_swapImageResolve, resolveSubresources, - m_swapImage, resolveSubresources, - VK_FORMAT_UNDEFINED); + m_swapImageResolve, m_swapImage, + resolveRegion, VK_FORMAT_UNDEFINED); } // Presentation semaphores and WSI swap chain image diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0e606dcdc..ec2b802c0 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1671,9 +1671,8 @@ namespace dxvk { void DxvkContext::resolveImage( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources, + const VkImageResolve& region, VkFormat format) { this->spillRenderPass(); @@ -1683,13 +1682,10 @@ namespace dxvk { if (srcImage->info().format == format && dstImage->info().format == format) { this->resolveImageHw( - dstImage, dstSubresources, - srcImage, srcSubresources); + dstImage, srcImage, region); } else { this->resolveImageFb( - dstImage, dstSubresources, - srcImage, srcSubresources, - format); + dstImage, srcImage, region, format); } } @@ -2605,11 +2601,10 @@ namespace dxvk { void DxvkContext::resolveImageHw( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources) { - auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresources); - auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresources); + const VkImageResolve& region) { + auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource); + auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource); if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write) || m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)) @@ -2617,9 +2612,14 @@ namespace dxvk { // We only support resolving to the entire image // area, so we might as well discard its contents + VkImageLayout initialLayout = dstImage->info().layout; + + if (dstImage->isFullSubresource(region.dstSubresource, region.extent)) + initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + m_transitions.accessImage( dstImage, dstSubresourceRange, - VK_IMAGE_LAYOUT_UNDEFINED, 0, 0, + initialLayout, 0, 0, dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); @@ -2633,17 +2633,10 @@ namespace dxvk { m_transitions.recordCommands(m_cmd); - VkImageResolve imageRegion; - imageRegion.srcSubresource = srcSubresources; - imageRegion.srcOffset = VkOffset3D { 0, 0, 0 }; - imageRegion.dstSubresource = dstSubresources; - imageRegion.dstOffset = VkOffset3D { 0, 0, 0 }; - imageRegion.extent = srcImage->mipLevelExtent(srcSubresources.mipLevel); - m_cmd->cmdResolveImage( srcImage->handle(), srcImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL), dstImage->handle(), dstImage->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL), - 1, &imageRegion); + 1, ®ion); m_barriers.accessImage( dstImage, dstSubresourceRange, @@ -2670,12 +2663,11 @@ namespace dxvk { void DxvkContext::resolveImageFb( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources, + const VkImageResolve& region, VkFormat format) { - auto dstSubresourceRange = vk::makeSubresourceRange(dstSubresources); - auto srcSubresourceRange = vk::makeSubresourceRange(srcSubresources); + auto dstSubresourceRange = vk::makeSubresourceRange(region.dstSubresource); + auto srcSubresourceRange = vk::makeSubresourceRange(region.srcSubresource); if (m_barriers.isImageDirty(dstImage, dstSubresourceRange, DxvkAccess::Write) || m_barriers.isImageDirty(srcImage, srcSubresourceRange, DxvkAccess::Write)) @@ -2700,31 +2692,32 @@ namespace dxvk { dstViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; dstViewInfo.format = format; dstViewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - dstViewInfo.aspect = dstSubresources.aspectMask; - dstViewInfo.minLevel = dstSubresources.mipLevel; + dstViewInfo.aspect = region.dstSubresource.aspectMask; + dstViewInfo.minLevel = region.dstSubresource.mipLevel; dstViewInfo.numLevels = 1; - dstViewInfo.minLayer = dstSubresources.baseArrayLayer; - dstViewInfo.numLayers = dstSubresources.layerCount; + dstViewInfo.minLayer = region.dstSubresource.baseArrayLayer; + dstViewInfo.numLayers = region.dstSubresource.layerCount; DxvkImageViewCreateInfo srcViewInfo; srcViewInfo.type = VK_IMAGE_VIEW_TYPE_2D_ARRAY; srcViewInfo.format = format; srcViewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - srcViewInfo.aspect = srcSubresources.aspectMask; - srcViewInfo.minLevel = srcSubresources.mipLevel; + srcViewInfo.aspect = region.srcSubresource.aspectMask; + srcViewInfo.minLevel = region.srcSubresource.mipLevel; srcViewInfo.numLevels = 1; - srcViewInfo.minLayer = srcSubresources.baseArrayLayer; - srcViewInfo.numLayers = srcSubresources.layerCount; + 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 and pipeline for the resolve op - Rc fb = new DxvkMetaResolveRenderPass( - m_device->vkd(), dstImageView, srcImageView); - VkExtent3D passExtent = dstImageView->mipLevelExtent(0); + Rc fb = new DxvkMetaResolveRenderPass( + m_device->vkd(), dstImageView, srcImageView, + dstImage->isFullSubresource(region.dstSubresource, region.extent)); + auto pipeInfo = m_metaResolve->getPipeline( format, srcImage->info().sampleCount); @@ -2748,16 +2741,16 @@ namespace dxvk { m_cmd->updateDescriptorSets(1, &descriptorWrite); VkViewport viewport; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = float(passExtent.width); - viewport.height = float(passExtent.height); + viewport.x = float(region.dstOffset.x); + viewport.y = float(region.dstOffset.y); + viewport.width = float(region.extent.width); + viewport.height = float(region.extent.height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor; - scissor.offset = { 0, 0 }; - scissor.extent = { passExtent.width, passExtent.height }; + scissor.offset = { region.dstOffset.x, region.dstOffset.y }; + scissor.extent = { region.extent.width, region.extent.height }; VkRenderPassBeginInfo info; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -2770,13 +2763,20 @@ namespace dxvk { info.pClearValues = nullptr; // Perform the actual resolve operation + VkOffset2D srcOffset = { + region.srcOffset.x, + region.srcOffset.y }; + m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeHandle); m_cmd->cmdBindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeInfo.pipeLayout, descriptorWrite.dstSet, 0, nullptr); m_cmd->cmdSetViewport(0, 1, &viewport); m_cmd->cmdSetScissor (0, 1, &scissor); - m_cmd->cmdDraw(1, dstSubresources.layerCount, 0, 0); + m_cmd->cmdPushConstants(pipeInfo.pipeLayout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof(srcOffset), &srcOffset); + m_cmd->cmdDraw(1, region.dstSubresource.layerCount, 0, 0); m_cmd->cmdEndRenderPass(); m_barriers.accessImage( diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 735f14213..91204d2b7 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -629,16 +629,14 @@ namespace dxvk { * If it is \c VK_FORMAT_UNDEFINED, the resolve operation * will use the source image format. * \param [in] dstImage Destination image - * \param [in] dstSubresources Subresources to write to * \param [in] srcImage Source image - * \param [in] srcSubresources Subresources to read from + * \param [in] region Region to resolve * \param [in] format Format for the resolve operation */ void resolveImage( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources, + const VkImageResolve& region, VkFormat format); /** @@ -950,15 +948,13 @@ namespace dxvk { void resolveImageHw( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources); + const VkImageResolve& region); void resolveImageFb( const Rc& dstImage, - const VkImageSubresourceLayers& dstSubresources, const Rc& srcImage, - const VkImageSubresourceLayers& srcSubresources, + const VkImageResolve& region, VkFormat format); void updatePredicate( diff --git a/src/dxvk/dxvk_meta_resolve.cpp b/src/dxvk/dxvk_meta_resolve.cpp index 012d07def..bb133b3f9 100644 --- a/src/dxvk/dxvk_meta_resolve.cpp +++ b/src/dxvk/dxvk_meta_resolve.cpp @@ -13,11 +13,12 @@ namespace dxvk { DxvkMetaResolveRenderPass::DxvkMetaResolveRenderPass( const Rc& vkd, const Rc& dstImageView, - const Rc& srcImageView) + const Rc& srcImageView, + bool discardDst) : m_vkd(vkd), m_dstImageView(dstImageView), m_srcImageView(srcImageView), - m_renderPass (createRenderPass ()), + m_renderPass (createRenderPass(discardDst)), m_framebuffer (createFramebuffer()) { } @@ -27,17 +28,22 @@ namespace dxvk { } - VkRenderPass DxvkMetaResolveRenderPass::createRenderPass() const { + VkRenderPass DxvkMetaResolveRenderPass::createRenderPass(bool discard) const { VkAttachmentDescription attachment; attachment.flags = 0; attachment.format = m_dstImageView->info().format; attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.initialLayout = m_dstImageView->imageInfo().layout; attachment.finalLayout = m_dstImageView->imageInfo().layout; + + if (discard) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } VkAttachmentReference dstRef; dstRef.attachment = 0; @@ -274,14 +280,19 @@ namespace dxvk { VkPipelineLayout DxvkMetaResolveObjects::createPipelineLayout( VkDescriptorSetLayout descriptorSetLayout) const { + VkPushConstantRange push; + push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + push.offset = 0; + push.size = sizeof(VkOffset2D); + VkPipelineLayoutCreateInfo info; info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; info.pNext = nullptr; info.flags = 0; info.setLayoutCount = 1; info.pSetLayouts = &descriptorSetLayout; - info.pushConstantRangeCount = 0; - info.pPushConstantRanges = nullptr; + info.pushConstantRangeCount = 1; + info.pPushConstantRanges = &push; VkPipelineLayout result = VK_NULL_HANDLE; if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) diff --git a/src/dxvk/dxvk_meta_resolve.h b/src/dxvk/dxvk_meta_resolve.h index ee0f789cc..2fd3499bd 100644 --- a/src/dxvk/dxvk_meta_resolve.h +++ b/src/dxvk/dxvk_meta_resolve.h @@ -58,7 +58,8 @@ namespace dxvk { DxvkMetaResolveRenderPass( const Rc& vkd, const Rc& dstImageView, - const Rc& srcImageView); + const Rc& srcImageView, + bool discardDst); ~DxvkMetaResolveRenderPass(); @@ -80,7 +81,7 @@ namespace dxvk { VkRenderPass m_renderPass = VK_NULL_HANDLE; VkFramebuffer m_framebuffer = VK_NULL_HANDLE; - VkRenderPass createRenderPass() const; + VkRenderPass createRenderPass(bool discard) const; VkFramebuffer createFramebuffer() const; diff --git a/src/dxvk/shaders/dxvk_resolve_frag_f.frag b/src/dxvk/shaders/dxvk_resolve_frag_f.frag index 0823bc2de..645a2f9bf 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_f.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_f.frag @@ -6,8 +6,13 @@ layout(binding = 0) uniform sampler2DMSArray s_image; layout(location = 0) out vec4 o_color; +layout(push_constant) +uniform u_info_t { + ivec2 offset; +} u_info; + void main() { - ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer); + ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); vec4 color = vec4(0.0f); for (int i = 0; i < c_samples; i++) color += texelFetch(s_image, coord, i); diff --git a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag b/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag index 180a9c25c..a9cf9ee48 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_f_amd.frag @@ -9,8 +9,13 @@ uniform sampler2DMSArray s_image; layout(location = 0) out vec4 o_color; +layout(push_constant) +uniform u_info_t { + ivec2 offset; +} u_info; + void main() { - ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer); + ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); // get a four-bit fragment index for each sample uint fragMask = fragmentMaskFetchAMD(s_image, coord); diff --git a/src/dxvk/shaders/dxvk_resolve_frag_i.frag b/src/dxvk/shaders/dxvk_resolve_frag_i.frag index d7cb2a87c..021980d64 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_i.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_i.frag @@ -4,7 +4,12 @@ layout(binding = 0) uniform isampler2DMSArray s_image; layout(location = 0) out ivec4 o_color; +layout(push_constant) +uniform u_info_t { + ivec2 offset; +} u_info; + void main() { - ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer); + ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); o_color = texelFetch(s_image, coord, 0); } \ No newline at end of file diff --git a/src/dxvk/shaders/dxvk_resolve_frag_u.frag b/src/dxvk/shaders/dxvk_resolve_frag_u.frag index dc6299f1f..3d3cfdf36 100644 --- a/src/dxvk/shaders/dxvk_resolve_frag_u.frag +++ b/src/dxvk/shaders/dxvk_resolve_frag_u.frag @@ -4,7 +4,12 @@ layout(binding = 0) uniform usampler2DMSArray s_image; layout(location = 0) out uvec4 o_color; +layout(push_constant) +uniform u_info_t { + ivec2 offset; +} u_info; + void main() { - ivec3 coord = ivec3(gl_FragCoord.xy, gl_Layer); + ivec3 coord = ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer); o_color = texelFetch(s_image, coord, 0); } \ No newline at end of file