[d3d9] Unmap unused resources

This commit is contained in:
Robin Kertels 2022-02-14 00:08:01 +01:00 committed by Joshie
parent b4f432f1de
commit ea76bfd019
7 changed files with 100 additions and 4 deletions

View File

@ -560,3 +560,12 @@
# - True/False
# dxvk.enableDebugUtils = False
# Memory limit for locked D3D9 textures
#
# How much virtual memory will be used for textures (in MB).
# 0 to disable the limit.
# THIS DOES NOT IMPACT ACTUAL MEMORY CONSUMPTION OR TEXTURE QUALITY.
# DO NOT CHANGE THIS UNLESS YOU HAVE A VERY GOOD REASON.
# d3d9.textureMemory = 100

View File

@ -89,6 +89,8 @@ namespace dxvk {
D3D9CommonTexture::~D3D9CommonTexture() {
if (m_size != 0)
m_device->ChangeReportedMemory(m_size);
m_device->RemoveMappedTexture(this);
}
@ -488,7 +490,7 @@ namespace dxvk {
return D3D9_COMMON_TEXTURE_MAP_MODE_NONE;
#ifdef D3D9_ALLOW_UNMAPPING
if (m_desc.Pool != D3DPOOL_DEFAULT)
if (m_device->GetOptions()->textureMemory != 0 && m_desc.Pool != D3DPOOL_DEFAULT)
return D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE;
#endif

View File

@ -1,6 +1,7 @@
#include "d3d9_device.h"
#include "d3d9_annotation.h"
#include "d3d9_common_texture.h"
#include "d3d9_interface.h"
#include "d3d9_swapchain.h"
#include "d3d9_caps.h"
@ -4201,6 +4202,7 @@ namespace dxvk {
pResource->GetBuffer(Subresource, !needsReadback);
}
// Don't use MapTexture here to keep the mapped list small while the resource is still locked.
mapPtr = pResource->GetData(Subresource);
if (needsReadback) {
@ -4298,6 +4300,8 @@ namespace dxvk {
pResource->SetLocked(Subresource, true);
UnmapTextures();
const bool noDirtyUpdate = Flags & D3DLOCK_NO_DIRTY_UPDATE;
if ((desc.Pool == D3DPOOL_DEFAULT || !noDirtyUpdate) && !readOnly) {
if (pBox && MipLevel != 0) {
@ -4354,6 +4358,7 @@ namespace dxvk {
if (unlikely(!pResource->GetLocked(Subresource)))
return D3D_OK;
MapTexture(pResource, Subresource); // Add it to the list of mapped resources
pResource->SetLocked(Subresource, false);
// Flush image contents from staging if we aren't read only
@ -4380,6 +4385,7 @@ namespace dxvk {
pResource->SetNeedsReadback(Subresource, true);
}
UnmapTextures();
return D3D_OK;
}
@ -4463,7 +4469,7 @@ namespace dxvk {
+ srcOffsetBlockCount.y * pitch
+ srcOffsetBlockCount.x * formatInfo->elementSize;
const void* mapPtr = pSrcTexture->GetData(SrcSubresource);
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
VkDeviceSize dirtySize = extentBlockCount.width * extentBlockCount.height * extentBlockCount.depth * formatInfo->elementSize;
D3D9BufferSlice slice = AllocStagingBuffer(dirtySize);
const void* srcData = reinterpret_cast<const uint8_t*>(mapPtr) + copySrcOffset;
@ -4489,7 +4495,7 @@ namespace dxvk {
}
else {
const DxvkFormatInfo* formatInfo = lookupFormatInfo(pDestTexture->GetFormatMapping().FormatColor);
const void* mapPtr = pSrcTexture->GetData(SrcSubresource);
const void* mapPtr = MapTexture(pSrcTexture, SrcSubresource);
// Add more blocks for the other planes that we might have.
// TODO: PLEASE CLEAN ME
@ -4522,6 +4528,7 @@ namespace dxvk {
image, dstLayers,
slice.slice);
}
UnmapTextures();
}
void D3D9DeviceEx::EmitGenerateMips(
@ -4643,6 +4650,7 @@ namespace dxvk {
pResource->SetMapFlags(Flags | oldFlags);
pResource->IncrementLockCount();
UnmapTextures();
return D3D_OK;
}
@ -4675,7 +4683,8 @@ namespace dxvk {
pResource->DirtyRange().Clear();
TrackBufferMappingBufferSequenceNumber(pResource);
return D3D_OK;
UnmapTextures();
return D3D_OK;
}
@ -7223,4 +7232,61 @@ namespace dxvk {
return m_csChunk->empty() ? m_csSeqNum : m_csSeqNum + 1;
}
void* D3D9DeviceEx::MapTexture(D3D9CommonTexture* pTexture, UINT Subresource) {
// Will only be called inside the device lock
void *ptr = pTexture->GetData(Subresource);
#ifdef D3D9_ALLOW_UNMAPPING
if (likely(pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE)) {
m_mappedTextures.insert(pTexture);
}
#endif
return ptr;
}
void D3D9DeviceEx::TouchMappedTexture(D3D9CommonTexture* pTexture) {
#ifdef D3D9_ALLOW_UNMAPPING
if (pTexture->GetMapMode() != D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE)
return;
D3D9DeviceLock lock = LockDevice();
m_mappedTextures.touch(pTexture);
#endif
}
void D3D9DeviceEx::RemoveMappedTexture(D3D9CommonTexture* pTexture) {
#ifdef D3D9_ALLOW_UNMAPPING
if (pTexture->GetMapMode() != D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE)
return;
D3D9DeviceLock lock = LockDevice();
m_mappedTextures.remove(pTexture);
#endif
}
void D3D9DeviceEx::UnmapTextures() {
// Will only be called inside the device lock
#ifdef D3D9_ALLOW_UNMAPPING
uint32_t mappedMemory = m_memoryAllocator.MappedMemory();
if (likely(mappedMemory < uint32_t(m_d3d9Options.textureMemory)))
return;
uint32_t threshold = (m_d3d9Options.textureMemory / 4) * 3;
auto iter = m_mappedTextures.leastRecentlyUsedIter();
while (m_memoryAllocator.MappedMemory() >= threshold && iter != m_mappedTextures.leastRecentlyUsedEndIter()) {
if (unlikely((*iter)->IsAnySubresourceLocked() != 0)) {
iter++;
continue;
}
(*iter)->UnmapData();
iter = m_mappedTextures.remove(iter);
}
#endif
}
}

View File

@ -28,10 +28,13 @@
#include "d3d9_shader_permutations.h"
#include <unordered_set>
#include <vector>
#include <type_traits>
#include <unordered_map>
#include "../util/util_lru.h"
namespace dxvk {
class D3D9InterfaceEx;
@ -934,6 +937,10 @@ namespace dxvk {
return &m_memoryAllocator;
}
void* MapTexture(D3D9CommonTexture* pTexture, UINT Subresource);
void TouchMappedTexture(D3D9CommonTexture* pTexture);
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
private:
DxvkCsChunkRef AllocCsChunk() {
@ -1142,6 +1149,8 @@ namespace dxvk {
D3D9CommonTexture* pResource,
UINT Subresource);
void UnmapTextures();
uint64_t GetCurrentSequenceNumber();
Com<D3D9InterfaceEx> m_parent;
@ -1282,6 +1291,9 @@ namespace dxvk {
Direct3DState9 m_state;
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif
};
}

View File

@ -73,6 +73,7 @@ namespace dxvk {
this->deviceLocalConstantBuffers = config.getOption<bool> ("d3d9.deviceLocalConstantBuffers", false);
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
// If we are not Nvidia, enable general hazards.
this->generalHazards = adapter != nullptr

View File

@ -157,6 +157,9 @@ namespace dxvk {
/// Don't use non seamless cube maps
bool seamlessCubes;
/// How much virtual memory will be used for textures (in MB).
int32_t textureMemory;
};
}

View File

@ -90,6 +90,7 @@ namespace dxvk {
if (m_texture.IsManaged())
m_texture.SetAllNeedUpload();
m_parent->TouchMappedTexture(&m_texture);
return D3D_OK;
}
@ -174,6 +175,7 @@ namespace dxvk {
if (m_texture.IsManaged())
m_texture.SetAllNeedUpload();
m_parent->TouchMappedTexture(&m_texture);
return D3D_OK;
}
@ -267,6 +269,7 @@ namespace dxvk {
}
}
m_parent->TouchMappedTexture(&m_texture);
return D3D_OK;
}