From 47362090981a0718f33c51424bab0242e896b789 Mon Sep 17 00:00:00 2001 From: Robin Kertels Date: Mon, 7 Sep 2020 13:09:30 +0200 Subject: [PATCH] [d3d9] Track dirty regions for UpdateTexture --- src/d3d9/d3d9_common_texture.h | 38 ++++++++++++++++++++++ src/d3d9/d3d9_device.cpp | 58 +++++++++++++++++++++++++++++----- src/d3d9/d3d9_texture.cpp | 14 +++++++- 3 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index ea60b11301e..6d4cf675af7 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -366,6 +366,42 @@ namespace dxvk { void PreLoadAll(); void PreLoadSubresource(UINT Subresource); + void AddUpdateBox(CONST D3DBOX* pDirtyRect, uint32_t layer) { + if (pDirtyRect) { + D3DBOX box = *pDirtyRect; + if (box.Right <= box.Left + || box.Bottom <= box.Top + || box.Back <= box.Front) + return; + + D3DBOX& updateBox = m_updateBoxes[layer]; + if (updateBox.Left == 0 && updateBox.Right == 0 + && updateBox.Top == 0 && updateBox.Bottom == 0 + && updateBox.Front == 0 && updateBox.Back == 0) { + updateBox = box; + } else { + updateBox.Left = std::min(updateBox.Left, box.Left); + updateBox.Right = std::max(updateBox.Right, box.Right); + updateBox.Top = std::min(updateBox.Top, box.Top); + updateBox.Bottom = std::max(updateBox.Bottom, box.Bottom); + updateBox.Front = std::min(updateBox.Front, box.Front); + updateBox.Back = std::max(updateBox.Back, box.Back); + } + } else { + m_updateBoxes[layer] = { 0, 0, m_desc.Width, m_desc.Height }; + } + } + + void ClearUpdateBoxes() { + for (uint32_t i = 0; i < m_updateBoxes.size(); i++) { + m_updateBoxes[i] = { 0, 0, 0, 0, 0, 0 }; + } + } + + const D3DBOX& GetUpdateBox(uint32_t layer) const { + return m_updateBoxes[layer]; + } + private: D3D9DeviceEx* m_device; @@ -406,6 +442,8 @@ namespace dxvk { D3DTEXTUREFILTERTYPE m_mipFilter = D3DTEXF_LINEAR; + std::array m_updateBoxes; + /** * \brief Mip level * \returns Size of packed mip level in bytes diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 856687250f1..43ed764975d 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -646,6 +646,17 @@ namespace dxvk { if (unlikely(srcTextureInfo->Desc()->Format != dstTextureInfo->Desc()->Format)) return D3DERR_INVALIDCALL; + if (pSourceRect) { + D3DBOX updateDirtyRect = { UINT(pSourceRect->left), UINT(pSourceRect->top), UINT(pSourceRect->right), UINT(pSourceRect->bottom), 0, 1 }; + if (pDestinationSurface) { + updateDirtyRect.Left = pDestPoint->x; + updateDirtyRect.Top = pDestPoint->y; + } + dstTextureInfo->AddUpdateBox(&updateDirtyRect, dst->GetFace()); + } else { + dstTextureInfo->AddUpdateBox(nullptr, dst->GetFace()); + } + const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTextureInfo->GetFormatMapping().FormatColor); VkOffset3D srcBlockOffset = { 0u, 0u, 0u }; @@ -723,27 +734,52 @@ namespace dxvk { return D3DERR_INVALIDCALL; const Rc dstImage = dstTexInfo->GetImage(); - + const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTexInfo->GetFormatMapping().FormatColor); uint32_t mipLevels = std::min(srcTexInfo->Desc()->MipLevels, dstTexInfo->Desc()->MipLevels); uint32_t arraySlices = std::min(srcTexInfo->Desc()->ArraySize, dstTexInfo->Desc()->ArraySize); + for (uint32_t a = 0; a < arraySlices; a++) { + const D3DBOX& box = srcTexInfo->GetUpdateBox(a); for (uint32_t m = 0; m < mipLevels; m++) { Rc srcBuffer = srcTexInfo->GetBuffer(srcTexInfo->CalcSubresource(a, m)); - VkImageSubresourceLayers dstLayers = { VK_IMAGE_ASPECT_COLOR_BIT, m, a, 1 }; - - VkExtent3D extent = dstImage->mipLevelExtent(m); - + + VkOffset3D offset = { + alignDown(int32_t(box.Left) >> m, int32_t(formatInfo->blockSize.width)), + alignDown(int32_t(box.Top) >> m, int32_t(formatInfo->blockSize.height)), + alignDown(int32_t(box.Front) >> m, int32_t(formatInfo->blockSize.depth)) + }; + VkExtent3D extent = { + alignDown(uint32_t((box.Right - box.Left) >> m), formatInfo->blockSize.width), + alignDown(uint32_t((box.Bottom - box.Top) >> m), formatInfo->blockSize.height), + alignDown(uint32_t((box.Back - box.Front) >> m), formatInfo->blockSize.depth), + }; + + VkExtent3D levelExtent = dstImage->mipLevelExtent(m); + VkExtent3D blockCount = util::computeBlockCount(levelExtent, formatInfo->blockSize); + VkOffset2D srcByteOffset = { + offset.x / int32_t(formatInfo->blockSize.width), + offset.y / int32_t(formatInfo->blockSize.height) + }; + VkDeviceSize srcOffset = srcByteOffset.y * formatInfo->elementSize * blockCount.width + + srcByteOffset.x * formatInfo->elementSize; + VkExtent2D srcExtent = VkExtent2D{ blockCount.width * formatInfo->blockSize.width, + blockCount.height * formatInfo->blockSize.height }; + EmitCs([ cDstImage = dstImage, cSrcBuffer = srcBuffer, cDstLayers = dstLayers, - cExtent = extent + cExtent = extent, + cOffset = offset, + cSrcOffset = srcOffset, + cSrcExtent = srcExtent ] (DxvkContext* ctx) { ctx->copyBufferToImage( cDstImage, cDstLayers, - VkOffset3D{ 0, 0, 0 }, cExtent, - cSrcBuffer, 0, { 0u, 0u }); + cOffset, cExtent, + cSrcBuffer, cSrcOffset, + cSrcExtent); }); } } @@ -757,6 +793,8 @@ namespace dxvk { else dstTexInfo->MarkAllDirty(); + srcTexInfo->ClearUpdateBoxes(); + FlushImplicit(false); return D3D_OK; @@ -3920,6 +3958,10 @@ namespace dxvk { if (unlikely((Flags & (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE)) == (D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE))) Flags &= ~D3DLOCK_DISCARD; + if (!(Flags & D3DLOCK_NO_DIRTY_UPDATE) && !(Flags & D3DLOCK_READONLY)) { + pResource->AddUpdateBox(pBox, Face); + } + auto& desc = *(pResource->Desc()); bool alloced = pResource->CreateBufferSubresource(Subresource); diff --git a/src/d3d9/d3d9_texture.cpp b/src/d3d9/d3d9_texture.cpp index 1cf50b49a1b..99104c9e336 100644 --- a/src/d3d9/d3d9_texture.cpp +++ b/src/d3d9/d3d9_texture.cpp @@ -76,6 +76,12 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D9Texture2D::AddDirtyRect(CONST RECT* pDirtyRect) { + if (pDirtyRect) { + D3DBOX box = { UINT(pDirtyRect->left), UINT(pDirtyRect->top), UINT(pDirtyRect->right), UINT(pDirtyRect->bottom), 0, 1 }; + m_texture.AddUpdateBox(&box, 0); + } else { + m_texture.AddUpdateBox(nullptr, 0); + } return D3D_OK; } @@ -151,8 +157,8 @@ namespace dxvk { return GetSubresource(Level)->UnlockBox(); } - HRESULT STDMETHODCALLTYPE D3D9Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) { + m_texture.AddUpdateBox(pDirtyBox, 0); return D3D_OK; } @@ -230,6 +236,12 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE D3D9TextureCube::AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect) { + if (pDirtyRect) { + D3DBOX box = { UINT(pDirtyRect->left), UINT(pDirtyRect->top), UINT(pDirtyRect->right), UINT(pDirtyRect->bottom), 0, 1 }; + m_texture.AddUpdateBox(&box, Face); + } else { + m_texture.AddUpdateBox(nullptr, Face); + } return D3D_OK; }