1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-03 04:24:11 +01:00

[d3d9] Track dirty regions for UpdateTexture

This commit is contained in:
Robin Kertels 2020-09-07 13:09:30 +02:00 committed by Joshie
parent a0cf5926d8
commit 338f6dfb0e
4 changed files with 107 additions and 9 deletions

View File

@ -17,6 +17,10 @@ namespace dxvk {
? D3D9Format::D32
: D3D9Format::X8R8G8B8;
for (uint32_t i = 0; i < m_updateDirtyBoxes.size(); i++) {
AddUpdateDirtyBox(nullptr, i);
}
m_mapping = pDevice->LookupFormat(m_desc.Format);
m_mapMode = DetermineMapMode();

View File

@ -367,6 +367,40 @@ namespace dxvk {
void PreLoadAll();
void PreLoadSubresource(UINT Subresource);
void AddUpdateDirtyBox(CONST D3DBOX* pDirtyBox, uint32_t layer) {
if (pDirtyBox) {
D3DBOX box = *pDirtyBox;
if (box.Right <= box.Left
|| box.Bottom <= box.Top
|| box.Back <= box.Front)
return;
D3DBOX& updateBox = m_updateDirtyBoxes[layer];
if (updateBox.Left == updateBox.Right) {
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_updateDirtyBoxes[layer] = { 0, 0, m_desc.Width, m_desc.Height, 0, m_desc.Depth };
}
}
void ClearUpdateDirtyBoxes() {
for (uint32_t i = 0; i < m_updateDirtyBoxes.size(); i++) {
m_updateDirtyBoxes[i] = { 0, 0, 0, 0, 0, 0 };
}
}
const D3DBOX& GetUpdateDirtyBox(uint32_t layer) const {
return m_updateDirtyBoxes[layer];
}
private:
D3D9DeviceEx* m_device;
@ -407,6 +441,8 @@ namespace dxvk {
D3DTEXTUREFILTERTYPE m_mipFilter = D3DTEXF_LINEAR;
std::array<D3DBOX, 6> m_updateDirtyBoxes;
/**
* \brief Mip level
* \returns Size of packed mip level in bytes

View File

@ -649,6 +649,19 @@ namespace dxvk {
if (unlikely(srcTextureInfo->Desc()->Format != dstTextureInfo->Desc()->Format))
return D3DERR_INVALIDCALL;
if (dst->GetMipLevel() == 0) {
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->AddUpdateDirtyBox(&updateDirtyRect, dst->GetFace());
} else {
dstTextureInfo->AddUpdateDirtyBox(nullptr, dst->GetFace());
}
}
const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTextureInfo->GetFormatMapping().FormatColor);
VkOffset3D srcBlockOffset = { 0u, 0u, 0u };
@ -726,27 +739,54 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
const Rc<DxvkImage> 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->GetUpdateDirtyBox(a);
for (uint32_t m = 0; m < mipLevels; m++) {
Rc<DxvkBuffer> 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);
VkOffset3D srcByteOffset = {
offset.x / int32_t(formatInfo->blockSize.width),
offset.y / int32_t(formatInfo->blockSize.height),
offset.z / int32_t(formatInfo->blockSize.depth)
};
VkDeviceSize srcOffset = srcByteOffset.z * formatInfo->elementSize * blockCount.depth
+ 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);
});
}
}
@ -760,6 +800,8 @@ namespace dxvk {
else
dstTexInfo->MarkAllDirty();
srcTexInfo->ClearUpdateDirtyBoxes();
FlushImplicit(false);
return D3D_OK;
@ -3929,6 +3971,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->AddUpdateDirtyBox(pBox, Face);
}
auto& desc = *(pResource->Desc());
bool alloced = pResource->CreateBufferSubresource(Subresource);

View File

@ -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.AddUpdateDirtyBox(&box, 0);
} else {
m_texture.AddUpdateDirtyBox(nullptr, 0);
}
return D3D_OK;
}
@ -151,8 +157,8 @@ namespace dxvk {
return GetSubresource(Level)->UnlockBox();
}
HRESULT STDMETHODCALLTYPE D3D9Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) {
m_texture.AddUpdateDirtyBox(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.AddUpdateDirtyBox(&box, Face);
} else {
m_texture.AddUpdateDirtyBox(nullptr, Face);
}
return D3D_OK;
}