Added delayed removal of captured resources

This commit is contained in:
cdozdil committed 2026-09-18 22:06:04 +03:00
1 parent 3bae8a59b7
commit 53050eeb4a
2 files changed
+159 -9

No files matched your search

+143 -9
View File
@@ -92,6 +92,140 @@ inline static bool CompareResourceFormats(DXGI_FORMAT sc, DXGI_FORMAT hudless)
return scGroup >= 0 && scGroup == hudlessGroup;
}
void Hudfix_Dx12::RemoveCaptureBuffer(ID3D12Resource** resource)
{
if (resource == nullptr || *resource == nullptr)
return;
auto* removedResource = *resource;
*resource = nullptr;
{
std::lock_guard<std::mutex> lock(_captureRemoveMutex);
_pendingCaptureRemovals.push_back(removedResource);
_captureRemovalActive.store(true, std::memory_order_release);
}
LOG_DEBUG("Capture buffer removed: {:X}", (size_t) removedResource);
}
void Hudfix_Dx12::ProcessPendingCaptureRemovals()
{
if (!_captureRemovalActive.load(std::memory_order_acquire))
return;
std::vector<ID3D12Resource*> completedResources;
std::vector<ID3D12Fence*> completedFences;
{
std::lock_guard<std::mutex> lock(_captureRemoveMutex);
for (auto it = _captureRemoveInfos.begin(); it != _captureRemoveInfos.end();)
{
if (it->fence != nullptr && it->fence->GetCompletedValue() >= it->fenceValue)
{
completedResources.insert(completedResources.end(), it->resources.begin(), it->resources.end());
completedFences.push_back(it->fence);
it = _captureRemoveInfos.erase(it);
}
else
{
++it;
}
}
if (_captureRemoveInfos.empty() && _pendingCaptureRemovals.empty())
_captureRemovalActive.store(false, std::memory_order_release);
}
// Release outside _captureRemoveMutex
for (auto* resource : completedResources)
{
if (resource != nullptr)
resource->Release();
}
for (auto* fence : completedFences)
{
if (fence != nullptr)
fence->Release();
}
if (!_captureRemovalActive.load(std::memory_order_acquire))
return;
if (State::Instance().isShuttingDown)
return;
std::vector<ID3D12Resource*> pendingResources;
{
std::lock_guard<std::mutex> lock(_captureRemoveMutex);
if (_pendingCaptureRemovals.empty())
return;
pendingResources.swap(_pendingCaptureRemovals);
}
auto* fg = State::Instance().currentFG;
ID3D12CommandQueue* queue = fg != nullptr ? fg->GetCommandQueue() : nullptr;
if (queue == nullptr)
queue = State::Instance().currentCommandQueue;
auto requeuePending = [&pendingResources]()
{
std::lock_guard<std::mutex> lock(_captureRemoveMutex);
_pendingCaptureRemovals.insert(_pendingCaptureRemovals.end(), pendingResources.begin(), pendingResources.end());
_captureRemovalActive.store(true, std::memory_order_release);
};
if (queue == nullptr)
{
requeuePending();
return;
}
ID3D12Device* device = nullptr;
auto result = queue->GetDevice(IID_PPV_ARGS(&device));
if (FAILED(result) || device == nullptr)
{
LOG_WARN("Can't get capture remove queue device: {:X}", (UINT) result);
requeuePending();
return;
}
ID3D12Fence* fence = nullptr;
result = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
device->Release();
if (FAILED(result) || fence == nullptr)
{
LOG_WARN("Can't create capture remove fence: {:X}", (UINT) result);
requeuePending();
return;
}
constexpr UINT64 fenceValue = 1;
result = queue->Signal(fence, fenceValue);
if (FAILED(result))
{
LOG_WARN("Can't signal capture remove fence: {:X}", (UINT) result);
fence->Release();
requeuePending();
return;
}
CaptureRemoveInfo batch {};
batch.fence = fence;
batch.fenceValue = fenceValue;
batch.resources = std::move(pendingResources);
{
std::lock_guard<std::mutex> lock(_captureRemoveMutex);
_captureRemoveInfos.push_back(std::move(batch));
_captureRemovalActive.store(true, std::memory_order_release);
}
}
bool Hudfix_Dx12::CreateBufferResource(ID3D12Device* InDevice, ResourceInfo* InSource, D3D12_RESOURCE_STATES InState,
ID3D12Resource** OutResource)
{
@@ -105,11 +239,8 @@ bool Hudfix_Dx12::CreateBufferResource(ID3D12Device* InDevice, ResourceInfo* InS
if (bufDesc.Width != (UINT64) (InSource->width) || bufDesc.Height != (UINT) (InSource->height) ||
bufDesc.Format != InSource->format)
{
// Maybe need to add a fence here
// To be sure it's not used anymore
(*OutResource)->Release();
(*OutResource) = nullptr;
LOG_WARN("Release {}x{}, new one: {}x{}", bufDesc.Width, bufDesc.Height, InSource->width, InSource->height);
RemoveCaptureBuffer(OutResource);
LOG_WARN("Remove {}x{}, new one: {}x{}", bufDesc.Width, bufDesc.Height, InSource->width, InSource->height);
}
else
{
@@ -156,9 +287,8 @@ bool Hudfix_Dx12::CreateBufferResourceWithSize(ID3D12Device* InDevice, ResourceI
if (bufDesc.Width != (UINT64) InWidth || bufDesc.Height != InHeight || bufDesc.Format != InSource->format)
{
(*OutResource)->Release();
(*OutResource) = nullptr;
LOG_WARN("Release {}x{}, new one: {}x{}", bufDesc.Width, bufDesc.Height, InWidth, InHeight);
RemoveCaptureBuffer(OutResource);
LOG_WARN("Remove {}x{}, new one: {}x{}", bufDesc.Width, bufDesc.Height, InWidth, InHeight);
}
else
{
@@ -443,7 +573,11 @@ void Hudfix_Dx12::PresentStart()
_fgCounter.store(_upscaleCounter.load(std::memory_order_acquire), std::memory_order_release);
}
void Hudfix_Dx12::PresentEnd() { LOG_DEBUG(""); }
void Hudfix_Dx12::PresentEnd()
{
ProcessPendingCaptureRemovals();
LOG_DEBUG("");
}
UINT64 Hudfix_Dx12::ActiveUpscaleFrame() { return _upscaleCounter.load(std::memory_order_acquire); }
+16
View File
@@ -9,6 +9,7 @@
#include <atomic>
#include <d3d12.h>
#include <shared_mutex>
#include <vector>
enum ResourceType
{
@@ -78,6 +79,18 @@ class Hudfix_Dx12
// Buffer for Format Transfer
inline static ID3D12Resource* _captureBuffer[BUFFER_COUNT] = { nullptr, nullptr, nullptr, nullptr };
struct CaptureRemoveInfo
{
ID3D12Fence* fence = nullptr;
UINT64 fenceValue = 0;
std::vector<ID3D12Resource*> resources;
};
inline static std::atomic<bool> _captureRemovalActive { false };
inline static std::mutex _captureRemoveMutex;
inline static std::vector<ID3D12Resource*> _pendingCaptureRemovals;
inline static std::vector<CaptureRemoveInfo> _captureRemoveInfos;
// used hudless list
inline static ankerl::unordered_dense::map<ID3D12Resource*, HudlessInfo> _hudlessList;
@@ -93,6 +106,9 @@ class Hudfix_Dx12
inline static std::atomic<bool> _skipHudlessChecks { false };
static void RemoveCaptureBuffer(ID3D12Resource** resource);
static void ProcessPendingCaptureRemovals();
static bool CreateBufferResource(ID3D12Device* InDevice, ResourceInfo* InSource, D3D12_RESOURCE_STATES InState,
ID3D12Resource** OutResource);
static bool CreateBufferResourceWithSize(ID3D12Device* InDevice, ResourceInfo* InSource,