Made resource tracking optional

This commit is contained in:
cdozdil
2026-01-11 14:19:20 +03:00
parent 404811b436
commit cf549e3be8
5 changed files with 259 additions and 40 deletions
+5
View File
@@ -306,6 +306,11 @@ HUDFixImmediate=auto
; true or false - Default (auto) is false
AlwaysTrackHeaps=auto
; Instead of single mutex use shards for tracking resources
; Might improve performance on heavy multithreaded games
; true or false - Default (auto) is false
UseShards=auto
; Block rarely used resources from using as hudless
; to prevent flickers and other issues
; true or false - Default (auto) is false
+2
View File
@@ -142,6 +142,7 @@ bool Config::Reload(std::filesystem::path iniPath)
FGHUDLimit.set_from_config(readInt("OptiFG", "HUDLimit"));
FGHUDFixExtended.set_from_config(readBool("OptiFG", "HUDFixExtended"));
FGImmediateCapture.set_from_config(readBool("OptiFG", "HUDFixImmediate"));
FGUseShards.set_from_config(readBool("OptiFG", "UseShards"));
FGAlwaysTrackHeaps.set_from_config(readBool("OptiFG", "AlwaysTrackHeaps"));
FGResourceBlocking.set_from_config(readBool("OptiFG", "ResourceBlocking"));
FGMakeDepthCopy.set_from_config(readBool("OptiFG", "MakeDepthCopy"));
@@ -768,6 +769,7 @@ bool Config::SaveIni()
ini.SetValue("OptiFG", "HUDFixExtended", GetBoolValue(Instance()->FGHUDFixExtended.value_for_config()).c_str());
ini.SetValue("OptiFG", "HUDFixImmediate",
GetBoolValue(Instance()->FGImmediateCapture.value_for_config()).c_str());
ini.SetValue("OptiFG", "UseShards", GetBoolValue(Instance()->FGUseShards.value_for_config()).c_str());
ini.SetValue("OptiFG", "AlwaysTrackHeaps",
GetBoolValue(Instance()->FGAlwaysTrackHeaps.value_for_config()).c_str());
ini.SetValue("OptiFG", "ResourceBlocking",
+1
View File
@@ -438,6 +438,7 @@ class Config
// OptiFG - Resource Tracking
CustomOptional<bool> FGAlwaysTrackHeaps { false };
CustomOptional<bool> FGResourceBlocking { false };
CustomOptional<bool> FGUseShards { false };
// OptiFG - DLSS-D Depth scale
CustomOptional<bool> FGEnableDepthScale { false };
+248 -33
View File
@@ -109,7 +109,12 @@ static PFN_OMSetRenderTargets o_OMSetRenderTargets = nullptr;
static PFN_SetGraphicsRootDescriptorTable o_SetGraphicsRootDescriptorTable = nullptr;
static PFN_SetComputeRootDescriptorTable o_SetComputeRootDescriptorTable = nullptr;
// heaps
static std::mutex _hudlessTrackMutex;
static ankerl::unordered_dense::map<ID3D12GraphicsCommandList*,
ankerl::unordered_dense::map<ID3D12Resource*, ResourceInfo>>
fgPossibleHudless[BUFFER_COUNT];
// heaps section
// #define USE_SPINLOCK_MUTEX_FOR_HEAP_CREATION
@@ -1190,10 +1195,26 @@ void ResTrack_Dx12::hkSetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList*
}
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
if (!fgPossibleHudless[fIndex].contains(This))
{
ankerl::unordered_dense::map<ID3D12Resource*, ResourceInfo> newMap;
newMap.reserve(32);
fgPossibleHudless[fIndex].insert_or_assign(This, newMap);
}
LOG_TRACK("AddRef Resource: {:X}, Desc: {:X}", (size_t) capturedBuffer->buffer, BaseDescriptor.ptr);
fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer);
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
@@ -1293,10 +1314,27 @@ void ResTrack_Dx12::hkOMSetRenderTargets(ID3D12GraphicsCommandList* This, UINT N
}
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
if (!fgPossibleHudless[fIndex].contains(This))
{
ankerl::unordered_dense::map<ID3D12Resource*, ResourceInfo> newMap;
newMap.reserve(32);
fgPossibleHudless[fIndex].insert_or_assign(This, newMap);
}
// add found resource
LOG_TRACK("AddRef Resource: {:X}, Desc: {:X}", (size_t) capturedBuffer->buffer, handle.ptr);
fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer);
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
@@ -1382,10 +1420,27 @@ void ResTrack_Dx12::hkSetComputeRootDescriptorTable(ID3D12GraphicsCommandList* T
}
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
if (!fgPossibleHudless[fIndex].contains(This))
{
ankerl::unordered_dense::map<ID3D12Resource*, ResourceInfo> newMap;
newMap.reserve(32);
fgPossibleHudless[fIndex].insert_or_assign(This, newMap);
}
// add found resource
LOG_TRACK("AddRef Resource: {:X}, Desc: {:X}", (size_t) capturedBuffer->buffer, handle.ptr);
fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer);
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
@@ -1429,18 +1484,61 @@ void ResTrack_Dx12::hkDrawInstanced(ID3D12GraphicsCommandList* This, UINT Vertex
LOG_TRACK("CmdList: {:X}", (size_t) This);
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
if (This == MenuOverlayDx::MenuCommandList() && fgPossibleHudless[fIndex].contains(This))
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
fgPossibleHudless[fIndex][This].clear();
return;
}
if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This))
{
LOG_DEBUG_ONLY("Early exit");
return;
}
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
auto val0 = fgPossibleHudless[fIndex][This];
do
{
// if this command list does not have entries skip
if (val0.size() == 0)
break;
if (Config::Instance()->FGHudfixDisableDI.value_or_default())
break;
for (auto& [key, val] : val0)
{
std::lock_guard<std::mutex> lock(_drawMutex);
val.captureInfo |= CaptureInfo::DrawInstanced;
if (Hudfix_Dx12::CheckForHudless(This, &val, val.state))
break;
}
} while (false);
fgPossibleHudless[fIndex][This].clear();
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (This == MenuOverlayDx::MenuCommandList() && shard.map.contains(This))
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
shard.map[This].clear();
return;
}
@@ -1452,6 +1550,12 @@ void ResTrack_Dx12::hkDrawInstanced(ID3D12GraphicsCommandList* This, UINT Vertex
return;
}
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
auto val0 = shard.map[This];
do
@@ -1495,18 +1599,63 @@ void ResTrack_Dx12::hkDrawIndexedInstanced(ID3D12GraphicsCommandList* This, UINT
LOG_TRACK("CmdList: {:X}", (size_t) This);
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
if (This == MenuOverlayDx::MenuCommandList() && fgPossibleHudless[fIndex].contains(This))
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
fgPossibleHudless[fIndex][This].clear();
return;
}
// if can't find output skip
if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This))
{
LOG_DEBUG_ONLY("Early exit");
return;
}
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
auto val0 = fgPossibleHudless[fIndex][This];
do
{
// if this command list does not have entries skip
if (val0.size() == 0)
break;
if (Config::Instance()->FGHudfixDisableDII.value_or_default())
break;
for (auto& [key, val] : val0)
{
// LOG_DEBUG("Waiting _drawMutex {:X}", (size_t)val.buffer);
std::lock_guard<std::mutex> lock(_drawMutex);
val.captureInfo |= CaptureInfo::DrawIndexedInstanced;
if (Hudfix_Dx12::CheckForHudless(This, &val, val.state))
break;
}
} while (false);
fgPossibleHudless[fIndex][This].clear();
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (This == MenuOverlayDx::MenuCommandList() && shard.map.contains(This))
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
shard.map[This].clear();
return;
}
@@ -1518,6 +1667,12 @@ void ResTrack_Dx12::hkDrawIndexedInstanced(ID3D12GraphicsCommandList* This, UINT
return;
}
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
auto val0 = shard.map[This];
do
@@ -1633,18 +1788,63 @@ void ResTrack_Dx12::hkDispatch(ID3D12GraphicsCommandList* This, UINT ThreadGroup
LOG_TRACK("CmdList: {:X}", (size_t) This);
auto fIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (!_useShards)
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
if (This == MenuOverlayDx::MenuCommandList() && fgPossibleHudless[fIndex].contains(This))
{
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
fgPossibleHudless[fIndex][This].clear();
return;
}
// if can't find output skip
if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This))
{
LOG_DEBUG_ONLY("Early exit");
return;
}
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
auto val0 = fgPossibleHudless[fIndex][This];
do
{
// if this command list does not have entries skip
if (val0.size() == 0)
break;
if (Config::Instance()->FGHudfixDisableDispatch.value_or_default())
break;
for (auto& [key, val] : val0)
{
// LOG_DEBUG("Waiting _drawMutex {:X}", (size_t)val.buffer);
std::lock_guard<std::mutex> lock(_drawMutex);
val.captureInfo |= CaptureInfo::Dispatch;
if (Hudfix_Dx12::CheckForHudless(This, &val, val.state))
{
break;
}
}
} while (false);
fgPossibleHudless[fIndex][This].clear();
}
else
{
size_t shardIdx = GetShardIndex(This);
auto& shard = _hudlessShards[fIndex][shardIdx];
if (This == MenuOverlayDx::MenuCommandList() && shard.map.contains(This))
{
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
shard.map[This].clear();
return;
}
@@ -1656,6 +1856,12 @@ void ResTrack_Dx12::hkDispatch(ID3D12GraphicsCommandList* This, UINT ThreadGroup
return;
}
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
auto val0 = shard.map[This];
do
@@ -1844,6 +2050,7 @@ void ResTrack_Dx12::HookDevice(ID3D12Device* device)
if (device == nullptr)
return;
_useShards = Config::Instance()->FGUseShards.value_or_default();
_trackedResources.reserve(1024);
fgHeaps.reserve(65536);
@@ -1984,17 +2191,25 @@ void ResTrack_Dx12::ClearPossibleHudless()
auto hfIndex = Hudfix_Dx12::ActivePresentFrame() % BUFFER_COUNT;
for (size_t i = 0; i < SHARD_COUNT; i++)
if (!_useShards)
{
auto& shard = _hudlessShards[hfIndex][i];
std::lock_guard<std::mutex> lock(_hudlessTrackMutex);
fgPossibleHudless[hfIndex].clear();
}
else
{
for (size_t i = 0; i < SHARD_COUNT; i++)
{
auto& shard = _hudlessShards[hfIndex][i];
#ifdef USE_SPINLOCK_MUTEX
std::lock_guard<SpinLock> lock(shard.mutex);
std::lock_guard<SpinLock> lock(shard.mutex);
#else
std::lock_guard<std::mutex> lock(shard.mutex);
std::lock_guard<std::mutex> lock(shard.mutex);
#endif
shard.map.clear();
shard.map.clear();
}
}
std::lock_guard<std::mutex> lock2(_resourceCommandListMutex);
+3 -7
View File
@@ -36,7 +36,7 @@ static void TestResource(ResourceInfo* info)
#ifdef USE_SPINLOCK_MUTEX
#define USE_PERF_SPINLOCK
// #define USE_PERF_SPINLOCK
#ifdef __cpp_lib_hardware_interference_size
constexpr size_t CACHE_LINE_SIZE = std::hardware_destructive_interference_size;
@@ -337,6 +337,7 @@ class ResTrack_Dx12
private:
inline static bool _presentDone = true;
inline static std::mutex _drawMutex;
inline static bool _useShards = false;
inline static std::mutex _resourceCommandListMutex;
inline static std::unordered_map<FG_ResourceType, ID3D12GraphicsCommandList*> _resourceCommandList[BUFFER_COUNT];
@@ -424,13 +425,8 @@ class ResTrack_Dx12
static void FillResourceInfo(ID3D12Resource* resource, ResourceInfo* info);
// Sharding
#ifdef USE_SPINLOCK_MUTEX
// Sharding
inline static constexpr size_t SHARD_COUNT = 16;
#else
inline static constexpr size_t SHARD_COUNT = 16;
#endif
inline static CommandListShard _hudlessShards[BUFFER_COUNT][SHARD_COUNT];
inline static size_t GetShardIndex(ID3D12GraphicsCommandList* ptr)