From da406133f19b1b6e9d97352798278ba986ebb183 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 2 Nov 2024 10:22:30 +0100 Subject: [PATCH] [d3d11] Add D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC --- src/d3d11/d3d11_context_imm.cpp | 27 +++++++++++----- src/d3d11/d3d11_texture.cpp | 17 ++++++++-- src/d3d11/d3d11_texture.h | 55 +++++++++++++++++++++++---------- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 1993a8fd2..b1987b722 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -465,6 +465,10 @@ namespace dxvk { if (!WaitForResource(*mappedImage, sequenceNumber, MapType, MapFlags)) return DXGI_ERROR_WAS_STILL_DRAWING; } + } else if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) { + // Nothing else to really do here, NotifyMap will ensure that we + // actually get a staging buffer that isn't currently in use. + ThrottleDiscard(layout.Size); } else { Rc mappedBuffer = pResource->GetMappedBuffer(Subresource); @@ -565,8 +569,8 @@ namespace dxvk { } } - // Mark the given subresource as mapped - pResource->SetMapType(Subresource, MapType); + // Mark the subresource as successfully mapped + pResource->NotifyMap(Subresource, MapType); if (pMappedResource) { pMappedResource->pData = pResource->GetMapPtr(Subresource, layout.Offset); @@ -582,28 +586,35 @@ namespace dxvk { void D3D11ImmediateContext::UnmapImage( D3D11CommonTexture* pResource, UINT Subresource) { - D3D11_MAP mapType = pResource->GetMapType(Subresource); - pResource->SetMapType(Subresource, D3D11_MAP(~0u)); + auto mapType = pResource->GetMapType(Subresource); + auto mapMode = pResource->GetMapMode(); - if (mapType == D3D11_MAP(~0u)) + if (mapType == D3D11CommonTexture::UnmappedSubresource) return; // Decrement mapped image counter only after making sure // the given subresource is actually mapped right now m_mappedImageCount -= 1; - if ((mapType != D3D11_MAP_READ) && (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)) { + // If the texture has an image as well as a staging buffer, + // upload the written buffer data to the image + bool needsUpload = mapType != D3D11_MAP_READ + && (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC); + + if (needsUpload) { if (pResource->NeedsDirtyRegionTracking()) { for (uint32_t i = 0; i < pResource->GetDirtyRegionCount(Subresource); i++) { D3D11_COMMON_TEXTURE_REGION region = pResource->GetDirtyRegion(Subresource, i); UpdateDirtyImageRegion(pResource, Subresource, ®ion); } - - pResource->ClearDirtyRegions(Subresource); } else { UpdateDirtyImageRegion(pResource, Subresource, nullptr); } } + + // Unmap the subresource. This will implicitly destroy the + // staging buffer for dynamically mapped images. + pResource->NotifyUnmap(Subresource); } diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index d6b0bd55d..27dbebcf0 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -200,11 +200,14 @@ namespace dxvk { } if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER - || m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) { + || m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_STAGING + || m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) { m_buffers.resize(subresourceCount); - for (uint32_t i = 0; i < subresourceCount; i++) - CreateMappedBuffer(i); + if (m_mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) { + for (uint32_t i = 0; i < subresourceCount; i++) + CreateMappedBuffer(i); + } } // Skip image creation if possible @@ -778,6 +781,14 @@ namespace dxvk { entry.buffer = m_device->GetDXVKDevice()->createBuffer(info, memType); entry.slice = entry.buffer->storage(); } + + + void D3D11CommonTexture::FreeMappedBuffer( + UINT Subresource) { + auto& entry = m_buffers[Subresource]; + entry.buffer = nullptr; + entry.slice = nullptr; + } VkImageType D3D11CommonTexture::GetImageTypeFromResourceDim(D3D11_RESOURCE_DIMENSION Dimension) { diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index 1c465ce3b..ae8985395 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -26,6 +26,7 @@ namespace dxvk { enum D3D11_COMMON_TEXTURE_MAP_MODE { D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer + D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC, ///< Mapped through temporary buffer D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem D3D11_COMMON_TEXTURE_MAP_MODE_STAGING, ///< Buffer only, no image }; @@ -83,7 +84,9 @@ namespace dxvk { class D3D11CommonTexture { public: - + + static constexpr D3D11_MAP UnmappedSubresource = D3D11_MAP(-1u); + D3D11CommonTexture( ID3D11Resource* pInterface, D3D11Device* pDevice, @@ -205,15 +208,40 @@ namespace dxvk { /** * \brief Sets map type for a given subresource - * + * + * Also ensures taht a staging buffer is created + * in case of dynamic mapping. * \param [in] Subresource The subresource * \param [in] MapType The map type */ - void SetMapType(UINT Subresource, D3D11_MAP MapType) { - if (Subresource < m_mapInfo.size()) + void NotifyMap(UINT Subresource, D3D11_MAP MapType) { + if (likely(Subresource < m_mapInfo.size())) { m_mapInfo[Subresource].mapType = MapType; + + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) + CreateMappedBuffer(Subresource); + } } - + + /** + * \brief Resets map info for a given subresource + * + * For dynamic mapping, this will also free the + * staging buffer. + * \param [in] Subresource The subresource + */ + void NotifyUnmap(UINT Subresource) { + if (likely(Subresource < m_mapInfo.size())) { + m_mapInfo[Subresource].mapType = UnmappedSubresource; + + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC) + FreeMappedBuffer(Subresource); + + if (Subresource < m_buffers.size()) + m_buffers[Subresource].dirtyRegions.clear(); + } + } + /** * \brief The DXVK image * \returns The DXVK image @@ -359,6 +387,7 @@ namespace dxvk { return reinterpret_cast(m_mapPtr) + Offset; case D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER: + case D3D11_COMMON_TEXTURE_MAP_MODE_DYNAMIC: case D3D11_COMMON_TEXTURE_MAP_MODE_STAGING: return reinterpret_cast(m_buffers[Subresource].slice->mapPtr()) + Offset; @@ -386,17 +415,6 @@ namespace dxvk { m_buffers[Subresource].dirtyRegions.push_back(region); } - /** - * \brief Clears dirty regions - * - * Removes all dirty regions from the given subresource. - * \param [in] Subresource Subresource index - */ - void ClearDirtyRegions(UINT Subresource) { - if (Subresource < m_buffers.size()) - m_buffers[Subresource].dirtyRegions.clear(); - } - /** * \brief Counts dirty regions * @@ -553,7 +571,7 @@ namespace dxvk { struct MappedInfo { D3D11_COMMON_TEXTURE_SUBRESOURCE_LAYOUT layout = { }; - D3D11_MAP mapType = D3D11_MAP(~0u); + D3D11_MAP mapType = UnmappedSubresource; uint64_t seq = 0u; }; @@ -575,6 +593,9 @@ namespace dxvk { void CreateMappedBuffer( UINT Subresource); + void FreeMappedBuffer( + UINT Subresource); + BOOL CheckImageSupport( const DxvkImageCreateInfo* pImageInfo, VkImageTiling Tiling) const;