diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 468024c6..57bdfb7a 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -554,6 +554,9 @@ namespace dxvk { cExtent); } }); + + if (dstTextureInfo->CanUpdateMappedBufferEarly()) + UpdateMappedBuffer(dstTextureInfo, dstSubresource); } } @@ -604,8 +607,11 @@ namespace dxvk { cSrcBuffer.length()); }); } else { - const Rc dstImage = GetCommonTexture(pDstResource)->GetImage(); - const Rc srcImage = GetCommonTexture(pSrcResource)->GetImage(); + auto dstTexture = GetCommonTexture(pDstResource); + auto srcTexture = GetCommonTexture(pSrcResource); + + const Rc dstImage = dstTexture->GetImage(); + const Rc srcImage = srcTexture->GetImage(); const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(dstImage->info().format); const DxvkFormatInfo* srcFormatInfo = imageFormatInfo(srcImage->info().format); @@ -652,6 +658,11 @@ namespace dxvk { cSrcImage, cSrcLayers, VkOffset3D { 0, 0, 0 }, cExtent); }); + + if (dstTexture->CanUpdateMappedBufferEarly()) { + for (uint32_t j = 0; j < dstImage->info().numLayers; j++) + UpdateMappedBuffer(dstTexture, { dstLayers.aspectMask, i, j }); + } } } } @@ -1229,6 +1240,9 @@ namespace dxvk { cPackedFormat); } }); + + if (textureInfo->CanUpdateMappedBufferEarly()) + UpdateMappedBuffer(textureInfo, subresource); } } @@ -3667,6 +3681,40 @@ namespace dxvk { ctrSlotId + i, ~0u); } } + + + void D3D11DeviceContext::UpdateMappedBuffer( + const D3D11CommonTexture* pTexture, + VkImageSubresource Subresource) { + Rc mappedImage = pTexture->GetImage(); + Rc mappedBuffer = pTexture->GetMappedBuffer(); + + VkFormat packedFormat = m_parent->LookupPackedFormat( + pTexture->Desc()->Format, pTexture->GetFormatMode()).Format; + + VkExtent3D levelExtent = mappedImage->mipLevelExtent(Subresource.mipLevel); + + EmitCs([ + cImageBuffer = std::move(mappedBuffer), + cImage = std::move(mappedImage), + cSubresources = vk::makeSubresourceLayers(Subresource), + cLevelExtent = levelExtent, + cPackedFormat = packedFormat + ] (DxvkContext* ctx) { + if (cSubresources.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + ctx->copyImageToBuffer( + cImageBuffer, 0, VkExtent2D { 0u, 0u }, + cImage, cSubresources, VkOffset3D { 0, 0, 0 }, + cLevelExtent); + } else { + ctx->copyDepthStencilImageToPackedBuffer( + cImageBuffer, 0, cImage, cSubresources, + VkOffset2D { 0, 0 }, + VkExtent2D { cLevelExtent.width, cLevelExtent.height }, + cPackedFormat); + } + }); + } bool D3D11DeviceContext::ValidateRenderTargets( diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 8a115637..23fb8f03 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -803,6 +803,10 @@ namespace dxvk { DxbcProgramType Stage, D3D11UnorderedAccessBindings& Bindings); + void UpdateMappedBuffer( + const D3D11CommonTexture* pTexture, + VkImageSubresource Subresource); + bool ValidateRenderTargets( UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 65065e38..9572f548 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -383,32 +383,16 @@ namespace dxvk { // When using any map mode which requires the image contents // to be preserved, and if the GPU has write access to the // image, copy the current image contents into the buffer. - if (pResource->Desc()->Usage == D3D11_USAGE_STAGING) { - auto subresourceLayers = vk::makeSubresourceLayers(subresource); - - EmitCs([ - cImageBuffer = mappedBuffer, - cImage = mappedImage, - cSubresources = subresourceLayers, - cLevelExtent = levelExtent, - cPackedFormat = packedFormat - ] (DxvkContext* ctx) { - if (cSubresources.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - ctx->copyImageToBuffer( - cImageBuffer, 0, VkExtent2D { 0u, 0u }, - cImage, cSubresources, VkOffset3D { 0, 0, 0 }, - cLevelExtent); - } else { - ctx->copyDepthStencilImageToPackedBuffer( - cImageBuffer, 0, cImage, cSubresources, - VkOffset2D { 0, 0 }, - VkExtent2D { cLevelExtent.width, cLevelExtent.height }, - cPackedFormat); - } - }); + if (pResource->Desc()->Usage == D3D11_USAGE_STAGING + && !pResource->CanUpdateMappedBufferEarly()) { + UpdateMappedBuffer(pResource, subresource); + MapFlags &= ~D3D11_MAP_FLAG_DO_NOT_WAIT; } - WaitForResource(mappedBuffer, 0); + // Wait for mapped buffer to become available + if (!WaitForResource(mappedBuffer, MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + physSlice = mappedBuffer->getSliceHandle(); } diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index 4479e0a1..597aa7a2 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -130,6 +130,22 @@ namespace dxvk { void ClearMappedSubresource() { m_mappedSubresource = VkImageSubresource { }; } + + /** + * \brief Checks whether we can update the mapped buffer early + * + * For images which are mapped through a buffer and that are + * only used for transfer operations, we can update the mapped + * buffer right after performing those transfers to avoid stalls. + * \returns \c true if the mapped buffer can be updated early + */ + bool CanUpdateMappedBufferEarly() const { + return m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER + && (m_desc.BindFlags & ~D3D11_BIND_SHADER_RESOURCE) == 0 + && m_desc.Usage == D3D11_USAGE_STAGING + && m_desc.MipLevels == 1 + && m_desc.ArraySize == 1; + } /** * \brief Computes subresource from the subresource index