From 73701cbbc45b6bdb3e2b6feb66ae9f51f9dcf9cb Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Tue, 18 Feb 2025 07:29:43 -0500 Subject: [PATCH 1/4] Fix unsafe usage of DisableThreadLibraryCalls in a DLL that uses thread_local storage --- src/dllmain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 97b45bc7..f338914c 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -70,7 +70,8 @@ static void Shutdown() BOOL APIENTRY DllMain(HMODULE mod, DWORD ul_reason_for_call, LPVOID) { - DisableThreadLibraryCalls(mod); + // Not safe to do this, the DLL uses thread_local storage + //DisableThreadLibraryCalls(mod); switch (ul_reason_for_call) { From e8a096161a449ca1b4474bc79a10095b16d28b84 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Tue, 18 Feb 2025 07:30:45 -0500 Subject: [PATCH 2/4] Use window class name rather than window title to find game window Handle WM_WINDOWPOSCHANGED correctly for SWP_NOMOVE and SWP_NOSIZE cases --- src/window/window.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/window/window.cpp b/src/window/window.cpp index ef35142e..45113bad 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -14,9 +14,9 @@ static BOOL CALLBACK EnumWindowsProcCP77(HWND ahWnd, LPARAM alParam) GetWindowThreadProcessId(ahWnd, &lpdwProcessId); if (lpdwProcessId == GetCurrentProcessId()) { - TCHAR name[512] = {0}; - GetWindowText(ahWnd, name, 511); - if (_tcscmp(TEXT("Cyberpunk 2077 (C) 2020 by CD Projekt RED"), name) == 0) + wchar_t name[512] = {0}; + RealGetWindowClassW(ahWnd,name,511); + if (wcscmp (L"W2ViewportClass", name) == 0) { *reinterpret_cast(alParam) = ahWnd; return FALSE; @@ -32,8 +32,11 @@ LRESULT APIENTRY Window::WndProc(HWND ahWnd, UINT auMsg, WPARAM awParam, LPARAM if (auMsg == WM_WINDOWPOSCHANGED) { const auto* wp = reinterpret_cast(alParam); - s_pWindow->m_wndPos = {wp->x, wp->y}; - s_pWindow->m_wndSize = {wp->cx, wp->cy}; + + if ((wp->flags & SWP_NOMOVE) == 0) + s_pWindow->m_wndPos = {wp->x, wp->y}; + if ((wp->flags & SWP_NOSIZE) == 0) + s_pWindow->m_wndSize = {wp->cx, wp->cy}; RECT cr; GetClientRect(ahWnd, &cr); From 7745e25eca6a69842127eb06df21abf9c32a7de9 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Tue, 18 Feb 2025 07:31:57 -0500 Subject: [PATCH 3/4] Avoid infinite loop on ShowCursor failure and fallback to software cursor as necessary --- src/d3d12/D3D12.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/d3d12/D3D12.cpp b/src/d3d12/D3D12.cpp index cb8efff8..1e141e9d 100644 --- a/src/d3d12/D3D12.cpp +++ b/src/d3d12/D3D12.cpp @@ -9,17 +9,28 @@ void D3D12::SetTrapInputInImGui(const bool acEnabled) { + // Must have an out-condition to this otherwise infinite loop + static int constexpr maxCursorDepth = 8; + int showCursorTries = 0; int showCursorState; if (acEnabled) do { showCursorState = ShowCursor(TRUE); - } while (showCursorState < 0); + } while (showCursorState < 0 && showCursorTries++ < maxCursorDepth); else do { showCursorState = ShowCursor(FALSE); - } while (showCursorState >= 0); + } while (showCursorState >= 0 && showCursorTries++ < maxCursorDepth); + + // Turn off software cursor + if (showCursorTries < maxCursorDepth || acEnabled == false) + ImGui::GetIO().MouseDrawCursor = false; + + // Enable software cursor as fallback if necessary + else + ImGui::GetIO().MouseDrawCursor = acEnabled; m_trapInputInImGui = acEnabled; } From 816038d03fb0aca261759b6ba1bb2fb5face9487 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Tue, 18 Feb 2025 07:33:28 -0500 Subject: [PATCH 4/4] Correctly isolate command lists and command list allocators to individual frame contexts instead of sharing frame context 0's allocator for all command lists --- src/d3d12/D3D12.h | 2 +- src/d3d12/D3D12_Functions.cpp | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/d3d12/D3D12.h b/src/d3d12/D3D12.h index 87035739..3689f3be 100644 --- a/src/d3d12/D3D12.h +++ b/src/d3d12/D3D12.h @@ -35,6 +35,7 @@ struct D3D12 struct FrameContext { Microsoft::WRL::ComPtr CommandAllocator; + Microsoft::WRL::ComPtr CommandList{}; Microsoft::WRL::ComPtr BackBuffer; D3D12_CPU_DESCRIPTOR_HANDLE MainRenderTargetDescriptor{0}; }; @@ -62,7 +63,6 @@ struct D3D12 Microsoft::WRL::ComPtr m_pd3d12Device{}; Microsoft::WRL::ComPtr m_pd3dRtvDescHeap{}; Microsoft::WRL::ComPtr m_pd3dSrvDescHeap{}; - Microsoft::WRL::ComPtr m_pd3dCommandList{}; // borrowed resources from game, do not manipulate reference counts on these! Microsoft::WRL::ComPtr m_pdxgiSwapChain{nullptr}; diff --git a/src/d3d12/D3D12_Functions.cpp b/src/d3d12/D3D12_Functions.cpp index f48dc2d4..60b5d0fc 100644 --- a/src/d3d12/D3D12_Functions.cpp +++ b/src/d3d12/D3D12_Functions.cpp @@ -35,7 +35,6 @@ bool D3D12::ResetState(const bool acDestroyContext) m_pd3d12Device.Reset(); m_pd3dRtvDescHeap.Reset(); m_pd3dSrvDescHeap.Reset(); - m_pd3dCommandList.Reset(); m_pCommandQueue.Reset(); m_pdxgiSwapChain.Reset(); @@ -113,17 +112,19 @@ bool D3D12::Initialize() } for (auto& context : m_frameContexts) + { if (FAILED(m_pd3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&context.CommandAllocator)))) { Log::Error("D3D12::Initialize() - failed to create command allocator!"); return ResetState(); } - if (FAILED(m_pd3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_frameContexts[0].CommandAllocator.Get(), nullptr, IID_PPV_ARGS(&m_pd3dCommandList))) || - FAILED(m_pd3dCommandList->Close())) - { - Log::Error("D3D12::Initialize() - failed to create command list!"); - return ResetState(); + if (FAILED(m_pd3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, context.CommandAllocator.Get(), nullptr, IID_PPV_ARGS(&context.CommandList))) || + FAILED(context.CommandList->Close())) + { + Log::Error("D3D12::Initialize() - failed to create command list!"); + return ResetState(); + } } if (!InitializeImGui(buffersCounts)) @@ -404,18 +405,18 @@ void D3D12::Update() ID3D12DescriptorHeap* heaps[] = {m_pd3dSrvDescHeap.Get()}; - m_pd3dCommandList->Reset(frameContext.CommandAllocator.Get(), nullptr); - m_pd3dCommandList->ResourceBarrier(1, &barrier); - m_pd3dCommandList->SetDescriptorHeaps(1, heaps); - m_pd3dCommandList->OMSetRenderTargets(1, &frameContext.MainRenderTargetDescriptor, FALSE, nullptr); + frameContext.CommandList->Reset(frameContext.CommandAllocator.Get(), nullptr); + frameContext.CommandList->ResourceBarrier(1, &barrier); + frameContext.CommandList->SetDescriptorHeaps(1, heaps); + frameContext.CommandList->OMSetRenderTargets(1, &frameContext.MainRenderTargetDescriptor, FALSE, nullptr); - ImGui_ImplDX12_RenderDrawData(&m_imguiDrawDataBuffers[0], m_pd3dCommandList.Get()); + ImGui_ImplDX12_RenderDrawData(&m_imguiDrawDataBuffers[0], frameContext.CommandList.Get()); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; - m_pd3dCommandList->ResourceBarrier(1, &barrier); - m_pd3dCommandList->Close(); + frameContext.CommandList->ResourceBarrier(1, &barrier); + frameContext.CommandList->Close(); - ID3D12CommandList* commandLists[] = {m_pd3dCommandList.Get()}; + ID3D12CommandList* commandLists[] = {frameContext.CommandList.Get()}; m_pCommandQueue->ExecuteCommandLists(1, commandLists); }