diff --git a/OptiScaler/NVNGX_DLSS_Dx11.cpp b/OptiScaler/NVNGX_DLSS_Dx11.cpp index a8fdcf35..c9fde2b4 100644 --- a/OptiScaler/NVNGX_DLSS_Dx11.cpp +++ b/OptiScaler/NVNGX_DLSS_Dx11.cpp @@ -18,7 +18,7 @@ #include -#include "imgui/imgui_overlay_dx.h" +#include "hooks/HooksDx.h" inline ID3D11Device* D3D11Device = nullptr; @@ -95,11 +95,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_Init_Ext(unsigned long long InApp D3D11_QUERY_DESC timestampQueryDesc = {}; timestampQueryDesc.Query = D3D11_QUERY_TIMESTAMP; - for (int i = 0; i < ImGuiOverlayDx::QUERY_BUFFER_COUNT; i++) + for (int i = 0; i < HooksDx::QUERY_BUFFER_COUNT; i++) { - InDevice->CreateQuery(&disjointQueryDesc, &ImGuiOverlayDx::disjointQueries[i]); - InDevice->CreateQuery(×tampQueryDesc, &ImGuiOverlayDx::startQueries[i]); - InDevice->CreateQuery(×tampQueryDesc, &ImGuiOverlayDx::endQueries[i]); + InDevice->CreateQuery(&disjointQueryDesc, &HooksDx::disjointQueries[i]); + InDevice->CreateQuery(×tampQueryDesc, &HooksDx::startQueries[i]); + InDevice->CreateQuery(×tampQueryDesc, &HooksDx::endQueries[i]); } return NVSDK_NGX_Result_Success; @@ -213,7 +213,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_Shutdown() // Unhooking and cleaning stuff causing issues during shutdown. // Disabled for now to check if it cause any issues - //ImGuiOverlayDx::UnHookDx(); + //HooksDx::UnHookDx(); shutdown = false; @@ -836,12 +836,12 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_EvaluateFeature(ID3D11DeviceConte } // In the render loop: - ImGuiOverlayDx::previousFrameIndex = (ImGuiOverlayDx::currentFrameIndex + ImGuiOverlayDx::QUERY_BUFFER_COUNT - 2) % ImGuiOverlayDx::QUERY_BUFFER_COUNT; - int nextFrameIndex = ImGuiOverlayDx::currentFrameIndex; + HooksDx::previousFrameIndex = (HooksDx::currentFrameIndex + HooksDx::QUERY_BUFFER_COUNT - 2) % HooksDx::QUERY_BUFFER_COUNT; + int nextFrameIndex = HooksDx::currentFrameIndex; // Record the queries in the current frame - InDevCtx->Begin(ImGuiOverlayDx::disjointQueries[nextFrameIndex]); - InDevCtx->End(ImGuiOverlayDx::startQueries[nextFrameIndex]); + InDevCtx->Begin(HooksDx::disjointQueries[nextFrameIndex]); + InDevCtx->End(HooksDx::startQueries[nextFrameIndex]); if (!deviceContext->Evaluate(InDevCtx, InParameters) && !deviceContext->IsInited() && (deviceContext->Name() == "XeSS" || deviceContext->Name() == "DLSS" || deviceContext->Name() == "FSR3 w/Dx12")) { @@ -849,10 +849,10 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_EvaluateFeature(ID3D11DeviceConte Config::Instance()->changeBackend = true; } - InDevCtx->End(ImGuiOverlayDx::endQueries[nextFrameIndex]); - InDevCtx->End(ImGuiOverlayDx::disjointQueries[nextFrameIndex]); + InDevCtx->End(HooksDx::endQueries[nextFrameIndex]); + InDevCtx->End(HooksDx::disjointQueries[nextFrameIndex]); - ImGuiOverlayDx::dx11UpscaleTrig[nextFrameIndex] = true; + HooksDx::dx11UpscaleTrig[nextFrameIndex] = true; return NVSDK_NGX_Result_Success; } diff --git a/OptiScaler/NVNGX_DLSS_Dx12.cpp b/OptiScaler/NVNGX_DLSS_Dx12.cpp index 6bb17928..afe03258 100644 --- a/OptiScaler/NVNGX_DLSS_Dx12.cpp +++ b/OptiScaler/NVNGX_DLSS_Dx12.cpp @@ -12,7 +12,7 @@ #include "backends/fsr31/FSR31Feature_Dx12.h" #include "backends/xess/XeSSFeature_Dx12.h" -#include "imgui/imgui_overlay_dx.h" +#include "hooks/HooksDx.h" #include "detours/detours.h" #include @@ -390,13 +390,13 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Init_Ext(unsigned long long InApp queryHeapDesc.Count = 2; // Start and End timestamps queryHeapDesc.NodeMask = 0; queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; - auto result = InDevice->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&ImGuiOverlayDx::queryHeap)); + auto result = InDevice->CreateQueryHeap(&queryHeapDesc, IID_PPV_ARGS(&HooksDx::queryHeap)); // Create a readback buffer to retrieve timestamp data D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(2 * sizeof(UINT64)); D3D12_HEAP_PROPERTIES heapProps = {}; heapProps.Type = D3D12_HEAP_TYPE_READBACK; - result = InDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&ImGuiOverlayDx::readbackBuffer)); + result = InDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&HooksDx::readbackBuffer)); if (_createContext == nullptr) LoadFSR31Funcs(); @@ -523,9 +523,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Shutdown(void) // Unhooking and cleaning stuff causing issues during shutdown. // Disabled for now to check if it cause any issues - //ImGuiOverlayDx::UnHookDx(); + //HooksDx::UnHookDx(); - ImGuiOverlayDx::StopAndDestroyFGContext(true, true); + HooksDx::StopAndDestroyFGContext(true, true); shutdown = false; @@ -856,7 +856,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_CreateFeature(ID3D12GraphicsComma HookToCommandList(InCmdList); evalCounter = 0; - ImGuiOverlayDx::fgTarget = 10; + HooksDx::fgTarget = 10; return NVSDK_NGX_Result_Success; } @@ -878,7 +878,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_ReleaseFeature(NVSDK_NGX_Handle* auto handleId = InHandle->Id; Config::Instance()->FGChanged = true; - ImGuiOverlayDx::StopAndDestroyFGContext(true, false); + HooksDx::StopAndDestroyFGContext(true, false); if (!shutdown) LOG_INFO("releasing feature with id {0}", handleId); @@ -1082,9 +1082,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom // first release everything if (changeBackendCounter == 1) { - if (ImGuiOverlayDx::fgContext != nullptr) + if (HooksDx::fgContext != nullptr) { - ImGuiOverlayDx::StopAndDestroyFGContext(false, false); + HooksDx::StopAndDestroyFGContext(false, false); } if (Dx12Contexts.contains(handleId)) @@ -1254,7 +1254,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom // if initial feature can't be inited Config::Instance()->CurrentFeature = Dx12Contexts[handleId].get(); - ImGuiOverlayDx::fgTarget = 10; + HooksDx::fgTarget = 10; return NVSDK_NGX_Result_Success; } @@ -1297,22 +1297,22 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom // FG Init || Disable if (Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true)) { - if (!Config::Instance()->FGChanged && ImGuiOverlayDx::fgTarget < deviceContext->FrameCount() && Config::Instance()->FGEnabled.value_or(false) && - _createContext != nullptr && !ImGuiOverlayDx::fgIsActive && ImGuiOverlayDx::currentSwapchain != nullptr && - ImGuiOverlayDx::swapchainFormat != DXGI_FORMAT_UNKNOWN) + if (!Config::Instance()->FGChanged && HooksDx::fgTarget < deviceContext->FrameCount() && Config::Instance()->FGEnabled.value_or(false) && + _createContext != nullptr && !HooksDx::fgIsActive && HooksDx::currentSwapchain != nullptr && + HooksDx::swapchainFormat != DXGI_FORMAT_UNKNOWN) { - ImGuiOverlayDx::CreateFGObjects(D3D12Device); - ImGuiOverlayDx::CreateFGContext(D3D12Device, deviceContext); + HooksDx::CreateFGObjects(D3D12Device); + HooksDx::CreateFGContext(D3D12Device, deviceContext); } - else if ((!Config::Instance()->FGEnabled.value_or(false) || Config::Instance()->FGChanged) && ImGuiOverlayDx::fgIsActive) + else if ((!Config::Instance()->FGEnabled.value_or(false) || Config::Instance()->FGChanged) && HooksDx::fgIsActive) { - ImGuiOverlayDx::StopAndDestroyFGContext(Config::Instance()->SCChanged, false); + HooksDx::StopAndDestroyFGContext(Config::Instance()->SCChanged, false); } if (Config::Instance()->FGChanged) { LOG_DEBUG(" FG disabled for 10 frames"); - ImGuiOverlayDx::fgTarget = deviceContext->FrameCount() + 20; + HooksDx::fgTarget = deviceContext->FrameCount() + 20; Config::Instance()->FGChanged = false; } } @@ -1320,17 +1320,17 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom Config::Instance()->SCChanged = false; // Record the first timestamp (before FSR2 upscaling) - InCmdList->EndQuery(ImGuiOverlayDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0); + InCmdList->EndQuery(HooksDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0); bool evalResult = deviceContext->Evaluate(InCmdList, InParameters); // Record the second timestamp (after FSR2 upscaling) - InCmdList->EndQuery(ImGuiOverlayDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 1); + InCmdList->EndQuery(HooksDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 1); // Resolve the queries to the readback buffer - InCmdList->ResolveQueryData(ImGuiOverlayDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, 2, ImGuiOverlayDx::readbackBuffer, 0); + InCmdList->ResolveQueryData(HooksDx::queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, 2, HooksDx::readbackBuffer, 0); - ImGuiOverlayDx::dx12UpscaleTrig = true; + HooksDx::dx12UpscaleTrig = true; if (deviceContext->Name() != "DLSSD" && (Config::Instance()->RestoreComputeSignature.value_or(false) || Config::Instance()->RestoreGraphicSignature.value_or(false))) { @@ -1380,9 +1380,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom if (evalResult) { // FG Dispatch || Prepare - if (ImGuiOverlayDx::fgIsActive && Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true) && - Config::Instance()->FGEnabled.value_or(false) && ImGuiOverlayDx::fgTarget < deviceContext->FrameCount() && - ImGuiOverlayDx::fgContext != nullptr && ImGuiOverlayDx::currentSwapchain != nullptr) + if (HooksDx::fgIsActive && Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true) && + Config::Instance()->FGEnabled.value_or(false) && HooksDx::fgTarget < deviceContext->FrameCount() && + HooksDx::fgContext != nullptr && HooksDx::currentSwapchain != nullptr) { float msDelta = 0.0; auto now = Util::MillisecondsNow(); @@ -1398,15 +1398,15 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom ID3D12Resource* output; InParameters->Get(NVSDK_NGX_Parameter_Output, &output); - auto frameIndex = ImGuiOverlayDx::ClearFrameResources(); - ImGuiOverlayDx::NewFrame(); - ImGuiOverlayDx::fgUpscaledImage[frameIndex] = output; + auto frameIndex = HooksDx::ClearFrameResources(); + HooksDx::NewFrame(); + HooksDx::fgUpscaledImage[frameIndex] = output; - auto allocator = ImGuiOverlayDx::fgCopyCommandAllocators[frameIndex]; + auto allocator = HooksDx::fgCopyCommandAllocators[frameIndex]; auto result = allocator->Reset(); - result = ImGuiOverlayDx::fgCopyCommandList->Reset(allocator, nullptr); + result = HooksDx::fgCopyCommandList->Reset(allocator, nullptr); - if (!Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgTarget > deviceContext->FrameCount()) + if (!Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgTarget > deviceContext->FrameCount()) { LOG_DEBUG("FG running, frame: {0}", deviceContext->FrameCount()); @@ -1415,9 +1415,9 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; - if (desc.Format == ImGuiOverlayDx::swapchainFormat) + if (desc.Format == HooksDx::swapchainFormat) { - LOG_DEBUG("FG desc.Format == ImGuiOverlayDx::swapchainFormat, using hudless!"); + LOG_DEBUG("FG desc.Format == HooksDx::swapchainFormat, using hudless!"); m_FrameGenerationConfig.HUDLessColor = ffxApiGetResourceDX12(output, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS, 0); } else @@ -1443,26 +1443,30 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom m_FrameGenerationConfig.frameGenerationCallback = [](ffxDispatchDescFrameGeneration* params, void* pUserCtx) -> ffxReturnCode_t { #ifdef USE_COPY_QUEUE_FOR_FG - auto fIndex = ImGuiOverlayDx::GetFrame(); + auto fIndex = HooksDx::GetFrame(); // check for status if (!Config::Instance()->FGEnabled.value_or(false) || Config::Instance()->FGChanged || - ImGuiOverlayDx::fgContext == nullptr || ImGuiOverlayDx::fgCopyCommandList == nullptr || - ImGuiOverlayDx::fgCopyCommandQueue == nullptr || !ImGuiOverlayDx::fgIsActive) + HooksDx::fgContext == nullptr || HooksDx::fgCopyCommandList == nullptr || + HooksDx::fgCopyCommandQueue == nullptr) { LOG_WARN("Cancel async dispatch"); - ImGuiOverlayDx::fgSkipHudlessChecks = false; + HooksDx::fgSkipHudlessChecks = false; return FFX_API_RETURN_OK; } // If fg is active but upscaling paused - if (Config::Instance()->CurrentFeature == nullptr || fgLastFGFrame == Config::Instance()->CurrentFeature->FrameCount()) + if (Config::Instance()->CurrentFeature == nullptr || !HooksDx::fgIsActive || + fgLastFGFrame == Config::Instance()->CurrentFeature->FrameCount()) { LOG_WARN("Callback without hudless!"); - auto allocator = ImGuiOverlayDx::fgCopyCommandAllocators[fIndex]; + auto allocator = HooksDx::fgCopyCommandAllocators[fIndex]; auto result = allocator->Reset(); - result = ImGuiOverlayDx::fgCopyCommandList->Reset(allocator, nullptr); + result = HooksDx::fgCopyCommandList->Reset(allocator, nullptr); + + params->frameID = fgLastFGFrame; + params->numGeneratedFrames = 0; } if (Config::Instance()->CurrentFeature != nullptr) @@ -1471,13 +1475,13 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom auto result = _dispatch(reinterpret_cast(pUserCtx), ¶ms->header); ID3D12CommandList* cl[1] = { nullptr }; - result = ImGuiOverlayDx::fgCopyCommandList->Close(); - cl[0] = ImGuiOverlayDx::fgCopyCommandList; - ImGuiOverlayDx::gameCommandQueue->ExecuteCommandLists(1, cl); + result = HooksDx::fgCopyCommandList->Close(); + cl[0] = HooksDx::fgCopyCommandList; + HooksDx::gameCommandQueue->ExecuteCommandLists(1, cl); return result; #else - if (!Config::Instance()->FGEnabled.value_or(false) || Config::Instance()->FGChanged || Config::Instance()->CurrentFeature == nullptr || ImGuiOverlayDx::fgContext == nullptr) + if (!Config::Instance()->FGEnabled.value_or(false) || Config::Instance()->FGChanged || Config::Instance()->CurrentFeature == nullptr || HooksDx::fgContext == nullptr) return FFX_API_RETURN_OK; auto result = _dispatch(reinterpret_cast(pUserCtx), ¶ms->header); @@ -1485,10 +1489,10 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom #endif }; - m_FrameGenerationConfig.frameGenerationCallbackUserContext = &ImGuiOverlayDx::fgContext; + m_FrameGenerationConfig.frameGenerationCallbackUserContext = &HooksDx::fgContext; m_FrameGenerationConfig.onlyPresentGenerated = Config::Instance()->FGOnlyGenerated; // check here m_FrameGenerationConfig.frameID = deviceContext->FrameCount(); - m_FrameGenerationConfig.swapChain = ImGuiOverlayDx::currentSwapchain; + m_FrameGenerationConfig.swapChain = HooksDx::currentSwapchain; ffxConfigureDescGlobalDebug1 debugDesc; debugDesc.header.type = FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1; @@ -1497,7 +1501,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom m_FrameGenerationConfig.header.pNext = &debugDesc.header; Config::Instance()->dxgiSkipSpoofing = true; - ffxReturnCode_t retCode = _configure(&ImGuiOverlayDx::fgContext, &m_FrameGenerationConfig.header); + ffxReturnCode_t retCode = _configure(&HooksDx::fgContext, &m_FrameGenerationConfig.header); Config::Instance()->dxgiSkipSpoofing = false; LOG_DEBUG(" FG _configure result: {0:X}", retCode); @@ -1512,7 +1516,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom dfgPrepare.header.pNext = &backendDesc.header; #ifdef USE_COPY_QUEUE_FOR_FG - dfgPrepare.commandList = ImGuiOverlayDx::fgCopyCommandList; + dfgPrepare.commandList = HooksDx::fgCopyCommandList; #else dfgPrepare.commandList = InCmdList; #endif @@ -1528,15 +1532,15 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom if (InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, ¶mVelocity) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, (void**)¶mVelocity); - if (CreateBufferResource(L"fgVelocity", D3D12Device, paramVelocity, D3D12_RESOURCE_STATE_COPY_DEST, &ImGuiOverlayDx::paramVelocity[frameIndex])) - InCmdList->CopyResource(ImGuiOverlayDx::paramVelocity[frameIndex], paramVelocity); + if (CreateBufferResource(L"fgVelocity", D3D12Device, paramVelocity, D3D12_RESOURCE_STATE_COPY_DEST, &HooksDx::paramVelocity[frameIndex])) + InCmdList->CopyResource(HooksDx::paramVelocity[frameIndex], paramVelocity); ID3D12Resource* paramDepth; if (InParameters->Get(NVSDK_NGX_Parameter_Depth, ¶mDepth) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_Depth, (void**)¶mDepth); - if (CreateBufferResource(L"fgDepth", D3D12Device, paramDepth, D3D12_RESOURCE_STATE_COPY_DEST, &ImGuiOverlayDx::paramDepth[frameIndex])) - InCmdList->CopyResource(ImGuiOverlayDx::paramDepth[frameIndex], paramDepth); + if (CreateBufferResource(L"fgDepth", D3D12Device, paramDepth, D3D12_RESOURCE_STATE_COPY_DEST, &HooksDx::paramDepth[frameIndex])) + InCmdList->CopyResource(HooksDx::paramDepth[frameIndex], paramDepth); #else ID3D12Resource* paramVelocity; if (InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, ¶mVelocity) != NVSDK_NGX_Result_Success) @@ -1551,8 +1555,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom dfgPrepare.depth = ffxApiGetResourceDX12(paramDepth, FFX_API_RESOURCE_STATE_COMPUTE_READ); #endif - dfgPrepare.motionVectors = ffxApiGetResourceDX12(ImGuiOverlayDx::paramVelocity[frameIndex], FFX_API_RESOURCE_STATE_COMPUTE_READ); - dfgPrepare.depth = ffxApiGetResourceDX12(ImGuiOverlayDx::paramDepth[frameIndex], FFX_API_RESOURCE_STATE_COMPUTE_READ); + dfgPrepare.motionVectors = ffxApiGetResourceDX12(HooksDx::paramVelocity[frameIndex], FFX_API_RESOURCE_STATE_COMPUTE_READ); + dfgPrepare.depth = ffxApiGetResourceDX12(HooksDx::paramDepth[frameIndex], FFX_API_RESOURCE_STATE_COMPUTE_READ); float MVScaleX = 1.0f; float MVScaleY = 1.0f; @@ -1587,39 +1591,39 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom dfgPrepare.frameTimeDelta = msDelta; Config::Instance()->dxgiSkipSpoofing = true; - retCode = _dispatch(&ImGuiOverlayDx::fgContext, &dfgPrepare.header); + retCode = _dispatch(&HooksDx::fgContext, &dfgPrepare.header); Config::Instance()->dxgiSkipSpoofing = false; LOG_DEBUG(" FG _dispatch result: {0}", retCode); } } else { - ImGuiOverlayDx::upscaleRan = true; + HooksDx::upscaleRan = true; LOG_DEBUG("Set fgUpscaledImage[{}]", frameIndex); LOG_DEBUG("HUDFix copy buffers running, frame: {0}", deviceContext->FrameCount()); - InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_X, &ImGuiOverlayDx::jitterX); - InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_Y, &ImGuiOverlayDx::jitterY); + InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_X, &HooksDx::jitterX); + InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_Y, &HooksDx::jitterY); ID3D12Resource* paramVelocity; if (InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, ¶mVelocity) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, (void**)¶mVelocity); - if (CreateBufferResource(L"fgVelocity", D3D12Device, paramVelocity, D3D12_RESOURCE_STATE_COPY_DEST, &ImGuiOverlayDx::paramVelocity[frameIndex])) - InCmdList->CopyResource(ImGuiOverlayDx::paramVelocity[frameIndex], paramVelocity); + if (CreateBufferResource(L"fgVelocity", D3D12Device, paramVelocity, D3D12_RESOURCE_STATE_COPY_DEST, &HooksDx::paramVelocity[frameIndex])) + InCmdList->CopyResource(HooksDx::paramVelocity[frameIndex], paramVelocity); ID3D12Resource* paramDepth; if (InParameters->Get(NVSDK_NGX_Parameter_Depth, ¶mDepth) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_Depth, (void**)¶mDepth); - if (CreateBufferResource(L"fgDepth", D3D12Device, paramDepth, D3D12_RESOURCE_STATE_COPY_DEST, &ImGuiOverlayDx::paramDepth[frameIndex])) - InCmdList->CopyResource(ImGuiOverlayDx::paramDepth[frameIndex], paramDepth); + if (CreateBufferResource(L"fgDepth", D3D12Device, paramDepth, D3D12_RESOURCE_STATE_COPY_DEST, &HooksDx::paramDepth[frameIndex])) + InCmdList->CopyResource(HooksDx::paramDepth[frameIndex], paramDepth); - InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_X, &ImGuiOverlayDx::mvScaleX); - InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_Y, &ImGuiOverlayDx::mvScaleY); + InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_X, &HooksDx::mvScaleX); + InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_Y, &HooksDx::mvScaleY); - ImGuiOverlayDx::fgFrameTime = msDelta; + HooksDx::fgFrameTime = msDelta; LOG_DEBUG("HUDFix copy buffers done, frame: {0}", deviceContext->FrameCount()); } diff --git a/OptiScaler/NVNGX_DLSS_Vk.cpp b/OptiScaler/NVNGX_DLSS_Vk.cpp index 825c1e2a..d440d70b 100644 --- a/OptiScaler/NVNGX_DLSS_Vk.cpp +++ b/OptiScaler/NVNGX_DLSS_Vk.cpp @@ -13,7 +13,7 @@ #include "backends/fsr2_212/FSR2Feature_Vk_212.h" #include "backends/fsr31/FSR31Feature_Vk.h" -#include "imgui/imgui_overlay_vk.h" +#include "hooks/HooksVk.h" #include "NVNGX_Parameter.h" #include "NVNGX_Proxy.h" @@ -164,11 +164,11 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_Init_Ext2(unsigned long long InA queryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; queryPoolInfo.queryCount = 2; // Start and End timestamps - vkCreateQueryPool(InDevice, &queryPoolInfo, nullptr, &ImGuiOverlayVk::queryPool); + vkCreateQueryPool(InDevice, &queryPoolInfo, nullptr, &HooksVk::queryPool); VkPhysicalDeviceProperties deviceProperties; vkGetPhysicalDeviceProperties(InPD, &deviceProperties); - ImGuiOverlayVk::timeStampPeriod = deviceProperties.limits.timestampPeriod; + HooksVk::timeStampPeriod = deviceProperties.limits.timestampPeriod; return NVSDK_NGX_Result_Success; } @@ -961,13 +961,13 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_EvaluateFeature(VkCommandBuffer Config::Instance()->RenderMenu = true; // Record the first timestamp (before FSR2) - vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, ImGuiOverlayVk::queryPool, 0); + vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, HooksVk::queryPool, 0); auto upscaleResult = deviceContext->Evaluate(InCmdBuffer, InParameters); // Record the second timestamp (after FSR2) - vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ImGuiOverlayVk::queryPool, 1); - ImGuiOverlayVk::vkUpscaleTrig = true; + vkCmdWriteTimestamp(InCmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, HooksVk::queryPool, 1); + HooksVk::vkUpscaleTrig = true; return upscaleResult ? NVSDK_NGX_Result_Success : NVSDK_NGX_Result_Fail; } diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index e9d86c43..aca8b0f7 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -81,8 +81,8 @@ $(SolutionDir)external\vulkan\include;$(SolutionDir)external\nvngx_dlss_sdk;$(SolutionDir)external\xess\inc\xess;$(SolutionDir)external\FidelityFX-SDK\ffx-api\include\ffx_api;$(SolutionDir)external\simpleini;$(SolutionDir)external\unordered_dense\include;$(SolutionDir)external\spdlog\include;$(IncludePath) $(ProjectDir)fsr2\lib;$(ProjectDir)fsr2_212\lib;$(ProjectDir)fsr31\lib;$(ProjectDir)vulkan;$(ProjectDir)d3dx;$(ProjectDir)detours;$(SolutionDir)external\xess\lib;$(LibraryPath) - dxgi - D:\Folders\Games\Kena - Bridge of Spirits\Kena\Binaries\Win64\ + version + D:\Folders\Games\No Man%27s Sky\Binaries\ .\x64\Debug @@ -208,6 +208,8 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ + + @@ -248,7 +250,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - + @@ -295,6 +297,8 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ + + @@ -311,7 +315,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ - + diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index a97c8a34..5e06ef75 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -7,8 +7,8 @@ #include "NVNGX_Proxy.h" #include "XeSS_Proxy.h" -#include "imgui/imgui_overlay_dx.h" -#include "imgui/imgui_overlay_vk.h" +#include "hooks/HooksDx.h" +#include "hooks/HooksVk.h" #include @@ -959,8 +959,8 @@ static void DetachHooks() { if (!isNvngxMode) { - ImGuiOverlayDx::UnHookDx(); - ImGuiOverlayVk::UnHookVk(); + HooksDx::UnHookDx(); + HooksVk::UnHookVk(); } if (o_LoadLibraryA != nullptr || o_LoadLibraryW != nullptr || o_LoadLibraryExA != nullptr || o_LoadLibraryExW != nullptr) @@ -1578,8 +1578,8 @@ static void CheckWorkingMode() Config::Instance()->OverlayMenu = (!isNvngxMode || isWorkingWithEnabler) && Config::Instance()->OverlayMenu.value_or(true); if (Config::Instance()->OverlayMenu.value()) { - ImGuiOverlayDx::HookDx(); - ImGuiOverlayVk::HookVk(); + HooksDx::HookDx(); + HooksVk::HookVk(); } return; diff --git a/OptiScaler/hooks/HooksDx.cpp b/OptiScaler/hooks/HooksDx.cpp new file mode 100644 index 00000000..83b0caed --- /dev/null +++ b/OptiScaler/hooks/HooksDx.cpp @@ -0,0 +1,2861 @@ +#include "HooksDx.h" + +#include "../Util.h" +#include "../Logger.h" +#include "../Config.h" + +#include "../imgui/imgui_overlay_dx.h" + +#include "../detours/detours.h" +#include + +#include "wrapped_swapchain.h" + +#pragma region FG definitions + +#include +#include + +// #define USE_RESOURCE_DISCARD +// #define USE_COPY_RESOURCE +#define USE_RESOURCE_BARRIRER + +enum ResourceType +{ + SRV, + RTV, + UAV +}; + +typedef struct SwapChainInfo +{ + IDXGISwapChain* swapChain = nullptr; + DXGI_FORMAT swapChainFormat = DXGI_FORMAT_UNKNOWN; + int swapChainBufferCount = 0; + ID3D12CommandQueue* fgCommandQueue = nullptr; + ID3D12CommandQueue* gameCommandQueue = nullptr; +}; + +typedef struct ResourceInfo +{ + ID3D12Resource* buffer = nullptr; + UINT64 width = 0; + UINT height = 0; + DXGI_FORMAT format; + D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON; + ResourceType type = SRV; +} resource_info; + +typedef struct HeapInfo +{ + SIZE_T cpuStart = NULL; + SIZE_T cpuEnd = NULL; + SIZE_T gpuStart = NULL; + SIZE_T gpuEnd = NULL; + UINT numDescriptors = 0; + UINT increment = 0; + UINT type = 0; + std::shared_ptr info; + + HeapInfo(SIZE_T cpuStart, SIZE_T cpuEnd, SIZE_T gpuStart, SIZE_T gpuEnd, UINT numResources, UINT increment, UINT type) + : cpuStart(cpuStart), cpuEnd(cpuEnd), gpuStart(gpuStart), gpuEnd(gpuEnd), numDescriptors(numResources), increment(increment), info(new ResourceInfo[numResources]), type(type) {} + + ResourceInfo* GetByCpuHandle(SIZE_T cpuHandle) + { + if (cpuStart > cpuHandle || cpuEnd < cpuHandle) + return nullptr; + + auto index = (cpuHandle - cpuStart) / increment; + + return &info[index]; + } + + ResourceInfo* GetByGpuHandle(SIZE_T gpuHandle) + { + if (gpuStart > gpuHandle || gpuEnd < gpuHandle) + return nullptr; + + auto index = (gpuHandle - gpuStart) / increment; + + return &info[index]; + } + + void SetByCpuHandle(SIZE_T cpuHandle, ResourceInfo setInfo) + { + if (cpuStart > cpuHandle || cpuEnd < cpuHandle) + return; + + auto index = (cpuHandle - cpuStart) / increment; + + info[index] = setInfo; + } + + void SetByGpuHandle(SIZE_T gpuHandle, ResourceInfo setInfo) + { + if (gpuStart > gpuHandle || gpuEnd < gpuHandle) + return; + + auto index = (gpuHandle - gpuStart) / increment; + + info[index] = setInfo; + } +} heap_info; + +typedef struct ResourceHeapInfo +{ + SIZE_T cpuStart = NULL; + SIZE_T gpuStart = NULL; +} resource_heap_info; + +// Device hooks for FG +typedef void(*PFN_CreateRenderTargetView)(ID3D12Device* This, ID3D12Resource* pResource, const D3D12_RENDER_TARGET_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +typedef void(*PFN_CreateShaderResourceView)(ID3D12Device* This, ID3D12Resource* pResource, D3D12_SHADER_RESOURCE_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +typedef void(*PFN_CreateUnorderedAccessView)(ID3D12Device* This, ID3D12Resource* pResource, ID3D12Resource* pCounterResource, D3D12_UNORDERED_ACCESS_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +typedef HRESULT(*PFN_CreateDescriptorHeap)(ID3D12Device* This, D3D12_DESCRIPTOR_HEAP_DESC* pDescriptorHeapDesc, REFIID riid, void** ppvHeap); +typedef void(*PFN_CopyDescriptors)(ID3D12Device* This, UINT NumDestDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pDestDescriptorRangeStarts, UINT* pDestDescriptorRangeSizes, UINT NumSrcDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pSrcDescriptorRangeStarts, UINT* pSrcDescriptorRangeSizes, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType); +typedef void(*PFN_CopyDescriptorsSimple)(ID3D12Device* This, UINT NumDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart, D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType); + +// Command list hooks for FG +typedef void(*PFN_OMSetRenderTargets)(ID3D12GraphicsCommandList* This, UINT NumRenderTargetDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, BOOL RTsSingleHandleToDescriptorRange, D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor); +typedef void(*PFN_DrawIndexedInstanced)(ID3D12GraphicsCommandList* This, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation); +typedef void(*PFN_DrawInstanced)(ID3D12GraphicsCommandList* This, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation); +typedef void(*PFN_CopyResource)(ID3D12GraphicsCommandList* This, ID3D12Resource* pDstResource, ID3D12Resource* pSrcResource); +typedef void(*PFN_CopyTextureRegion)(ID3D12GraphicsCommandList* This, D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, UINT DstY, UINT DstZ, D3D12_TEXTURE_COPY_LOCATION* pSrc, D3D12_BOX* pSrcBox); +typedef void(*PFN_SetGraphicsRootDescriptorTable)(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); +typedef void(*PFN_SetComputeRootDescriptorTable)(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); +typedef void(*PFN_Dispatch)(ID3D12GraphicsCommandList* This, UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ); +typedef void(*PFN_DiscardResource)(ID3D12GraphicsCommandList* This, ID3D12Resource* pResource, D3D12_DISCARD_REGION* pRegion); + +// Original method calls for device +static PFN_CreateRenderTargetView o_CreateRenderTargetView = nullptr; +static PFN_CreateShaderResourceView o_CreateShaderResourceView = nullptr; +static PFN_CreateUnorderedAccessView o_CreateUnorderedAccessView = nullptr; +static PFN_CreateDescriptorHeap o_CreateDescriptorHeap = nullptr; +static PFN_CopyDescriptors o_CopyDescriptors = nullptr; +static PFN_CopyDescriptorsSimple o_CopyDescriptorsSimple = nullptr; + +// Original method calls for command list +static PFN_OMSetRenderTargets o_OMSetRenderTargets = nullptr; +static PFN_DrawInstanced o_DrawInstanced = nullptr; +static PFN_DrawIndexedInstanced o_DrawIndexedInstanced = nullptr; +#ifdef USE_COPY_RESOURCE +static PFN_CopyResource o_CopyResource = nullptr; +#endif +static PFN_CopyTextureRegion o_CopyTextureRegion = nullptr; +static PFN_SetGraphicsRootDescriptorTable o_SetGraphicsRootDescriptorTable = nullptr; +static PFN_SetComputeRootDescriptorTable o_SetComputeRootDescriptorTable = nullptr; +static PFN_Dispatch o_Dispatch = nullptr; +#ifdef USE_RESOURCE_DISCARD +static PFN_DiscardResource o_DiscardResource = nullptr; +#endif + +// FSR 3.x methods +static PfnFfxCreateContext _createContext = nullptr; +static PfnFfxDestroyContext _destroyContext = nullptr; +static PfnFfxConfigure _configure = nullptr; +static PfnFfxQuery _query = nullptr; +static PfnFfxDispatch _dispatch = nullptr; + +// swapchains variables +static ankerl::unordered_dense::map fgSwapChains; +static bool fgSkipSCWrapping = false; +static DXGI_SWAP_CHAIN_DESC fgScDesc{}; + +// queues +static std::vector fgQueues; + +// heaps +static std::vector fgHeaps; + +#ifdef USE_RESOURCE_DISCARD +// created resources +static ankerl::unordered_dense::map fgHandlesByResources; +#endif + +// possibleHudless lisy by cmdlist +static ankerl::unordered_dense::map > fgPossibleHudless[HooksDx::FG_BUFFER_SIZE]; + +// mutexes +static std::shared_mutex heapMutex; +static std::shared_mutex resourceMutex; +static std::shared_mutex hudlessMutex[HooksDx::FG_BUFFER_SIZE]; +static std::shared_mutex counterMutex[HooksDx::FG_BUFFER_SIZE]; + +// found hudless info +static ID3D12Resource* fgCopySource[HooksDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; +static ID3D12Resource* fgHudless[HooksDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; +static ID3D12Resource* fgHudlessBuffer[HooksDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; + +static UINT fgFrameIndex = 0; + +// Last captured upscaled hudless frame number +static UINT64 fgHudlessFrame = 0; +static UINT64 fgPresentedFrame = 0; +static bool fgPresentRunning = false; + +// Used for frametime calculation +static double fgLastFrameTime = 0.0; +static double fgLastDeltaTime = 0.0; +static bool fgDispatchCalled = false; +static bool fgStopAfterNextPresent = false; + +// Swapchain frame counter +static UINT64 frameCounter = 0; + +// Swapchain frame target while capturing RTVs etc +static UINT64 fgLastFGFrame = 0; +static bool fgUpscaledFound = false; + +#pragma endregion + +// dxgi stuff +typedef HRESULT(*PFN_CreateDXGIFactory)(REFIID riid, IDXGIFactory** ppFactory); +typedef HRESULT(*PFN_CreateDXGIFactory1)(REFIID riid, IDXGIFactory1** ppFactory); +typedef HRESULT(*PFN_CreateDXGIFactory2)(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory); + +typedef HRESULT(*PFN_EnumAdapterByGpuPreference2)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapterByLuid2)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); +typedef HRESULT(*PFN_EnumAdapters12)(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); +typedef HRESULT(*PFN_EnumAdapters2)(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); + +typedef HRESULT(*PFN_CreateSwapChain)(IDXGIFactory*, IUnknown*, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**); +typedef HRESULT(*PFN_CreateSwapChainForHwnd)(IDXGIFactory*, IUnknown*, HWND, const DXGI_SWAP_CHAIN_DESC1*, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC*, IDXGIOutput*, IDXGISwapChain1**); + + +static PFN_CreateDXGIFactory o_CreateDXGIFactory = nullptr; +static PFN_CreateDXGIFactory1 o_CreateDXGIFactory1 = nullptr; +static PFN_CreateDXGIFactory2 o_CreateDXGIFactory2 = nullptr; + +inline static PFN_EnumAdapters2 ptrEnumAdapters = nullptr; +inline static PFN_EnumAdapters12 ptrEnumAdapters1 = nullptr; +inline static PFN_EnumAdapterByLuid2 ptrEnumAdapterByLuid = nullptr; +inline static PFN_EnumAdapterByGpuPreference2 ptrEnumAdapterByGpuPreference = nullptr; + +static PFN_CreateSwapChain oCreateSwapChain = nullptr; +static PFN_CreateSwapChainForHwnd oCreateSwapChainForHwnd = nullptr; + +// DirectX +typedef void(*PFN_CreateSampler)(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +typedef HRESULT(*PFN_CreateSamplerState)(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); + +static PFN_D3D12_CREATE_DEVICE o_D3D12CreateDevice = nullptr; +static PFN_CreateSampler o_CreateSampler = nullptr; + +static PFN_D3D11_CREATE_DEVICE o_D3D11CreateDevice = nullptr; +static PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN o_D3D11CreateDeviceAndSwapChain = nullptr; +static PFN_CreateSamplerState o_CreateSamplerState = nullptr; +static PFN_D3D11ON12_CREATE_DEVICE o_D3D11On12CreateDevice = nullptr; +static ID3D11Device* d3d11Device = nullptr; +static ID3D11Device* d3d11on12Device = nullptr; + +// menu +static bool _dx11Device = false; +static bool _dx12Device = false; + +// for dx11 +static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; + +// for dx12 +static ID3D12Device* g_pd3dDeviceParam = nullptr; +static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr; + +// status +static bool _isInited = false; +static bool _d3d12Captured = false; + +static void DeatachAllHooks(); +static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); +static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); +static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); +static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); +static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); +static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); + +static void LoadFSR31Funcs() +{ + + ID3D12Resource* textureResource; + ID3D12DescriptorHeap* srvHeap; + D3D12_GPU_DESCRIPTOR_HANDLE srvGpuHandle; + + LOG_DEBUG("Loading amd_fidelityfx_dx12.dll methods"); + + auto file = Util::DllPath().parent_path() / "amd_fidelityfx_dx12.dll"; + LOG_INFO("Trying to load {}", file.string()); + + auto _dll = LoadLibrary(file.wstring().c_str()); + if (_dll != nullptr) + { + _configure = (PfnFfxConfigure)GetProcAddress(_dll, "ffxConfigure"); + _createContext = (PfnFfxCreateContext)GetProcAddress(_dll, "ffxCreateContext"); + _destroyContext = (PfnFfxDestroyContext)GetProcAddress(_dll, "ffxDestroyContext"); + _dispatch = (PfnFfxDispatch)GetProcAddress(_dll, "ffxDispatch"); + _query = (PfnFfxQuery)GetProcAddress(_dll, "ffxQuery"); + } + + if (_configure == nullptr) + { + LOG_INFO("Trying to load amd_fidelityfx_dx12.dll with detours"); + + _configure = (PfnFfxConfigure)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxConfigure"); + _createContext = (PfnFfxCreateContext)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxCreateContext"); + _destroyContext = (PfnFfxDestroyContext)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxDestroyContext"); + _dispatch = (PfnFfxDispatch)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxDispatch"); + _query = (PfnFfxQuery)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxQuery"); + } + + if (_configure != nullptr) + LOG_INFO("amd_fidelityfx_dx12.dll methods loaded!"); + else + LOG_ERROR("can't load amd_fidelityfx_dx12.dll methods!"); +} + +static void FfxFgLogCallback(uint32_t type, const wchar_t* message) +{ + std::wstring string(message); + LOG_DEBUG(" FG Log: {0}", wstring_to_string(string)); +} + +static bool CreateBufferResource(ID3D12Device* InDevice, ID3D12Resource* InSource, D3D12_RESOURCE_STATES InState, ID3D12Resource** OutResource) +{ + if (InDevice == nullptr || InSource == nullptr) + return false; + + D3D12_RESOURCE_DESC texDesc = InSource->GetDesc(); + + if (*OutResource != nullptr) + { + auto bufDesc = (*OutResource)->GetDesc(); + + if (bufDesc.Width != (UINT64)(texDesc.Width) || bufDesc.Height != (UINT)(texDesc.Height) || bufDesc.Format != texDesc.Format) + { + (*OutResource)->Release(); + (*OutResource) = nullptr; + } + else + return true; + } + + D3D12_HEAP_PROPERTIES heapProperties; + D3D12_HEAP_FLAGS heapFlags; + HRESULT hr = InSource->GetHeapProperties(&heapProperties, &heapFlags); + + if (hr != S_OK) + { + LOG_ERROR("GetHeapProperties result: {0:X}", (UINT64)hr); + return false; + } + + texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + hr = InDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texDesc, InState, nullptr, IID_PPV_ARGS(OutResource)); + + if (hr != S_OK) + { + LOG_ERROR("CreateCommittedResource result: {0:X}", (UINT64)hr); + return false; + } + + (*OutResource)->SetName(L"fgHudlessSCBufferCopy"); + return true; +} + +static void ResourceBarrier(ID3D12GraphicsCommandList* InCommandList, ID3D12Resource* InResource, D3D12_RESOURCE_STATES InBeforeState, D3D12_RESOURCE_STATES InAfterState) +{ + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = InResource; + barrier.Transition.StateBefore = InBeforeState; + barrier.Transition.StateAfter = InAfterState; + barrier.Transition.Subresource = 0; + InCommandList->ResourceBarrier(1, &barrier); +} + +static SIZE_T GetGPUHandle(ID3D12Device* This, SIZE_T cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE type) +{ + std::shared_lock lock(heapMutex); + for (auto& val : fgHeaps) + { + if (val.cpuStart <= cpuHandle && val.cpuEnd >= cpuHandle && val.gpuStart != 0) + { + auto incSize = This->GetDescriptorHandleIncrementSize(type); + auto addr = cpuHandle - val.cpuStart; + auto index = addr / incSize; + auto gpuAddr = val.gpuStart + (index * incSize); + + return gpuAddr; + } + } + + return NULL; +} + +static SIZE_T GetCPUHandle(ID3D12Device* This, SIZE_T gpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE type) +{ + std::shared_lock lock(heapMutex); + for (auto& val : fgHeaps) + { + if (val.gpuStart <= gpuHandle && val.gpuEnd >= gpuHandle && val.cpuStart != 0) + { + auto incSize = This->GetDescriptorHandleIncrementSize(type); + auto addr = gpuHandle - val.gpuStart; + auto index = addr / incSize; + auto cpuAddr = val.cpuStart + (index * incSize); + + return cpuAddr; + } + } + + return NULL; +} + +static HeapInfo* GetHeapByCpuHandle(SIZE_T cpuHandle) +{ + std::shared_lock lock(heapMutex); + for (size_t i = 0; i < fgHeaps.size(); i++) + { + if (fgHeaps[i].cpuStart <= cpuHandle && fgHeaps[i].cpuEnd >= cpuHandle) + return &fgHeaps[i]; + } + + return nullptr; +} + +static HeapInfo* GetHeapByGpuHandle(SIZE_T gpuHandle) +{ + std::shared_lock lock(heapMutex); + for (size_t i = 0; i < fgHeaps.size(); i++) + { + if (fgHeaps[i].gpuStart <= gpuHandle && fgHeaps[i].gpuEnd >= gpuHandle) + return &fgHeaps[i]; + } + + return nullptr; +} + +static bool InUpscaledList(ID3D12Resource* resource) +{ + auto fIndex = fgFrameIndex; + if (HooksDx::fgUpscaledImage[fIndex] == resource) + { + LOG_DEBUG_ONLY("Found upscaled image!"); + fgUpscaledFound = true; + return true; + } + + return false; +} + +static void FillResourceInfo(ID3D12Resource* resource, ResourceInfo* info) +{ + auto desc = resource->GetDesc(); + info->buffer = resource; + info->width = desc.Width; + info->height = desc.Height; + info->format = desc.Format; +} + +static void GetHudless(ID3D12GraphicsCommandList* This) +{ + auto fIndex = fgFrameIndex; + if (This != g_pd3dCommandList && fgCopySource[fIndex] != nullptr && Config::Instance()->CurrentFeature != nullptr && + fgHudlessFrame != Config::Instance()->CurrentFeature->FrameCount() && HooksDx::fgTarget <= Config::Instance()->CurrentFeature->FrameCount()) + { + LOG_DEBUG("FrameCount: {0}, fgHudlessFrame: {1}, CommandList: {2:X}", Config::Instance()->CurrentFeature->FrameCount(), fgHudlessFrame, (UINT64)This); + + HooksDx::fgSkipHudlessChecks = true; + + // hudless captured for this frame + fgHudlessFrame = Config::Instance()->CurrentFeature->FrameCount(); + auto frame = fgHudlessFrame; + + LOG_DEBUG("running, frame: {0}", frame); + + // switch dlss targets for next depth and mv + ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; + + m_FrameGenerationConfig.HUDLessColor = ffxApiGetResourceDX12(fgHudless[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST, 0); + + m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; + m_FrameGenerationConfig.frameGenerationEnabled = true; + m_FrameGenerationConfig.flags = 0; + + if (Config::Instance()->FGDebugView.value_or(false)) + m_FrameGenerationConfig.flags |= FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_VIEW; + + m_FrameGenerationConfig.allowAsyncWorkloads = Config::Instance()->FGAsync.value_or(false); + + // assume symmetric letterbox + m_FrameGenerationConfig.generationRect.left = 0; + m_FrameGenerationConfig.generationRect.top = 0; + m_FrameGenerationConfig.generationRect.width = Config::Instance()->CurrentFeature->DisplayWidth(); + m_FrameGenerationConfig.generationRect.height = Config::Instance()->CurrentFeature->DisplayHeight(); + + m_FrameGenerationConfig.frameGenerationCallback = [](ffxDispatchDescFrameGeneration* params, void* pUserCtx) -> ffxReturnCode_t + { + HRESULT result; + ffxReturnCode_t dispatchResult; + auto fIndex = fgFrameIndex; + + // check for status + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || Config::Instance()->FGChanged || + HooksDx::fgContext == nullptr || HooksDx::fgCopyCommandList == nullptr || HooksDx::fgCopyCommandQueue == nullptr) + { + LOG_WARN("Cancel async dispatch"); + fgDispatchCalled = false; + HooksDx::fgSkipHudlessChecks = false; + return FFX_API_RETURN_OK; + } + + // If fg is active but upscaling paused + if (!fgDispatchCalled || Config::Instance()->CurrentFeature == nullptr || + fgLastFGFrame == Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive) + { + LOG_WARN("Callback without hudless! frameID: {}", params->frameID); + + auto allocator = HooksDx::fgCopyCommandAllocators[fIndex]; + result = allocator->Reset(); + result = HooksDx::fgCopyCommandList->Reset(allocator, nullptr); + + params->frameID = fgLastFGFrame; + params->numGeneratedFrames = 0; + } + + if (Config::Instance()->CurrentFeature != nullptr) + fgLastFGFrame = Config::Instance()->CurrentFeature->FrameCount(); + + dispatchResult = _dispatch(reinterpret_cast(pUserCtx), ¶ms->header); + ID3D12CommandList* cl[1] = { nullptr }; + result = HooksDx::fgCopyCommandList->Close(); + cl[0] = HooksDx::fgCopyCommandList; + HooksDx::gameCommandQueue->ExecuteCommandLists(1, cl); + + LOG_DEBUG("_dispatch result: {0}", (UINT)result); + + fgDispatchCalled = false; + HooksDx::fgSkipHudlessChecks = false; + + return dispatchResult; + }; + + m_FrameGenerationConfig.frameGenerationCallbackUserContext = &HooksDx::fgContext; + + m_FrameGenerationConfig.onlyPresentGenerated = Config::Instance()->FGOnlyGenerated; + m_FrameGenerationConfig.frameID = Config::Instance()->CurrentFeature->FrameCount(); + m_FrameGenerationConfig.swapChain = HooksDx::currentSwapchain; + + ffxConfigureDescGlobalDebug1 debugDesc; + debugDesc.header.type = FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1; + debugDesc.debugLevel = FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_VERBOSE; + debugDesc.fpMessage = FfxFgLogCallback; + m_FrameGenerationConfig.header.pNext = &debugDesc.header; + + Config::Instance()->dxgiSkipSpoofing = true; + ffxReturnCode_t retCode = _configure(&HooksDx::fgContext, &m_FrameGenerationConfig.header); + Config::Instance()->dxgiSkipSpoofing = false; + LOG_DEBUG("_configure result: {0:X}, frame: {1}", retCode, frame); + + if (retCode == FFX_API_RETURN_OK) + { + ffxCreateBackendDX12Desc backendDesc{}; + backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12; + backendDesc.device = g_pd3dDeviceParam; + + ffxDispatchDescFrameGenerationPrepare dfgPrepare{}; + dfgPrepare.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION_PREPARE; + dfgPrepare.header.pNext = &backendDesc.header; + + dfgPrepare.commandList = HooksDx::fgCopyCommandList; // This; + + dfgPrepare.frameID = frame; + dfgPrepare.flags = m_FrameGenerationConfig.flags; + + dfgPrepare.renderSize = { Config::Instance()->CurrentFeature->RenderWidth(), Config::Instance()->CurrentFeature->RenderHeight() }; + + dfgPrepare.jitterOffset.x = HooksDx::jitterX; + dfgPrepare.jitterOffset.y = HooksDx::jitterY; + + // They will be always copies + dfgPrepare.motionVectors = ffxApiGetResourceDX12(HooksDx::paramVelocity[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST); + dfgPrepare.depth = ffxApiGetResourceDX12(HooksDx::paramDepth[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST); + + dfgPrepare.motionVectorScale.x = HooksDx::mvScaleX; + dfgPrepare.motionVectorScale.y = HooksDx::mvScaleY; + + if (Config::Instance()->CurrentFeature->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_DepthInverted) + { + dfgPrepare.cameraFar = Config::Instance()->FsrCameraNear.value_or(0.01f); + dfgPrepare.cameraNear = Config::Instance()->FsrCameraFar.value_or(0.99f); + } + else + { + dfgPrepare.cameraFar = Config::Instance()->FsrCameraFar.value_or(0.99f); + dfgPrepare.cameraNear = Config::Instance()->FsrCameraNear.value_or(0.01f); + } + + dfgPrepare.cameraFovAngleVertical = 1.0471975511966f; + dfgPrepare.viewSpaceToMetersFactor = 1.0; + dfgPrepare.frameTimeDelta = HooksDx::fgFrameTime; + + // If somehow context is destroyed before this point + if (Config::Instance()->CurrentFeature == nullptr || HooksDx::fgContext == nullptr || !HooksDx::fgIsActive) + { + LOG_WARN("!! Config::Instance()->CurrentFeature == nullptr || HooksDx::fgContext == nullptr"); + return; + } + + Config::Instance()->dxgiSkipSpoofing = true; + retCode = _dispatch(&HooksDx::fgContext, &dfgPrepare.header); + fgDispatchCalled = true; + Config::Instance()->dxgiSkipSpoofing = false; + LOG_DEBUG("_dispatch result: {0}, frame: {1}", retCode, frame); + } + } +} + +static bool CheckCapture() +{ + auto fIndex = fgFrameIndex; + + { + std::unique_lock lock(counterMutex[fIndex]); + HooksDx::fgHUDlessCaptureCounter[fIndex]++; + + LOG_DEBUG("frameCounter: {}, fgHUDlessCaptureCounter: {}, Limit: {}", frameCounter, HooksDx::fgHUDlessCaptureCounter[fIndex], Config::Instance()->FGHUDLimit.value_or(1)); + + if (HooksDx::fgHUDlessCaptureCounter[fIndex] != Config::Instance()->FGHUDLimit.value_or(1)) + return false; + } + + return true; +} + +static void CaptureHudless(ID3D12GraphicsCommandList* cmdList, ResourceInfo* resource, D3D12_RESOURCE_STATES state) +{ + auto fIndex = fgFrameIndex; + HooksDx::upscaleRan = false; + fgUpscaledFound = false; + fgCopySource[fIndex] = resource->buffer; + + LOG_TRACE("Capture resource: {0:X}", (size_t)resource->buffer); + + if (resource->format != HooksDx::swapchainFormat && Config::Instance()->FGHUDFixExtended.value_or(false) && HooksDx::fgFormatTransfer != nullptr && + (resource->format == DXGI_FORMAT_R16G16B16A16_FLOAT || resource->format == DXGI_FORMAT_R11G11B10_FLOAT || resource->format == DXGI_FORMAT_R32G32B32A32_FLOAT || resource->format == DXGI_FORMAT_R32G32B32_FLOAT) && + (HooksDx::swapchainFormat == DXGI_FORMAT_R8G8B8A8_UNORM || HooksDx::swapchainFormat == DXGI_FORMAT_B8G8R8A8_UNORM || HooksDx::swapchainFormat == DXGI_FORMAT_R10G10B10A2_UNORM)) + { + if (HooksDx::fgFormatTransfer->CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS) && + CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, &fgHudlessBuffer[fIndex])) + { +#ifdef USE_RESOURCE_BARRIRER + ResourceBarrier(cmdList, resource->buffer, state, D3D12_RESOURCE_STATE_COPY_SOURCE); + ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); +#endif + + cmdList->CopyResource(fgHudlessBuffer[fIndex], resource->buffer); +#ifdef USE_RESOURCE_BARRIRER + ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, state); +#endif + + HooksDx::fgFormatTransfer->SetBufferState(HooksDx::fgCopyCommandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + HooksDx::fgFormatTransfer->Dispatch(g_pd3dDeviceParam, HooksDx::fgCopyCommandList, fgHudlessBuffer[fIndex], HooksDx::fgFormatTransfer->Buffer()); + HooksDx::fgFormatTransfer->SetBufferState(HooksDx::fgCopyCommandList, D3D12_RESOURCE_STATE_COPY_SOURCE); + + LOG_TRACE("Using fgFormatTransfer->Buffer()"); + fgHudless[fIndex] = HooksDx::fgFormatTransfer->Buffer(); + } + else + { + LOG_WARN("Can't create fgHudlessBuffer or fgFormatTransfer buffer!"); + return; + } + } + else + { +#ifdef USE_RESOURCE_BARRIRER + ResourceBarrier(cmdList, resource->buffer, state, D3D12_RESOURCE_STATE_COPY_SOURCE); +#endif + + if (CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_COPY_DEST, &fgHudless[fIndex])) + cmdList->CopyResource(fgHudless[fIndex], resource->buffer); + +#ifdef USE_RESOURCE_BARRIRER + ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, state); +#endif + } + + GetHudless(cmdList); +} + +static bool CheckForHudless(ResourceInfo* resource, bool checkFormat = true) +{ + if (HooksDx::currentSwapchain == nullptr) + return false; + + DXGI_SWAP_CHAIN_DESC scDesc{}; + if (HooksDx::currentSwapchain->GetDesc(&scDesc) != S_OK) + { + LOG_WARN("Can't get swapchain desc!"); + return false; + } + + if (scDesc.BufferDesc.Height != fgScDesc.BufferDesc.Height || scDesc.BufferDesc.Width != fgScDesc.BufferDesc.Width || scDesc.BufferDesc.Format != fgScDesc.BufferDesc.Format) + { + LOG_DEBUG("Format change, recreate the FormatTransfer"); + delete HooksDx::fgFormatTransfer; + HooksDx::fgFormatTransfer = nullptr; + HooksDx::fgFormatTransfer = new FT_Dx12("FormatTransfer", g_pd3dDeviceParam, scDesc.BufferDesc.Format); + + HooksDx::swapchainFormat = scDesc.BufferDesc.Format; + fgScDesc = scDesc; + } + + if (resource->height == fgScDesc.BufferDesc.Height && resource->width == fgScDesc.BufferDesc.Width && (!checkFormat || resource->format == fgScDesc.BufferDesc.Format || + (Config::Instance()->FGHUDFixExtended.value_or(false) && HooksDx::fgFormatTransfer != nullptr && + (resource->format == DXGI_FORMAT_R16G16B16A16_FLOAT || resource->format == DXGI_FORMAT_R11G11B10_FLOAT || resource->format == DXGI_FORMAT_R32G32B32A32_FLOAT || resource->format == DXGI_FORMAT_R32G32B32_FLOAT) && + (fgScDesc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || fgScDesc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || fgScDesc.BufferDesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM)))) + { + LOG_TRACE("Width: {}/{}, Height: {}/{}, Format: {}/{}, checkFormat: {} -> TRUE", + resource->width, fgScDesc.BufferDesc.Width, resource->height, fgScDesc.BufferDesc.Height, (UINT)resource->format, (UINT)fgScDesc.BufferDesc.Format, checkFormat); + + return true; + } + + LOG_TRACE("Width: {}/{}, Height: {}/{}, Format: {}/{}, checkFormat: {} -> FALSE", + resource->width, fgScDesc.BufferDesc.Width, resource->height, fgScDesc.BufferDesc.Height, (UINT)resource->format, (UINT)fgScDesc.BufferDesc.Format, checkFormat); + + return false; +} + +#ifdef USE_RESOURCE_DISCARD +static void hkDiscardResource(ID3D12GraphicsCommandList* This, ID3D12Resource* pResource, D3D12_DISCARD_REGION* pRegion) +{ + o_DiscardResource(This, pResource, pRegion); + + if (This != g_pd3dCommandList && pRegion == nullptr) + { + std::unique_lock lock(resourceMutex); + + if (!fgHandlesByResources.contains(pResource)) + return; + + auto heapInfo = &fgHandlesByResources[pResource]; + LOG_DEBUG_ONLY(" <-- {}", heapInfo->cpuStart); + + auto heap = GetHeapByCpuHandle(heapInfo->cpuStart); + if (heap != nullptr) + heap->SetByCpuHandle(heapInfo->cpuStart, {}); + + fgHandlesByResources.erase(pResource); + LOG_DEBUG_ONLY("Erased"); + } +} +#endif + +#pragma region "Resource inputs" + +static void hkCreateRenderTargetView(ID3D12Device* This, ID3D12Resource* pResource, const D3D12_RENDER_TARGET_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) +{ + o_CreateRenderTargetView(This, pResource, pDesc, DestDescriptor); + + + if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) + return; + + auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + ResourceHeapInfo info{}; + info.cpuStart = DestDescriptor.ptr; + info.gpuStart = gpuHandle; + + ResourceInfo resInfo{}; + FillResourceInfo(pResource, &resInfo); + resInfo.type = RTV; + +#ifdef USE_RESOURCE_DISCARD + { + std::unique_lock lock(resourceMutex); + fgHandlesByResources.insert_or_assign(pResource, info); + } +#endif + + auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); + if (heap != nullptr) + heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); +} + +static void hkCreateShaderResourceView(ID3D12Device* This, ID3D12Resource* pResource, D3D12_SHADER_RESOURCE_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) +{ + o_CreateShaderResourceView(This, pResource, pDesc, DestDescriptor); + + if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) + return; + + auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + ResourceHeapInfo info{}; + info.cpuStart = DestDescriptor.ptr; + info.gpuStart = gpuHandle; + + ResourceInfo resInfo{}; + FillResourceInfo(pResource, &resInfo); + resInfo.type = SRV; + +#ifdef USE_RESOURCE_DISCARD + { + std::unique_lock lock(resourceMutex); + fgHandlesByResources.insert_or_assign(pResource, info); + } +#endif + + auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); + if (heap != nullptr) + heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); +} + +static void hkCreateUnorderedAccessView(ID3D12Device* This, ID3D12Resource* pResource, ID3D12Resource* pCounterResource, D3D12_UNORDERED_ACCESS_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) +{ + o_CreateUnorderedAccessView(This, pResource, pCounterResource, pDesc, DestDescriptor); + + + if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) + return; + + auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + ResourceHeapInfo info{}; + info.cpuStart = DestDescriptor.ptr; + info.gpuStart = gpuHandle; + + ResourceInfo resInfo{}; + FillResourceInfo(pResource, &resInfo); + resInfo.type = UAV; + +#ifdef USE_RESOURCE_DISCARD + { + std::unique_lock lock(resourceMutex); + fgHandlesByResources.insert_or_assign(pResource, info); + } +#endif + + auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); + if (heap != nullptr) + heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); +} + +#pragma endregion + +#pragma region "Resource copy" + +#ifdef USE_COPY_RESOURCE +static void hkCopyResource(ID3D12GraphicsCommandList* This, ID3D12Resource* Dest, ID3D12Resource* Source) +{ + o_CopyResource(This, Dest, Source); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This /* || fgPresentRunning */ || HooksDx::fgSkipHudlessChecks || + Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <--"); + + ResourceInfo resInfo{}; + FillResourceInfo(Dest, &resInfo); + + // Copy source is not in sources and dest is not matching for swapchain format + if (!InUpscaledList(Source) && !CheckForHudless(&resInfo, false)) + return; + + // not matching to swapchain format or limit is not ok + if (CheckForHudless(&resInfo) && CheckCapture()) + { + LOG_DEBUG("Capture"); + CaptureHudless(This, Dest); + } +} +#endif + +static void hkCopyTextureRegion(ID3D12GraphicsCommandList* This, D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, UINT DstY, UINT DstZ, D3D12_TEXTURE_COPY_LOCATION* pSrc, D3D12_BOX* pSrcBox) +{ + o_CopyTextureRegion(This, pDst, DstX, DstY, DstZ, pSrc, pSrcBox); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This || HooksDx::fgSkipHudlessChecks || + Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <--"); + + ResourceInfo resInfo{}; + FillResourceInfo(pDst->pResource, &resInfo); + + // Copy source is not in sources and dest is not matching for swapchain format + if (!InUpscaledList(pSrc->pResource) && !CheckForHudless(&resInfo, false)) + return; + + // not matching to swapchain format or limit is not ok + if (CheckForHudless(&resInfo) && CheckCapture()) + { + LOG_DEBUG("Capture"); + CaptureHudless(This, &resInfo, D3D12_RESOURCE_STATE_COPY_DEST); + } +} + +#pragma endregion + +#pragma region "Heap methods" + +static HRESULT hkCreateDescriptorHeap(ID3D12Device* This, D3D12_DESCRIPTOR_HEAP_DESC* pDescriptorHeapDesc, REFIID riid, void** ppvHeap) +{ + auto result = o_CreateDescriptorHeap(This, pDescriptorHeapDesc, riid, ppvHeap); + + // try to calculate handle ranges for heap + if (result == S_OK && (pDescriptorHeapDesc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || pDescriptorHeapDesc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV)) //&& pDescriptorHeapDesc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) + { + auto heap = (ID3D12DescriptorHeap*)(*ppvHeap); + auto increment = This->GetDescriptorHandleIncrementSize(pDescriptorHeapDesc->Type); + auto numDescriptors = pDescriptorHeapDesc->NumDescriptors; + auto cpuStart = (SIZE_T)(heap->GetCPUDescriptorHandleForHeapStart().ptr); + auto cpuEnd = cpuStart + (increment * numDescriptors); + auto gpuStart = (SIZE_T)(heap->GetGPUDescriptorHandleForHeapStart().ptr); + auto gpuEnd = gpuStart + (increment * numDescriptors); + auto type = (UINT)pDescriptorHeapDesc->Type; + HeapInfo info(cpuStart, cpuEnd, gpuStart, gpuEnd, numDescriptors, increment, type); + + LOG_DEBUG_ONLY("Heap type: {}, Cpu: {}-{}, Gpu: {}-{}, Desc count: {}", info.type, info.cpuStart, info.cpuEnd, info.gpuStart, info.gpuEnd, info.numDescriptors); + { + std::unique_lock lock(heapMutex); + fgHeaps.push_back(info); + } + } + else + { + auto heap = (ID3D12DescriptorHeap*)(*ppvHeap); + LOG_DEBUG_ONLY("Skipping, Heap type: {}, Cpu: {}, Gpu: {}", (UINT)pDescriptorHeapDesc->Type, heap->GetCPUDescriptorHandleForHeapStart().ptr, heap->GetGPUDescriptorHandleForHeapStart().ptr); + } + + return result; +} + + +static void hkCopyDescriptors(ID3D12Device* This, + UINT NumDestDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pDestDescriptorRangeStarts, UINT* pDestDescriptorRangeSizes, + UINT NumSrcDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pSrcDescriptorRangeStarts, UINT* pSrcDescriptorRangeSizes, + D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) +{ + o_CopyDescriptors(This, NumDestDescriptorRanges, pDestDescriptorRangeStarts, pDestDescriptorRangeSizes, NumSrcDescriptorRanges, pSrcDescriptorRangeStarts, pSrcDescriptorRangeSizes, DescriptorHeapsType); + + auto fIndex = fgFrameIndex; + + if (Config::Instance()->CurrentFeature == nullptr) + return; + + if (DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_RTV) + return; + + LOG_DEBUG_ONLY("SrcRanges: {}, DestRanges: {}, Type: {}", NumSrcDescriptorRanges, NumDestDescriptorRanges, (UINT)DescriptorHeapsType); + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + auto size = This->GetDescriptorHandleIncrementSize(DescriptorHeapsType); + + UINT destRangeIndex = 0; + UINT destIndex = 0; + + for (size_t i = 0; i < NumSrcDescriptorRanges; i++) + { + UINT copyCount = 1; + + if (pSrcDescriptorRangeSizes != nullptr) + copyCount = pSrcDescriptorRangeSizes[i]; + + for (size_t j = 0; j < copyCount; j++) + { + auto handle = pSrcDescriptorRangeStarts[i].ptr + j * size; + + auto heap = GetHeapByCpuHandle(handle); + if (heap == nullptr) + continue; + + auto buffer = heap->GetByCpuHandle(handle); + auto destHandle = pDestDescriptorRangeStarts[destRangeIndex].ptr + destIndex * size; + heap->SetByCpuHandle(destHandle, *buffer); + } + + if (pDestDescriptorRangeSizes == nullptr) + { + destIndex = 0; + destRangeIndex++; + } + else + { + if (pDestDescriptorRangeSizes[destRangeIndex] == destIndex) + { + destIndex = 0; + destRangeIndex++; + } + else + { + destIndex++; + } + } + } +} + +static void hkCopyDescriptorsSimple(ID3D12Device* This, UINT NumDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart, + D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) +{ + o_CopyDescriptorsSimple(This, NumDescriptors, DestDescriptorRangeStart, SrcDescriptorRangeStart, DescriptorHeapsType); + + auto fIndex = fgFrameIndex; + + if (Config::Instance()->CurrentFeature == nullptr) + return; + + if (DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_RTV) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + auto size = This->GetDescriptorHandleIncrementSize(DescriptorHeapsType); + + for (size_t i = 0; i < NumDescriptors; i++) + { + auto handle = SrcDescriptorRangeStart.ptr + i * size; + + auto heap = GetHeapByCpuHandle(handle); + if (heap == nullptr) + continue; + + auto buffer = heap->GetByCpuHandle(handle); + auto destHandle = DestDescriptorRangeStart.ptr + i * size; + heap->SetByCpuHandle(destHandle, *buffer); + } +} + +#pragma endregion + +#pragma region "Shader inputs" + +static void hkSetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) +{ + o_SetGraphicsRootDescriptorTable(This, RootParameterIndex, BaseDescriptor); + + auto fIndex = fgFrameIndex; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + auto heap = GetHeapByGpuHandle(BaseDescriptor.ptr); + if (heap == nullptr) + return; + + auto capturedBuffer = heap->GetByGpuHandle(BaseDescriptor.ptr); + if (capturedBuffer == nullptr || capturedBuffer->buffer == nullptr) + { + LOG_DEBUG_ONLY("Miss RootParameterIndex: {1}, CommandList: {0:X}, gpuHandle: {2}", (SIZE_T)This, RootParameterIndex, BaseDescriptor.ptr); + return; + } + + if (!InUpscaledList(capturedBuffer->buffer) && !CheckForHudless(capturedBuffer, false)) + return; + + capturedBuffer->state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + + { + std::unique_lock lock(hudlessMutex[fIndex]); + if (fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); + return; + } + + ankerl::unordered_dense::map newMap; + fgPossibleHudless[fIndex].insert_or_assign(This, newMap); + fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); + } +} + +#pragma endregion + +#pragma region "Shader outputs" + +static void hkOMSetRenderTargets(ID3D12GraphicsCommandList* This, UINT NumRenderTargetDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, + BOOL RTsSingleHandleToDescriptorRange, D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor) +{ + o_OMSetRenderTargets(This, NumRenderTargetDescriptors, pRenderTargetDescriptors, RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This /* || fgPresentRunning */ || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + { + std::unique_lock lock(hudlessMutex[fIndex]); + + for (size_t i = 0; i < NumRenderTargetDescriptors; i++) + { + auto handle = pRenderTargetDescriptors[i]; + auto heap = GetHeapByCpuHandle(handle.ptr); + if (heap == nullptr) + continue; + + auto resource = heap->GetByCpuHandle(handle.ptr); + if (resource == nullptr || resource->buffer == nullptr) + { + LOG_DEBUG_ONLY("Miss index: {0}, cpu: {1}", i, handle.ptr); + continue; + } + + if (!CheckForHudless(resource, false)) + continue; + + resource->state = D3D12_RESOURCE_STATE_RENDER_TARGET; + + if (fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].insert_or_assign(resource->buffer, *resource); + return; + } + + ankerl::unordered_dense::map newMap; + fgPossibleHudless[fIndex].insert_or_assign(This, newMap); + fgPossibleHudless[fIndex][This].insert_or_assign(resource->buffer, *resource); + } + } +} + +#pragma endregion + +#pragma region "Compute paramters" + +static void hkSetComputeRootDescriptorTable(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) +{ + o_SetComputeRootDescriptorTable(This, RootParameterIndex, BaseDescriptor); + + auto fIndex = fgFrameIndex; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + auto heap = GetHeapByGpuHandle(BaseDescriptor.ptr); + if (heap == nullptr) + return; + + auto capturedBuffer = heap->GetByGpuHandle(BaseDescriptor.ptr); + if (capturedBuffer != nullptr && capturedBuffer->buffer != nullptr && (InUpscaledList(capturedBuffer->buffer) || CheckForHudless(capturedBuffer, false))) + { + if (capturedBuffer->type == UAV) + capturedBuffer->state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + else + capturedBuffer->state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + std::unique_lock lock4(hudlessMutex[fIndex]); + if (fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); + return; + } + + ankerl::unordered_dense::map newMap; + fgPossibleHudless[fIndex].insert_or_assign(This, newMap); + fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); + } +} + +#pragma endregion + +#pragma region "Shader finalizers" + +// Capture if render target matches, wait for DrawIndexed +static void hkDrawInstanced(ID3D12GraphicsCommandList* This, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) +{ + o_DrawInstanced(This, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This /* || fgPresentRunning */ || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + { + std::unique_lock lock(hudlessMutex[fIndex]); + // if can't find output skip + if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].clear(); + return; + } + + do + { + auto& val0 = fgPossibleHudless[fIndex][This]; + + // if this command list does not have entries skip + if (val0.size() == 0) + break; + + for (auto& [key, val] : val0) + { + if (CheckForHudless(&val)) + { + if (CheckCapture()) + { + LOG_DEBUG("Capture"); + CaptureHudless(This, &val, val.state); + break; + } + } + } + + } while (false); + + fgPossibleHudless[fIndex][This].clear(); + LOG_DEBUG_ONLY("Clear"); + } +} + +static void hkDrawIndexedInstanced(ID3D12GraphicsCommandList* This, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) +{ + o_DrawIndexedInstanced(This, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This /* || fgPresentRunning */ || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + { + std::unique_lock lock(hudlessMutex[fIndex]); + // if can't find output skip + if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].clear(); + LOG_DEBUG_ONLY("Early exit"); + return; + } + + do + { + auto& val0 = fgPossibleHudless[fIndex][This]; + + // if this command list does not have entries skip + if (val0.size() == 0) + break; + + for (auto& [key, val] : val0) + { + if (CheckForHudless(&val)) + { + LOG_DEBUG_ONLY("Found matching final image"); + + if (CheckCapture()) + { + LOG_DEBUG("Capture"); + CaptureHudless(This, &val, val.state); + break; + } + } + } + + } while (false); + + fgPossibleHudless[fIndex][This].clear(); + LOG_DEBUG_ONLY("Clear"); + } +} + +static void hkDispatch(ID3D12GraphicsCommandList* This, UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) +{ + o_Dispatch(This, ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); + + auto fIndex = fgFrameIndex; + + if (This == g_pd3dCommandList || HooksDx::fgCopyCommandList == This /* || fgPresentRunning */ || HooksDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !HooksDx::upscaleRan) + return; + + if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || HooksDx::fgContext == nullptr || + HooksDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !HooksDx::fgIsActive || + fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) + return; + + LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); + + { + std::unique_lock lock(hudlessMutex[fIndex]); + // if can't find output skip + if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) + { + fgPossibleHudless[fIndex][This].clear(); + LOG_DEBUG_ONLY("Early exit"); + return; + } + + do + { + auto& val0 = fgPossibleHudless[fIndex][This]; + + // if this command list does not have entries skip + if (val0.size() == 0) + break; + + for (auto& [key, val] : val0) + { + if (CheckForHudless(&val)) + { + LOG_DEBUG_ONLY("Found matching final image"); + + if (CheckCapture()) + { + LOG_DEBUG("Capture"); + CaptureHudless(This, &val, val.state); + break; + } + } + } + + } while (false); + + fgPossibleHudless[fIndex][This].clear(); + LOG_DEBUG_ONLY("Clear"); + } +} + +#pragma endregion + +static int GetCorrectDXGIFormat(int eCurrentFormat) +{ + switch (eCurrentFormat) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM; + } + + return eCurrentFormat; +} + +#pragma region Callbacks for wrapped swapchain + +static HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd) +{ + LOG_DEBUG(""); + + HRESULT presentResult; + auto fIndex = fgFrameIndex; + + if (hWnd != Util::GetProcessWindow()) + { + //fgPresentRunning = true; + + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + //fgPresentRunning = false; + + HooksDx::currentSwapchain = nullptr; + HooksDx::swapchainFormat = DXGI_FORMAT_UNKNOWN; + HooksDx::fgSkipHudlessChecks = false; + + LOG_FUNC_RESULT(presentResult); + + //LOG_DEBUG("Return"); + + return presentResult; + } + + if (fgSwapChains.contains(hWnd)) + { + auto swInfo = &fgSwapChains[hWnd]; + HooksDx::currentSwapchain = swInfo->swapChain; + + if (HooksDx::swapchainFormat == DXGI_FORMAT_UNKNOWN) + HooksDx::swapchainFormat = swInfo->swapChainFormat; + + swInfo->fgCommandQueue = (ID3D12CommandQueue*)pDevice; + HooksDx::gameCommandQueue = swInfo->gameCommandQueue; + } + + //if (Config::Instance()->CurrentFeature != nullptr) + // LOG_DEBUG("FrameCount: {}, fgHudlessFrame: {}", Config::Instance()->CurrentFeature->FrameCount(), fgHudlessFrame); + + ID3D12CommandQueue* cq = nullptr; + ID3D11Device* device = nullptr; + ID3D12Device* device12 = nullptr; + + // try to obtain directx objects and find the path + if (pDevice->QueryInterface(IID_PPV_ARGS(&device)) == S_OK) + { + if (!_dx11Device) + LOG_DEBUG("D3D11Device captured"); + + _dx11Device = true; + } + else if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + if (!_dx12Device) + LOG_DEBUG("D3D12CommandQueue captured"); + + HooksDx::fgCommandQueue = (ID3D12CommandQueue*)pDevice; + HooksDx::fgCommandQueue->SetName(L"fgSwapChainQueue"); + HooksDx::GameCommandQueue = (ID3D12CommandQueue*)pDevice; + + if (cq->GetDevice(IID_PPV_ARGS(&device12)) == S_OK) + { + if (!_dx12Device) + LOG_DEBUG("D3D12Device captured"); + + _dx12Device = true; + } + } + + // DXVK check, it's here because of upscaler time calculations + if (Config::Instance()->IsRunningOnDXVK) + { + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + //fgPresentRunning = true; + + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + HooksDx::fgSkipHudlessChecks = false; + + if (Config::Instance()->CurrentFeature != nullptr) + fgPresentedFrame = Config::Instance()->CurrentFeature->FrameCount(); + + if (fgStopAfterNextPresent) + { + HooksDx::StopAndDestroyFGContext(false, false); + fgStopAfterNextPresent = false; + } + + auto now = Util::MillisecondsNow(); + + if (fgLastFrameTime != 0) + { + fgLastDeltaTime = now - fgLastFrameTime; + LOG_DEBUG("fgLastDeltaTime: {0:.2f}, frameCounter: {1}", fgLastDeltaTime, frameCounter); + } + + fgLastFrameTime = now; + + //LOG_DEBUG("Return"); + + return presentResult; + } + + // Upscaler GPU time computation + if (HooksDx::dx12UpscaleTrig && HooksDx::readbackBuffer != nullptr && HooksDx::queryHeap != nullptr && cq != nullptr) + { + UINT64* timestampData; + HooksDx::readbackBuffer->Map(0, nullptr, reinterpret_cast(×tampData)); + + if (timestampData != nullptr) + { + // Get the GPU timestamp frequency (ticks per second) + UINT64 gpuFrequency; + cq->GetTimestampFrequency(&gpuFrequency); + + // Calculate elapsed time in milliseconds + UINT64 startTime = timestampData[0]; + UINT64 endTime = timestampData[1]; + double elapsedTimeMs = (endTime - startTime) / static_cast(gpuFrequency) * 1000.0; + + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + } + else + { + LOG_WARN("timestampData is null!"); + } + + // Unmap the buffer + HooksDx::readbackBuffer->Unmap(0, nullptr); + + HooksDx::dx12UpscaleTrig = false; + } + else if (HooksDx::dx11UpscaleTrig[HooksDx::currentFrameIndex] && device != nullptr && HooksDx::disjointQueries[0] != nullptr && + HooksDx::startQueries[0] != nullptr && HooksDx::endQueries[0] != nullptr) + { + if (g_pd3dDeviceContext == nullptr) + device->GetImmediateContext(&g_pd3dDeviceContext); + + // Retrieve the results from the previous frame + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; + if (g_pd3dDeviceContext->GetData(HooksDx::disjointQueries[HooksDx::previousFrameIndex], &disjointData, sizeof(disjointData), 0) == S_OK) + { + if (!disjointData.Disjoint && disjointData.Frequency > 0) + { + UINT64 startTime = 0, endTime = 0; + if (g_pd3dDeviceContext->GetData(HooksDx::startQueries[HooksDx::previousFrameIndex], &startTime, sizeof(UINT64), 0) == S_OK && + g_pd3dDeviceContext->GetData(HooksDx::endQueries[HooksDx::previousFrameIndex], &endTime, sizeof(UINT64), 0) == S_OK) + { + double elapsedTimeMs = (endTime - startTime) / static_cast(disjointData.Frequency) * 1000.0; + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + } + } + } + + + HooksDx::dx11UpscaleTrig[HooksDx::currentFrameIndex] = false; + HooksDx::currentFrameIndex = (HooksDx::currentFrameIndex + 1) % HooksDx::QUERY_BUFFER_COUNT; + } + + + ImGuiOverlayDx::Present(pSwapChain, SyncInterval, Flags, pPresentParameters, pDevice, hWnd); + + frameCounter++; + + // swapchain present + if (pPresentParameters == nullptr) + presentResult = pSwapChain->Present(SyncInterval, Flags); + else + presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); + + HooksDx::fgSkipHudlessChecks = false; + + if (Config::Instance()->CurrentFeature != nullptr) + fgPresentedFrame = Config::Instance()->CurrentFeature->FrameCount(); + + // release used objects + if (cq != nullptr) + cq->Release(); + + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); + + auto now = Util::MillisecondsNow(); + + if (fgLastFrameTime != 0) + { + fgLastDeltaTime = now - fgLastFrameTime; + LOG_DEBUG("fgLastDeltaTime: {0:.2f}, frameCounter: {1}", fgLastDeltaTime, frameCounter); + } + + fgLastFrameTime = now; + + return presentResult; +} + +#pragma endregion + +#pragma region DXGI hooks + +static void CheckAdapter(IUnknown* unkAdapter) +{ + if (Config::Instance()->IsRunningOnDXVK) + return; + + //DXVK VkInterface GUID + const GUID guid = { 0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff} }; + + IDXGIAdapter* adapter = nullptr; + bool adapterOk = unkAdapter->QueryInterface(IID_PPV_ARGS(&adapter)) == S_OK; + + void* dxvkAdapter = nullptr; + if (adapterOk && adapter->QueryInterface(guid, &dxvkAdapter) == S_OK) + { + + Config::Instance()->IsRunningOnDXVK = dxvkAdapter != nullptr; + ((IDXGIAdapter*)dxvkAdapter)->Release(); + } + + if (adapterOk) + adapter->Release(); +} + +static void AttachToFactory(IUnknown* unkFactory) +{ + PVOID* pVTable = *(PVOID**)unkFactory; + + IDXGIFactory* factory; + if (ptrEnumAdapters == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapters = (PFN_EnumAdapters2)pVTable[7]; + + DetourAttach(&(PVOID&)ptrEnumAdapters, hkEnumAdapters); + + DetourTransactionCommit(); + + factory->Release(); + } + + IDXGIFactory1* factory1; + if (ptrEnumAdapters1 == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory1)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapters1 = (PFN_EnumAdapters12)pVTable[12]; + + DetourAttach(&(PVOID&)ptrEnumAdapters1, hkEnumAdapters1); + + DetourTransactionCommit(); + + factory1->Release(); + } + + IDXGIFactory4* factory4; + if (ptrEnumAdapterByLuid == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory4)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapterByLuid = (PFN_EnumAdapterByLuid2)pVTable[26]; + + DetourAttach(&(PVOID&)ptrEnumAdapterByLuid, hkEnumAdapterByLuid); + + DetourTransactionCommit(); + + factory4->Release(); + } + + IDXGIFactory6* factory6; + if (ptrEnumAdapterByGpuPreference == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory6)) == S_OK) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + ptrEnumAdapterByGpuPreference = (PFN_EnumAdapterByGpuPreference2)pVTable[29]; + + DetourAttach(&(PVOID&)ptrEnumAdapterByGpuPreference, hkEnumAdapterByGpuPreference); + + DetourTransactionCommit(); + + factory6->Release(); + } +} + +static HRESULT hkCreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) +{ + LOG_FUNC(); + + *ppSwapChain = nullptr; + + if (Config::Instance()->VulkanCreatingSC) + { + LOG_WARN("Vulkan is creating swapchain!"); + + if (pDesc != nullptr) + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); + + return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + } + + if (pDevice == nullptr) + { + LOG_WARN("pDevice is nullptr!"); + return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + } + + if (pDesc->BufferDesc.Height == 2 && pDesc->BufferDesc.Width == 2) + { + LOG_WARN("RTSS call!"); + return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + } + + ID3D12CommandQueue* cq = nullptr; + if (Config::Instance()->FGUseFGSwapChain.value_or(true) && !fgSkipSCWrapping && _createContext != nullptr && pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + cq->SetName(L"GameQueue"); + SwapChainInfo scInfo{}; + scInfo.gameCommandQueue = cq; + cq->Release(); + + ffxCreateContextDescFrameGenerationSwapChainNewDX12 createSwapChainDesc{}; + createSwapChainDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_NEW_DX12; + + createSwapChainDesc.dxgiFactory = pFactory; + createSwapChainDesc.gameQueue = (ID3D12CommandQueue*)pDevice; + createSwapChainDesc.desc = pDesc; + createSwapChainDesc.swapchain = (IDXGISwapChain4**)ppSwapChain; + + + fgSkipSCWrapping = true; + Config::Instance()->dxgiSkipSpoofing = true; + Config::Instance()->SkipHeapCapture = true; + + auto result = _createContext(&HooksDx::fgSwapChainContext, &createSwapChainDesc.header, nullptr); + + Config::Instance()->SkipHeapCapture = false; + Config::Instance()->dxgiSkipSpoofing = false; + fgSkipSCWrapping = false; + + if (result == FFX_API_RETURN_OK) + { + scInfo.swapChainFormat = pDesc->BufferDesc.Format; + scInfo.swapChainBufferCount = pDesc->BufferCount; + scInfo.swapChain = (IDXGISwapChain4*)*ppSwapChain; + fgSwapChains.insert_or_assign(pDesc->OutputWindow, scInfo); + return S_OK; + } + + LOG_ERROR("_createContext error: {}", result); + + return E_INVALIDARG; + } + + auto result = oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); + if (result == S_OK) + { + // check for SL proxy + IID riid; + IDXGISwapChain* real = nullptr; + auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); + + if (iidResult == S_OK) + { + auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); + + if (qResult == S_OK && real != nullptr) + { + LOG_INFO("Streamline proxy found"); + real->Release(); + } + else + { + LOG_DEBUG("Streamline proxy not found"); + } + } + + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); + + if (Util::GetProcessWindow() == pDesc->OutputWindow) + { + Config::Instance()->ScreenWidth = pDesc->BufferDesc.Width; + Config::Instance()->ScreenHeight = pDesc->BufferDesc.Height; + } + + LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDesc->OutputWindow); + // TODO: Bind overlay menu event here + *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, pDesc->OutputWindow, Present, ImGuiOverlayDx::CleanupRenderTarget); + LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); + } + + return result; +} + +static HRESULT hkCreateSwapChainForHwnd(IDXGIFactory* This, IUnknown* pDevice, HWND hWnd, DXGI_SWAP_CHAIN_DESC1* pDesc, + DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) +{ + LOG_FUNC(); + + *ppSwapChain = nullptr; + + if (Config::Instance()->VulkanCreatingSC) + { + LOG_WARN("Vulkan is creating swapchain!"); + return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + } + + if (pDevice == nullptr) + { + LOG_WARN("pDevice is nullptr!"); + return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + } + + if (pDesc->Height == 2 && pDesc->Width == 2) + { + LOG_WARN("RTSS call!"); + return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + } + + ID3D12CommandQueue* cq = nullptr; + if (Config::Instance()->FGUseFGSwapChain.value_or(true) && !fgSkipSCWrapping && _createContext != nullptr && pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + SwapChainInfo scInfo{}; + scInfo.gameCommandQueue = cq; + + cq->SetName(L"GameQueueHwnd"); + cq->Release(); + + fgQueues.push_back((ID3D12CommandQueue*)pDevice); + + ffxCreateContextDescFrameGenerationSwapChainForHwndDX12 createSwapChainDesc{}; + createSwapChainDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_FOR_HWND_DX12; + + createSwapChainDesc.fullscreenDesc = pFullscreenDesc; + createSwapChainDesc.hwnd = hWnd; + createSwapChainDesc.dxgiFactory = This; + createSwapChainDesc.gameQueue = (ID3D12CommandQueue*)pDevice; + createSwapChainDesc.desc = pDesc; + createSwapChainDesc.swapchain = (IDXGISwapChain4**)ppSwapChain; + + Config::Instance()->dxgiSkipSpoofing = true; + fgSkipSCWrapping = true; + Config::Instance()->SkipHeapCapture = true; + + auto result = _createContext(&HooksDx::fgSwapChainContext, &createSwapChainDesc.header, nullptr); + + Config::Instance()->SkipHeapCapture = false; + fgSkipSCWrapping = false; + Config::Instance()->dxgiSkipSpoofing = false; + + if (result == FFX_API_RETURN_OK) + { + scInfo.swapChainFormat = pDesc->Format; + scInfo.swapChainBufferCount = pDesc->BufferCount; + scInfo.swapChain = (IDXGISwapChain4*)*ppSwapChain; + fgSwapChains.insert_or_assign(hWnd, scInfo); + return S_OK; + } + + LOG_ERROR("_createContext error: {}", result); + + return result; + } + + auto result = oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); + if (result == S_OK) + { + // check for SL proxy + IID riid; + IDXGISwapChain1* real = nullptr; + auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); + + if (iidResult == S_OK) + { + IUnknown* real = nullptr; + auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); + + if (qResult == S_OK && real != nullptr) + { + LOG_INFO("Streamline proxy found"); + real->Release(); + } + else + { + LOG_DEBUG("Streamline proxy not found"); + } + } + + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); + + if (Util::GetProcessWindow() == hWnd) + { + Config::Instance()->ScreenWidth = pDesc->Width; + Config::Instance()->ScreenHeight = pDesc->Height; + } + + LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)hWnd); + // TODO: Bind overlay menu event here + *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, hWnd, Present, ImGuiOverlayDx::CleanupRenderTarget); + LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); + } + + return result; +} + +static HRESULT hkCreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory) +{ + auto result = o_CreateDXGIFactory(riid, ppFactory); + + if (result == S_OK) + AttachToFactory(*ppFactory); + + if (result == S_OK && oCreateSwapChain == nullptr) + { + void** pFactoryVTable = *reinterpret_cast(*ppFactory); + + oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + + if (oCreateSwapChain != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); + + DetourTransactionCommit(); + } + } + + return result; +} + +static HRESULT hkCreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactory) +{ + auto result = o_CreateDXGIFactory1(riid, ppFactory); + + if (result == S_OK) + AttachToFactory(*ppFactory); + + if (result == S_OK && oCreateSwapChainForHwnd == nullptr) + { + IDXGIFactory2* factory2 = nullptr; + + if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) + { + void** pFactoryVTable = *reinterpret_cast(factory2); + + bool skip = false; + + if (oCreateSwapChain == nullptr) + oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + else + skip = true; + + oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; + + if (oCreateSwapChainForHwnd != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (!skip) + DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); + + DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + + DetourTransactionCommit(); + } + + factory2->Release(); + factory2 = nullptr; + } + } + + return result; +} + +static HRESULT hkCreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory) +{ + auto result = o_CreateDXGIFactory2(Flags, riid, ppFactory); + + if (result == S_OK) + AttachToFactory(*ppFactory); + + if (result == S_OK && oCreateSwapChainForHwnd == nullptr) + { + IDXGIFactory2* factory2 = nullptr; + + if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) + { + void** pFactoryVTable = *reinterpret_cast(factory2); + + bool skip = false; + + if (oCreateSwapChain == nullptr) + oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; + else + skip = true; + + oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; + + if (oCreateSwapChainForHwnd != nullptr) + { + LOG_INFO("Hooking native DXGIFactory"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (!skip) + DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); + + DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + + DetourTransactionCommit(); + } + + factory2->Release(); + factory2 = nullptr; + } + } + + return result; +} + +static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter) +{ + auto result = ptrEnumAdapterByGpuPreference(This, Adapter, GpuPreference, riid, ppvAdapter); + + if (result == S_OK) + CheckAdapter(*ppvAdapter); + + return result; +} + +static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter) +{ + auto result = ptrEnumAdapterByLuid(This, AdapterLuid, riid, ppvAdapter); + + if (result == S_OK) + CheckAdapter(*ppvAdapter); + + return result; +} + +static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter) +{ + auto result = ptrEnumAdapters1(This, Adapter, ppAdapter); + + if (result == S_OK) + CheckAdapter(*ppAdapter); + + return result; +} + +static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter) +{ + auto result = ptrEnumAdapters(This, Adapter, ppAdapter); + + if (result == S_OK) + CheckAdapter(*ppAdapter); + + return result; +} + +#pragma endregion + +#pragma region DirectX hooks + + + +static void HookCommandList(ID3D12Device* InDevice) +{ + if (o_OMSetRenderTargets != nullptr || o_DrawIndexedInstanced != nullptr) + return; + + ID3D12GraphicsCommandList* commandList = nullptr; + ID3D12CommandAllocator* commandAllocator = nullptr; + + if (InDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)) == S_OK) + { + if (InDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, nullptr, IID_PPV_ARGS(&commandList)) == S_OK) + { + // Get the vtable pointer + PVOID* pVTable = *(PVOID**)commandList; + + // hudless shader + o_OMSetRenderTargets = (PFN_OMSetRenderTargets)pVTable[46]; + o_SetGraphicsRootDescriptorTable = (PFN_SetGraphicsRootDescriptorTable)pVTable[32]; + o_DrawInstanced = (PFN_DrawInstanced)pVTable[12]; + o_DrawIndexedInstanced = (PFN_DrawIndexedInstanced)pVTable[13]; + + // hudless compute + o_SetComputeRootDescriptorTable = (PFN_SetComputeRootDescriptorTable)pVTable[31]; + o_Dispatch = (PFN_Dispatch)pVTable[14]; + + // hudless copy +#ifdef USE_COPY_RESOURCE + o_CopyResource = (PFN_CopyResource)pVTable[17]; +#endif + o_CopyTextureRegion = (PFN_CopyTextureRegion)pVTable[16]; + +#ifdef USE_RESOURCE_DISCARD + // release resource + o_DiscardResource = (PFN_DiscardResource)pVTable[51]; +#endif + + if (o_OMSetRenderTargets != nullptr || o_DrawIndexedInstanced != nullptr || o_DrawInstanced != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_OMSetRenderTargets != nullptr) + DetourAttach(&(PVOID&)o_OMSetRenderTargets, hkOMSetRenderTargets); + + if (o_DrawIndexedInstanced != nullptr) + DetourAttach(&(PVOID&)o_DrawIndexedInstanced, hkDrawIndexedInstanced); + + if (o_DrawInstanced != nullptr) + DetourAttach(&(PVOID&)o_DrawInstanced, hkDrawInstanced); + + if (o_CopyTextureRegion != nullptr) + DetourAttach(&(PVOID&)o_CopyTextureRegion, hkCopyTextureRegion); + +#ifdef USE_COPY_RESOURCE + if (o_CopyResource != nullptr) + DetourAttach(&(PVOID&)o_CopyResource, hkCopyResource); +#endif + if (o_SetGraphicsRootDescriptorTable != nullptr) + DetourAttach(&(PVOID&)o_SetGraphicsRootDescriptorTable, hkSetGraphicsRootDescriptorTable); + + if (o_SetComputeRootDescriptorTable != nullptr) + DetourAttach(&(PVOID&)o_SetComputeRootDescriptorTable, hkSetComputeRootDescriptorTable); + + if (o_Dispatch != nullptr) + DetourAttach(&(PVOID&)o_Dispatch, hkDispatch); + +#ifdef USE_RESOURCE_DISCARD + if (o_DiscardResource != nullptr) + DetourAttach(&(PVOID&)o_DiscardResource, hkDiscardResource); +#endif + DetourTransactionCommit(); + } + + commandList->Close(); + commandList->Release(); + } + + commandAllocator->Reset(); + commandAllocator->Release(); + } + } + +static void HookToDevice(ID3D12Device* InDevice) +{ + if (o_CreateSampler != nullptr || InDevice == nullptr) + return; + + LOG_FUNC(); + + // Get the vtable pointer + PVOID* pVTable = *(PVOID**)InDevice; + + // hudless + o_CreateSampler = (PFN_CreateSampler)pVTable[22]; + o_CreateRenderTargetView = (PFN_CreateRenderTargetView)pVTable[20]; + o_CreateDescriptorHeap = (PFN_CreateDescriptorHeap)pVTable[14]; + o_CopyDescriptors = (PFN_CopyDescriptors)pVTable[23]; + o_CopyDescriptorsSimple = (PFN_CopyDescriptorsSimple)pVTable[24]; + o_CreateShaderResourceView = (PFN_CreateShaderResourceView)pVTable[18]; + o_CreateUnorderedAccessView = (PFN_CreateUnorderedAccessView)pVTable[19]; + + // Apply the detour + if (o_CreateSampler != nullptr || o_CreateRenderTargetView != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_CreateDescriptorHeap != nullptr) + DetourAttach(&(PVOID&)o_CreateDescriptorHeap, hkCreateDescriptorHeap); + + if (o_CreateSampler != nullptr) + DetourAttach(&(PVOID&)o_CreateSampler, hkCreateSampler); + + if (Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true)) + { + if (o_CreateRenderTargetView != nullptr) + DetourAttach(&(PVOID&)o_CreateRenderTargetView, hkCreateRenderTargetView); + + if (o_CreateShaderResourceView != nullptr) + DetourAttach(&(PVOID&)o_CreateShaderResourceView, hkCreateShaderResourceView); + + if (o_CreateUnorderedAccessView != nullptr) + DetourAttach(&(PVOID&)o_CreateUnorderedAccessView, hkCreateUnorderedAccessView); + + if (o_CopyDescriptors != nullptr) + DetourAttach(&(PVOID&)o_CopyDescriptors, hkCopyDescriptors); + + if (o_CopyDescriptorsSimple != nullptr) + DetourAttach(&(PVOID&)o_CopyDescriptorsSimple, hkCopyDescriptorsSimple); + } + + DetourTransactionCommit(); + } + + if (Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true)) + HookCommandList(InDevice); +} + +static void HookToDevice(ID3D11Device* InDevice) +{ + if (o_CreateSamplerState != nullptr || InDevice == nullptr) + return; + + LOG_FUNC(); + + // Get the vtable pointer + PVOID* pVTable = *(PVOID**)InDevice; + + o_CreateSamplerState = (PFN_CreateSamplerState)pVTable[23]; + + // Apply the detour + if (o_CreateSamplerState != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_CreateSamplerState, hkCreateSamplerState); + + DetourTransactionCommit(); + } +} + +static HRESULT hkD3D11On12CreateDevice(IUnknown* pDevice, UINT Flags, D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, IUnknown** ppCommandQueues, + UINT NumQueues, UINT NodeMask, ID3D11Device** ppDevice, ID3D11DeviceContext** ppImmediateContext, D3D_FEATURE_LEVEL* pChosenFeatureLevel) +{ + LOG_FUNC(); + + bool rtss = false; + + // Assuming RTSS is creating a D3D11on12 device, not sure why but sometimes RTSS tries to create + // it's D3D11on12 device with old CommandQueue which results crash + // I am changing it's CommandQueue with current swapchain's command queue + if (HooksDx::GameCommandQueue != nullptr && *ppCommandQueues != HooksDx::GameCommandQueue && GetModuleHandle(L"RTSSHooks64.dll") != nullptr && pDevice == g_pd3dDeviceParam) + { + LOG_INFO("Replaced RTSS CommandQueue with correct one {0:X} -> {1:X}", (UINT64)*ppCommandQueues, (UINT64)HooksDx::GameCommandQueue); + *ppCommandQueues = HooksDx::GameCommandQueue; + rtss = true; + } + + auto result = o_D3D11On12CreateDevice(pDevice, Flags, pFeatureLevels, FeatureLevels, ppCommandQueues, NumQueues, NodeMask, ppDevice, ppImmediateContext, pChosenFeatureLevel); + + if (result == S_OK && *ppDevice != nullptr && !rtss && !_d3d12Captured) + { + LOG_INFO("Device captured, D3D11Device: {0:X}", (UINT64)*ppDevice); + d3d11on12Device = *ppDevice; + HookToDevice(d3d11on12Device); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D11CreateDevice(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, UINT SDKVersion, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) +{ + LOG_FUNC(); + + static const D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_11_1, + }; + + D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; + + for (UINT i = 0; i < FeatureLevels; ++i) + { + maxLevel = std::max(maxLevel, pFeatureLevels[i]); + } + + if (maxLevel == D3D_FEATURE_LEVEL_11_0) + { + LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); + pFeatureLevels = levels; + FeatureLevels = ARRAYSIZE(levels); + } + + auto result = o_D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); + + if (result == S_OK && *ppDevice != nullptr && !_d3d12Captured) + { + LOG_INFO("Device captured"); + d3d11Device = *ppDevice; + + HookToDevice(d3d11Device); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D11CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, + UINT FeatureLevels, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) +{ + LOG_FUNC(); + + static const D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_11_1, + }; + + D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; + + for (UINT i = 0; i < FeatureLevels; ++i) + { + maxLevel = std::max(maxLevel, pFeatureLevels[i]); + } + + if (maxLevel == D3D_FEATURE_LEVEL_11_0) + { + LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); + pFeatureLevels = levels; + FeatureLevels = ARRAYSIZE(levels); + } + + if (pSwapChainDesc != nullptr && pSwapChainDesc->BufferDesc.Height == 2 && pSwapChainDesc->BufferDesc.Width == 2) + { + LOG_WARN("RTSS call!"); + return o_D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + } + + IDXGISwapChain* buffer = nullptr; + auto result = o_D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, &buffer, ppDevice, pFeatureLevel, ppImmediateContext); + + if (result == S_OK && *ppDevice != nullptr && !_d3d12Captured) + { + LOG_INFO("Device captured"); + d3d11Device = *ppDevice; + + HookToDevice(d3d11Device); + + if (pSwapChainDesc != nullptr) + { + LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pSwapChainDesc->BufferDesc.Width, pSwapChainDesc->BufferDesc.Height, (UINT)pSwapChainDesc->BufferDesc.Format, pSwapChainDesc->BufferCount, pSwapChainDesc->Windowed); + + if (Util::GetProcessWindow() == pSwapChainDesc->OutputWindow) + { + Config::Instance()->ScreenWidth = pSwapChainDesc->BufferDesc.Width; + Config::Instance()->ScreenHeight = pSwapChainDesc->BufferDesc.Height; + } + + IDXGIFactory* factory = nullptr; + result = CreateDXGIFactory(IID_PPV_ARGS(&factory)); + if (result == S_OK) + { + LOG_DEBUG("creating new swapchain"); + result = factory->CreateSwapChain(*ppDevice, pSwapChainDesc, ppSwapChain); + + if (result == S_OK) + LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)d3d11Device); + else + LOG_DEBUG("factory->CreateSwapChain error: {0:X}", (UINT64)result); + + factory->Release(); + } + } + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static HRESULT hkD3D12CreateDevice(IDXGIAdapter* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice) +{ + LOG_FUNC(); + + auto result = o_D3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); + + if (result == S_OK && *ppDevice != nullptr) + { + LOG_DEBUG("Device captured: {0:X}", (size_t)*ppDevice); + g_pd3dDeviceParam = (ID3D12Device*)*ppDevice; + HookToDevice(g_pd3dDeviceParam); + _d3d12Captured = true; + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) +{ + if (pDesc == nullptr || device == nullptr) + return; + + D3D12_SAMPLER_DESC newDesc{}; + + newDesc.AddressU = pDesc->AddressU; + newDesc.AddressV = pDesc->AddressV; + newDesc.AddressW = pDesc->AddressW; + newDesc.BorderColor[0] = pDesc->BorderColor[0]; + newDesc.BorderColor[1] = pDesc->BorderColor[1]; + newDesc.BorderColor[2] = pDesc->BorderColor[2]; + newDesc.BorderColor[3] = pDesc->BorderColor[3]; + newDesc.ComparisonFunc = pDesc->ComparisonFunc; + + if (Config::Instance()->AnisotropyOverride.has_value() && + (pDesc->Filter == D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT || pDesc->Filter == D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT || + pDesc->Filter == D3D12_FILTER_MIN_MAG_MIP_LINEAR || pDesc->Filter == D3D12_FILTER_ANISOTROPIC)) + { + LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pDesc->Filter); + newDesc.Filter = D3D12_FILTER_ANISOTROPIC; + newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); + } + else + { + newDesc.Filter = pDesc->Filter; + newDesc.MaxAnisotropy = pDesc->MaxAnisotropy; + } + + newDesc.MaxLOD = pDesc->MaxLOD; + newDesc.MinLOD = pDesc->MinLOD; + newDesc.MipLODBias = pDesc->MipLODBias; + + if (newDesc.MipLODBias < 0.0f) + { + if (Config::Instance()->MipmapBiasOverride.has_value()) + { + LOG_INFO("Overriding mipmap bias {0} -> {1}", pDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); + newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); + } + + Config::Instance()->lastMipBias = newDesc.MipLODBias; + } + + return o_CreateSampler(device, &newDesc, DestDescriptor); +} + +static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) +{ + if (pSamplerDesc == nullptr || This == nullptr) + return E_INVALIDARG; + + if (_d3d12Captured) + return o_CreateSamplerState(This, pSamplerDesc, ppSamplerState); + + LOG_FUNC(); + + D3D11_SAMPLER_DESC newDesc{}; + + newDesc.AddressU = pSamplerDesc->AddressU; + newDesc.AddressV = pSamplerDesc->AddressV; + newDesc.AddressW = pSamplerDesc->AddressW; + newDesc.ComparisonFunc = pSamplerDesc->ComparisonFunc; + newDesc.BorderColor[0] = pSamplerDesc->BorderColor[0]; + newDesc.BorderColor[1] = pSamplerDesc->BorderColor[1]; + newDesc.BorderColor[2] = pSamplerDesc->BorderColor[2]; + newDesc.BorderColor[3] = pSamplerDesc->BorderColor[3]; + newDesc.MinLOD = pSamplerDesc->MinLOD; + newDesc.MaxLOD = pSamplerDesc->MaxLOD; + + if (Config::Instance()->AnisotropyOverride.has_value() && + (pSamplerDesc->Filter == D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT || + pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT || + pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_MIP_LINEAR || + pSamplerDesc->Filter == D3D11_FILTER_ANISOTROPIC)) + { + LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pSamplerDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pSamplerDesc->Filter); + newDesc.Filter = D3D11_FILTER_ANISOTROPIC; + newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); + } + else + { + newDesc.Filter = pSamplerDesc->Filter; + newDesc.MaxAnisotropy = pSamplerDesc->MaxAnisotropy; + } + + newDesc.MipLODBias = pSamplerDesc->MipLODBias; + + if (newDesc.MipLODBias < 0.0f) + { + if (Config::Instance()->MipmapBiasOverride.has_value()) + { + LOG_INFO("Overriding mipmap bias {0} -> {1}", pSamplerDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); + newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); + } + + Config::Instance()->lastMipBias = newDesc.MipLODBias; + } + + return o_CreateSamplerState(This, &newDesc, ppSamplerState); +} + +#pragma endregion + +void DeatachAllHooks() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_D3D11CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); + o_D3D11CreateDevice = nullptr; + } + + if (o_D3D11On12CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); + o_D3D11On12CreateDevice = nullptr; + } + + if (o_D3D12CreateDevice != nullptr) + { + DetourDetach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); + o_D3D12CreateDevice = nullptr; + } + + if (o_CreateDXGIFactory1 != nullptr) + { + DetourDetach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); + o_CreateDXGIFactory1 = nullptr; + } + + if (o_CreateDXGIFactory2 != nullptr) + { + DetourDetach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); + o_CreateDXGIFactory2 = nullptr; + } + + if (oCreateSwapChain != nullptr) + { + DetourDetach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); + oCreateSwapChain = nullptr; + } + + if (oCreateSwapChainForHwnd != nullptr) + { + DetourDetach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); + oCreateSwapChainForHwnd = nullptr; + } + + if (o_CreateSampler != nullptr) + { + DetourDetach(&(PVOID&)o_CreateSampler, hkCreateSampler); + o_CreateSampler = nullptr; + } + + DetourTransactionCommit(); +} + +void HooksDx::HookDx() +{ + if (_isInited) + return; + + o_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)DetourFindFunction("d3d12.dll", "D3D12CreateDevice"); + if (o_D3D12CreateDevice != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); + + DetourTransactionCommit(); + } + + o_D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11CreateDevice"); + o_D3D11CreateDeviceAndSwapChain = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)DetourFindFunction("d3d11.dll", "D3D11CreateDeviceAndSwapChain"); + o_D3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11On12CreateDevice"); + if (o_D3D11CreateDevice != nullptr || o_D3D11On12CreateDevice != nullptr || o_D3D11CreateDeviceAndSwapChain != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_D3D11CreateDevice != nullptr) + DetourAttach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); + + if (o_D3D11On12CreateDevice != nullptr) + DetourAttach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); + + if (o_D3D11CreateDeviceAndSwapChain != nullptr) + DetourAttach(&(PVOID&)o_D3D11CreateDeviceAndSwapChain, hkD3D11CreateDeviceAndSwapChain); + + DetourTransactionCommit(); + } + + o_CreateDXGIFactory = (PFN_CreateDXGIFactory)DetourFindFunction("dxgi.dll", "CreateDXGIFactory"); + o_CreateDXGIFactory1 = (PFN_CreateDXGIFactory1)DetourFindFunction("dxgi.dll", "CreateDXGIFactory1"); + o_CreateDXGIFactory2 = (PFN_CreateDXGIFactory2)DetourFindFunction("dxgi.dll", "CreateDXGIFactory2"); + + if (o_CreateDXGIFactory1 != nullptr) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_CreateDXGIFactory != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory, hkCreateDXGIFactory); + + if (o_CreateDXGIFactory1 != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); + + if (o_CreateDXGIFactory2 != nullptr) + DetourAttach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); + + DetourTransactionCommit(); + } + + LoadFSR31Funcs(); +} + +UINT HooksDx::ClearFrameResources() +{ + LOG_DEBUG_ONLY(" <-- {}", fgFrameIndex); + + fgFrameIndex = (fgFrameIndex + 1) % FG_BUFFER_SIZE; + + LOG_DEBUG_ONLY(" <-- {}", fgFrameIndex); + fgUpscaledFound = false; + + return fgFrameIndex; +} + +UINT HooksDx::GetFrame() +{ + return fgFrameIndex; +} + +void HooksDx::NewFrame() +{ + auto fIndex = fgFrameIndex; + auto newIndex = (fIndex + 2) % FG_BUFFER_SIZE; + + { + fgCopySource[newIndex] = nullptr; + } + + if (fgPossibleHudless[newIndex].size() != 0) + { + std::unique_lock lock(hudlessMutex[newIndex]); + fgPossibleHudless[newIndex].clear(); + } + + if (HooksDx::fgHUDlessCaptureCounter[newIndex] != 0) + { + std::unique_lock lock(counterMutex[newIndex]); + HooksDx::fgHUDlessCaptureCounter[newIndex] = 0; + } +} + +void HooksDx::UnHookDx() +{ + DeatachAllHooks(); + _isInited = false; +} + +void HooksDx::ReleaseFGObjects() +{ + for (size_t i = 0; i < 4; i++) + { + if (HooksDx::fgCopyCommandAllocators[i] != nullptr) + { + HooksDx::fgCopyCommandAllocators[i]->Release(); + HooksDx::fgCopyCommandAllocators[i] = nullptr; + } + } + + if (HooksDx::fgCopyCommandList != nullptr) + { + HooksDx::fgCopyCommandList->Release(); + HooksDx::fgCopyCommandList = nullptr; + } + + if (HooksDx::fgCopyCommandQueue != nullptr) + { + HooksDx::fgCopyCommandQueue->Release(); + HooksDx::fgCopyCommandQueue = nullptr; + } + + if (HooksDx::fgFormatTransfer != nullptr) + { + delete HooksDx::fgFormatTransfer; + HooksDx::fgFormatTransfer = nullptr; + } +} + +void HooksDx::CreateFGObjects(ID3D12Device* InDevice) +{ + if (HooksDx::fgCopyCommandQueue != nullptr) + return; + + do + { + HRESULT result; + + for (size_t i = 0; i < 4; i++) + { + result = InDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&HooksDx::fgCopyCommandAllocators[i])); + if (result != S_OK) + { + LOG_ERROR("CreateCommandAllocators[{0}]: {1:X}", i, (unsigned long)result); + break; + } + HooksDx::fgCopyCommandAllocators[i]->SetName(L"fgCopyCommandAllocator"); + } + + result = InDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, HooksDx::fgCopyCommandAllocators[0], NULL, IID_PPV_ARGS(&HooksDx::fgCopyCommandList)); + if (result != S_OK) + { + LOG_ERROR("CreateCommandList: {0:X}", (unsigned long)result); + break; + } + HooksDx::fgCopyCommandList->SetName(L"fgCopyCommandList"); + + result = HooksDx::fgCopyCommandList->Close(); + if (result != S_OK) + { + LOG_ERROR("HooksDx::fgCopyCommandList->Close: {0:X}", (unsigned long)result); + break; + } + + // Create a command queue for frame generation + D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}; + copyQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + copyQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + copyQueueDesc.NodeMask = 0; + + if (Config::Instance()->FGHighPriority.value_or(false)) + copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH; + else + copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + + HRESULT hr = InDevice->CreateCommandQueue(©QueueDesc, IID_PPV_ARGS(&HooksDx::fgCopyCommandQueue)); + if (result != S_OK) + { + LOG_ERROR("CreateCommandQueue: {0:X}", (unsigned long)result); + break; + } + HooksDx::fgCopyCommandQueue->SetName(L"fgCopyCommandQueue"); + + HooksDx::fgFormatTransfer = new FT_Dx12("FormatTransfer", InDevice, HooksDx::swapchainFormat); + + } while (false); +} + +void HooksDx::CreateFGContext(ID3D12Device* InDevice, IFeature* deviceContext) +{ + if (HooksDx::fgContext != nullptr) + { + ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; + m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; + m_FrameGenerationConfig.frameGenerationEnabled = true; + m_FrameGenerationConfig.swapChain = HooksDx::currentSwapchain; + //m_FrameGenerationConfig.presentCallback = nullptr; + m_FrameGenerationConfig.HUDLessColor = FfxApiResource({}); + + auto result = _configure(&HooksDx::fgContext, &m_FrameGenerationConfig.header); + + HooksDx::fgIsActive = (result == FFX_API_RETURN_OK); + + LOG_DEBUG("Reactivate"); + + return; + } + + ffxCreateBackendDX12Desc backendDesc{}; + backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12; + backendDesc.device = InDevice; + + ffxCreateContextDescFrameGeneration createFg{}; + createFg.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATION; + createFg.displaySize = { deviceContext->DisplayWidth(), deviceContext->DisplayHeight() }; + createFg.maxRenderSize = { deviceContext->DisplayWidth(), deviceContext->DisplayHeight() }; + createFg.flags = 0; + + if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_IsHDR) + createFg.flags |= FFX_FRAMEGENERATION_ENABLE_HIGH_DYNAMIC_RANGE; + + if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_DepthInverted) + createFg.flags |= FFX_FRAMEGENERATION_ENABLE_DEPTH_INVERTED; + + if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_MVJittered) + createFg.flags |= FFX_FRAMEGENERATION_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; + + if ((deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_MVLowRes) == 0) + createFg.flags |= FFX_FRAMEGENERATION_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS; + + if (Config::Instance()->FGAsync.value_or(false)) + createFg.flags |= FFX_FRAMEGENERATION_ENABLE_ASYNC_WORKLOAD_SUPPORT; + + createFg.backBufferFormat = ffxApiGetSurfaceFormatDX12(HooksDx::swapchainFormat); + createFg.header.pNext = &backendDesc.header; + + Config::Instance()->dxgiSkipSpoofing = true; + Config::Instance()->SkipHeapCapture = true; + ffxReturnCode_t retCode = _createContext(&HooksDx::fgContext, &createFg.header, nullptr); + Config::Instance()->SkipHeapCapture = false; + Config::Instance()->dxgiSkipSpoofing = false; + LOG_INFO("_createContext result: {0:X}", retCode); + + HooksDx::fgIsActive = (retCode == FFX_API_RETURN_OK); + + LOG_DEBUG("Create"); +} + +void HooksDx::StopAndDestroyFGContext(bool destroy, bool shutDown) +{ + HooksDx::fgSkipHudlessChecks = false; + Config::Instance()->dxgiSkipSpoofing = true; + + if (HooksDx::fgContext != nullptr) + { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + + ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; + m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; + m_FrameGenerationConfig.frameGenerationEnabled = false; + m_FrameGenerationConfig.swapChain = HooksDx::currentSwapchain; + m_FrameGenerationConfig.presentCallback = nullptr; + m_FrameGenerationConfig.HUDLessColor = FfxApiResource({}); + + auto result = _configure(&HooksDx::fgContext, &m_FrameGenerationConfig.header); + + HooksDx::fgIsActive = false; + + if (!shutDown) + LOG_INFO(" FG _configure result: {0:X}", result); + } + + if (destroy && HooksDx::fgContext != nullptr) + { + auto result = _destroyContext(&HooksDx::fgContext, nullptr); + + if (!shutDown) + LOG_INFO(" FG _destroyContext result: {0:X}", result); + + HooksDx::fgContext = nullptr; + } + + Config::Instance()->dxgiSkipSpoofing = false; + + if (shutDown) + ReleaseFGObjects(); +} diff --git a/OptiScaler/hooks/HooksDx.h b/OptiScaler/hooks/HooksDx.h new file mode 100644 index 00000000..7d07fa47 --- /dev/null +++ b/OptiScaler/hooks/HooksDx.h @@ -0,0 +1,68 @@ +#pragma once + +#include "../pch.h" +#include "../format_transfer/FT_Dx12.h" +#include "../backends/IFeature.h" + + +#include +#include +#include + +#include +#include +#include + +namespace HooksDx +{ + inline ID3D12QueryHeap* queryHeap = nullptr; + inline ID3D12Resource* readbackBuffer = nullptr; + inline bool dx12UpscaleTrig = false; + + inline const int QUERY_BUFFER_COUNT = 3; + inline ID3D11Query* disjointQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline ID3D11Query* startQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline ID3D11Query* endQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; + inline bool dx11UpscaleTrig[QUERY_BUFFER_COUNT] = { false, false, false }; + + inline ID3D12CommandQueue* GameCommandQueue = nullptr; + + inline int currentFrameIndex = 0; + inline int previousFrameIndex = 0; + + inline IDXGISwapChain* currentSwapchain = nullptr; + inline DXGI_FORMAT swapchainFormat = DXGI_FORMAT_UNKNOWN; + + inline ffxContext fgSwapChainContext = nullptr; + inline ffxContext fgContext = nullptr; + inline float jitterX = 0.0; + inline float jitterY = 0.0; + inline float mvScaleX = 0.0; + inline float mvScaleY = 0.0; + inline const int FG_BUFFER_SIZE = 4; + inline ID3D12Resource* paramVelocity[FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; + inline ID3D12Resource* paramDepth[FG_BUFFER_SIZE] = { nullptr, nullptr,nullptr, nullptr }; + inline UINT64 fgHUDlessCaptureCounter[FG_BUFFER_SIZE] = { 0,0,0,0 }; + inline bool upscaleRan = false; + inline bool fgSkipHudlessChecks = false; + inline double fgFrameTime = 0.0; + inline ID3D12CommandQueue* fgCommandQueue = nullptr; + inline ID3D12CommandQueue* gameCommandQueue = nullptr; + inline ID3D12CommandQueue* fgCopyCommandQueue = nullptr; + inline ID3D12GraphicsCommandList* fgCopyCommandList = nullptr; + inline ID3D12CommandAllocator* fgCopyCommandAllocators[FG_BUFFER_SIZE] = { }; + inline UINT64 fgTarget = 10; + inline ID3D12Resource* fgUpscaledImage[FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; + inline FT_Dx12* fgFormatTransfer = nullptr; + inline bool fgIsActive = false; + + void UnHookDx(); + void HookDx(); + UINT ClearFrameResources(); + UINT GetFrame(); + void NewFrame(); + void ReleaseFGObjects(); + void CreateFGObjects(ID3D12Device* InDevice); + void CreateFGContext(ID3D12Device* InDevice, IFeature* deviceContext); + void StopAndDestroyFGContext(bool destroy, bool shutDown); +} diff --git a/OptiScaler/hooks/HooksVk.cpp b/OptiScaler/hooks/HooksVk.cpp new file mode 100644 index 00000000..40a1ccf9 --- /dev/null +++ b/OptiScaler/hooks/HooksVk.cpp @@ -0,0 +1,245 @@ +#include "HooksVk.h" + +#include "../Util.h" +#include "../Config.h" + +#include "../imgui/imgui_overlay_vk.h" + +#include "../detours/detours.h" + +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkFlags flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +static bool _isInited = false; + +// for menu rendering +static VkDevice _device = VK_NULL_HANDLE; +static VkInstance _instance = VK_NULL_HANDLE; +static VkPhysicalDevice _PD = VK_NULL_HANDLE; +static HWND _hwnd = nullptr; + +static std::mutex _vkPresentMutex; + +// hooking +typedef VkResult(*PFN_QueuePresentKHR)(VkQueue, const VkPresentInfoKHR*); +typedef VkResult(*PFN_CreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*); +typedef VkResult(*PFN_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*); + +PFN_vkCreateDevice o_vkCreateDevice = nullptr; +PFN_vkCreateInstance o_vkCreateInstance = nullptr; +PFN_vkCreateWin32SurfaceKHR o_vkCreateWin32SurfaceKHR = nullptr; +PFN_QueuePresentKHR o_QueuePresentKHR = nullptr; +PFN_CreateSwapchainKHR o_CreateSwapchainKHR = nullptr; + +static VkResult hkvkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); +static VkResult hkvkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo); +static VkResult hkvkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); + +static void HookDevice(VkDevice InDevice) +{ + if (o_CreateSwapchainKHR != nullptr || Config::Instance()->VulkanSkipHooks) + return; + + LOG_FUNC(); + + o_QueuePresentKHR = (PFN_QueuePresentKHR)(vkGetDeviceProcAddr(InDevice, "vkQueuePresentKHR")); + o_CreateSwapchainKHR = (PFN_CreateSwapchainKHR)(vkGetDeviceProcAddr(InDevice, "vkCreateSwapchainKHR")); + + if (o_CreateSwapchainKHR) + { + LOG_DEBUG("Hooking VkDevice"); + + // Hook + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)o_QueuePresentKHR, hkvkQueuePresentKHR); + DetourAttach(&(PVOID&)o_CreateSwapchainKHR, hkvkCreateSwapchainKHR); + + DetourTransactionCommit(); + } +} + +static VkResult hkvkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) +{ + LOG_FUNC(); + + auto result = o_vkCreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); + + auto procHwnd = Util::GetProcessWindow(); + LOG_DEBUG("procHwnd: {0:X}, swapchain hwnd: {1:X}", (UINT64)procHwnd, (UINT64)pCreateInfo->hwnd); + + if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks && procHwnd == pCreateInfo->hwnd) + { + ImGuiOverlayVk::DestroyVulkanObjects(false); + + _instance = instance; + LOG_DEBUG("_instance captured: {0:X}", (UINT64)_instance); + _hwnd = pCreateInfo->hwnd; + LOG_DEBUG("_hwnd captured: {0:X}", (UINT64)_hwnd); + } + + LOG_FUNC_RESULT(result); + + return result; + +} + +static VkResult hkvkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) +{ + LOG_FUNC(); + + auto result = o_vkCreateInstance(pCreateInfo, pAllocator, pInstance); + + if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks) + { + ImGuiOverlayVk::DestroyVulkanObjects(false); + + _instance = *pInstance; + LOG_DEBUG("_instance captured: {0:X}", (UINT64)_instance); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static VkResult hkvkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) +{ + LOG_FUNC(); + + auto result = o_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); + + if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks) + { + ImGuiOverlayVk::DestroyVulkanObjects(false); + + _PD = physicalDevice; + LOG_DEBUG("_PD captured: {0:X}", (UINT64)_PD); + _device = *pDevice; + LOG_DEBUG("_device captured: {0:X}", (UINT64)_device); + HookDevice(_device); + } + + LOG_FUNC_RESULT(result); + + return result; +} + +static VkResult hkvkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo) +{ + LOG_FUNC(); + + // get upscaler time + if (HooksVk::vkUpscaleTrig && HooksVk::queryPool != VK_NULL_HANDLE) + { + // Retrieve timestamps + uint64_t timestamps[2]; + vkGetQueryPoolResults(_device, HooksVk::queryPool, 0, 2, sizeof(timestamps), timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + + // Calculate elapsed time in milliseconds + double elapsedTimeMs = (timestamps[1] - timestamps[0]) * HooksVk::timeStampPeriod / 1e6; + + if (elapsedTimeMs > 0.0 && elapsedTimeMs < 5000.0) + { + Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); + Config::Instance()->upscaleTimes.pop_front(); + } + + HooksVk::vkUpscaleTrig = false; + } + + // render menu if needed + if(!ImGuiOverlayVk::QueuePresent(queue, pPresentInfo)) + return VK_ERROR_OUT_OF_DATE_KHR; + + // original call + Config::Instance()->VulkanCreatingSC = true; + auto result = o_QueuePresentKHR(queue, pPresentInfo); + Config::Instance()->VulkanCreatingSC = false; + + LOG_FUNC_RESULT(result); + return result; +} + +static VkResult hkvkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) +{ + LOG_FUNC(); + + Config::Instance()->VulkanCreatingSC = true; + auto result = o_CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); + Config::Instance()->VulkanCreatingSC = false; + + if (result == VK_SUCCESS && device != VK_NULL_HANDLE && pCreateInfo != nullptr && *pSwapchain != VK_NULL_HANDLE && !Config::Instance()->VulkanSkipHooks) + { + Config::Instance()->ScreenWidth = pCreateInfo->imageExtent.width; + Config::Instance()->ScreenHeight = pCreateInfo->imageExtent.height; + + LOG_DEBUG("if (result == VK_SUCCESS && device != VK_NULL_HANDLE && pCreateInfo != nullptr && pSwapchain != VK_NULL_HANDLE)"); + + _device = device; + LOG_DEBUG("_device captured: {0:X}", (UINT64)_device); + + ImGuiOverlayVk::CreateSwapchain(device, _PD, _instance, _hwnd, pCreateInfo, pAllocator, pSwapchain); + } + + LOG_FUNC_RESULT(result); + return result; +} + +void HooksVk::HookVk() +{ + if (o_vkCreateDevice != nullptr) + return; + + o_vkCreateDevice = (PFN_vkCreateDevice)DetourFindFunction("vulkan-1.dll", "vkCreateDevice"); + o_vkCreateInstance = (PFN_vkCreateInstance)DetourFindFunction("vulkan-1.dll", "vkCreateInstance"); + o_vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)DetourFindFunction("vulkan-1.dll", "vkCreateWin32SurfaceKHR"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_vkCreateDevice != nullptr) + DetourAttach(&(PVOID&)o_vkCreateDevice, hkvkCreateDevice); + + if (o_vkCreateInstance != nullptr) + DetourAttach(&(PVOID&)o_vkCreateInstance, hkvkCreateInstance); + + if (o_vkCreateWin32SurfaceKHR != nullptr) + DetourAttach(&(PVOID&)o_vkCreateWin32SurfaceKHR, hkvkCreateWin32SurfaceKHR); + + DetourTransactionCommit(); +} + +void HooksVk::UnHookVk() +{ + if (_isInited) + { + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_QueuePresentKHR != nullptr) + DetourDetach(&(PVOID&)o_QueuePresentKHR, hkvkQueuePresentKHR); + + if (o_CreateSwapchainKHR != nullptr) + DetourDetach(&(PVOID&)o_CreateSwapchainKHR, hkvkCreateSwapchainKHR); + + if (o_vkCreateDevice != nullptr) + DetourDetach(&(PVOID&)o_vkCreateDevice, hkvkCreateDevice); + + if (o_vkCreateInstance != nullptr) + DetourDetach(&(PVOID&)o_vkCreateInstance, hkvkCreateInstance); + + if (o_vkCreateWin32SurfaceKHR != nullptr) + DetourDetach(&(PVOID&)o_vkCreateWin32SurfaceKHR, hkvkCreateWin32SurfaceKHR); + + DetourTransactionCommit(); + } + + _isInited = false; +} diff --git a/OptiScaler/hooks/HooksVk.h b/OptiScaler/hooks/HooksVk.h new file mode 100644 index 00000000..dd45d3a3 --- /dev/null +++ b/OptiScaler/hooks/HooksVk.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../pch.h" +#include + +namespace HooksVk +{ + inline VkQueryPool queryPool = VK_NULL_HANDLE; + inline double timeStampPeriod = 1.0; + inline bool vkUpscaleTrig = false; + + void HookVk(); + void UnHookVk(); +} diff --git a/OptiScaler/imgui/wrapped_swapchain.cpp b/OptiScaler/hooks/wrapped_swapchain.cpp similarity index 99% rename from OptiScaler/imgui/wrapped_swapchain.cpp rename to OptiScaler/hooks/wrapped_swapchain.cpp index 46dca068..0a7a89ec 100644 --- a/OptiScaler/imgui/wrapped_swapchain.cpp +++ b/OptiScaler/hooks/wrapped_swapchain.cpp @@ -1,5 +1,5 @@ #include "wrapped_swapchain.h" -#include + #include "../Config.h" #include "../Util.h" diff --git a/OptiScaler/imgui/wrapped_swapchain.h b/OptiScaler/hooks/wrapped_swapchain.h similarity index 99% rename from OptiScaler/imgui/wrapped_swapchain.h rename to OptiScaler/hooks/wrapped_swapchain.h index dedd0af6..d65b2504 100644 --- a/OptiScaler/imgui/wrapped_swapchain.h +++ b/OptiScaler/hooks/wrapped_swapchain.h @@ -1,7 +1,6 @@ //#pragma once #include "../pch.h" #include "dxgi1_6.h" -#include "imgui_overlay_base.h" typedef HRESULT(*PFN_SC_Present)(IDXGISwapChain*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*, IUnknown*, HWND); typedef void(*PFN_SC_Clean)(bool, HWND); diff --git a/OptiScaler/imgui/imgui_overlay_base.h b/OptiScaler/imgui/imgui_overlay_base.h index 0abaefb1..72d47773 100644 --- a/OptiScaler/imgui/imgui_overlay_base.h +++ b/OptiScaler/imgui/imgui_overlay_base.h @@ -8,14 +8,14 @@ // LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -typedef HRESULT(__fastcall* PFN_Present)(IDXGISwapChain*, UINT, UINT); -typedef HRESULT(__fastcall* PFN_Present1)(IDXGISwapChain1*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*); -typedef HRESULT(__fastcall* PFN_ResizeBuffers)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT); -typedef HRESULT(__fastcall* PFN_ResizeBuffers1)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT, const UINT*, IUnknown* const*); -typedef HRESULT(__fastcall* PFN_CreateSwapChain)(IDXGIFactory*, IUnknown*, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**); -typedef HRESULT(__fastcall* PFN_CreateSwapChainForHwnd)(IDXGIFactory*, IUnknown*, HWND, const DXGI_SWAP_CHAIN_DESC1*, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC*, IDXGIOutput*, IDXGISwapChain1**); -typedef HRESULT(__fastcall* PFN_CreateSwapChainForCoreWindow)(IDXGIFactory*, IUnknown*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**); -typedef HRESULT(__fastcall* PFN_CreateSwapChainForComposition)(IDXGIFactory*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**); +//typedef HRESULT(__fastcall* PFN_Present)(IDXGISwapChain*, UINT, UINT); +//typedef HRESULT(__fastcall* PFN_Present1)(IDXGISwapChain1*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*); +//typedef HRESULT(__fastcall* PFN_ResizeBuffers)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT); +//typedef HRESULT(__fastcall* PFN_ResizeBuffers1)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT, const UINT*, IUnknown* const*); +//typedef HRESULT(__fastcall* PFN_CreateSwapChain)(IDXGIFactory*, IUnknown*, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**); +//typedef HRESULT(__fastcall* PFN_CreateSwapChainForHwnd)(IDXGIFactory*, IUnknown*, HWND, const DXGI_SWAP_CHAIN_DESC1*, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC*, IDXGIOutput*, IDXGISwapChain1**); +//typedef HRESULT(__fastcall* PFN_CreateSwapChainForCoreWindow)(IDXGIFactory*, IUnknown*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**); +//typedef HRESULT(__fastcall* PFN_CreateSwapChainForComposition)(IDXGIFactory*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**); class ImGuiOverlayBase { diff --git a/OptiScaler/imgui/imgui_overlay_dx.cpp b/OptiScaler/imgui/imgui_overlay_dx.cpp index d1bdc929..4709fb8d 100644 --- a/OptiScaler/imgui/imgui_overlay_dx.cpp +++ b/OptiScaler/imgui/imgui_overlay_dx.cpp @@ -9,249 +9,6 @@ #include "imgui/imgui_impl_dx12.h" #include "imgui/imgui_impl_win32.h" -#include "../detours/detours.h" -#include - -#include "wrapped_swapchain.h" - -#pragma region FG definitions - -#include -#include - -// #define USE_RESOURCE_DISCARD -// #define USE_COPY_RESOURCE -#define USE_RESOURCE_BARRIRER - -enum ResourceType -{ - SRV, - RTV, - UAV -}; - -typedef struct SwapChainInfo -{ - IDXGISwapChain* swapChain = nullptr; - DXGI_FORMAT swapChainFormat = DXGI_FORMAT_UNKNOWN; - int swapChainBufferCount = 0; - ID3D12CommandQueue* fgCommandQueue = nullptr; - ID3D12CommandQueue* gameCommandQueue = nullptr; -}; - -typedef struct ResourceInfo -{ - ID3D12Resource* buffer = nullptr; - UINT64 width = 0; - UINT height = 0; - DXGI_FORMAT format; - D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON; - ResourceType type = SRV; -} resource_info; - -typedef struct HeapInfo -{ - SIZE_T cpuStart = NULL; - SIZE_T cpuEnd = NULL; - SIZE_T gpuStart = NULL; - SIZE_T gpuEnd = NULL; - UINT numDescriptors = 0; - UINT increment = 0; - UINT type = 0; - std::shared_ptr info; - - HeapInfo(SIZE_T cpuStart, SIZE_T cpuEnd, SIZE_T gpuStart, SIZE_T gpuEnd, UINT numResources, UINT increment, UINT type) - : cpuStart(cpuStart), cpuEnd(cpuEnd), gpuStart(gpuStart), gpuEnd(gpuEnd), numDescriptors(numResources), increment(increment), info(new ResourceInfo[numResources]), type(type) {} - - ResourceInfo* GetByCpuHandle(SIZE_T cpuHandle) - { - if (cpuStart > cpuHandle || cpuEnd < cpuHandle) - return nullptr; - - auto index = (cpuHandle - cpuStart) / increment; - - return &info[index]; - } - - ResourceInfo* GetByGpuHandle(SIZE_T gpuHandle) - { - if (gpuStart > gpuHandle || gpuEnd < gpuHandle) - return nullptr; - - auto index = (gpuHandle - gpuStart) / increment; - - return &info[index]; - } - - void SetByCpuHandle(SIZE_T cpuHandle, ResourceInfo setInfo) - { - if (cpuStart > cpuHandle || cpuEnd < cpuHandle) - return; - - auto index = (cpuHandle - cpuStart) / increment; - - info[index] = setInfo; - } - - void SetByGpuHandle(SIZE_T gpuHandle, ResourceInfo setInfo) - { - if (gpuStart > gpuHandle || gpuEnd < gpuHandle) - return; - - auto index = (gpuHandle - gpuStart) / increment; - - info[index] = setInfo; - } -} heap_info; - -typedef struct ResourceHeapInfo -{ - SIZE_T cpuStart = NULL; - SIZE_T gpuStart = NULL; -} resource_heap_info; - -// Device hooks for FG -typedef void(*PFN_CreateRenderTargetView)(ID3D12Device* This, ID3D12Resource* pResource, const D3D12_RENDER_TARGET_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); -typedef void(*PFN_CreateShaderResourceView)(ID3D12Device* This, ID3D12Resource* pResource, D3D12_SHADER_RESOURCE_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); -typedef void(*PFN_CreateUnorderedAccessView)(ID3D12Device* This, ID3D12Resource* pResource, ID3D12Resource* pCounterResource, D3D12_UNORDERED_ACCESS_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); -typedef HRESULT(*PFN_CreateDescriptorHeap)(ID3D12Device* This, D3D12_DESCRIPTOR_HEAP_DESC* pDescriptorHeapDesc, REFIID riid, void** ppvHeap); -typedef void(*PFN_CopyDescriptors)(ID3D12Device* This, UINT NumDestDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pDestDescriptorRangeStarts, UINT* pDestDescriptorRangeSizes, UINT NumSrcDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pSrcDescriptorRangeStarts, UINT* pSrcDescriptorRangeSizes, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType); -typedef void(*PFN_CopyDescriptorsSimple)(ID3D12Device* This, UINT NumDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart, D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType); - -// Command list hooks for FG -typedef void(*PFN_OMSetRenderTargets)(ID3D12GraphicsCommandList* This, UINT NumRenderTargetDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, BOOL RTsSingleHandleToDescriptorRange, D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor); -typedef void(*PFN_DrawIndexedInstanced)(ID3D12GraphicsCommandList* This, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation); -typedef void(*PFN_DrawInstanced)(ID3D12GraphicsCommandList* This, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation); -typedef void(*PFN_CopyResource)(ID3D12GraphicsCommandList* This, ID3D12Resource* pDstResource, ID3D12Resource* pSrcResource); -typedef void(*PFN_CopyTextureRegion)(ID3D12GraphicsCommandList* This, D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, UINT DstY, UINT DstZ, D3D12_TEXTURE_COPY_LOCATION* pSrc, D3D12_BOX* pSrcBox); -typedef void(*PFN_SetGraphicsRootDescriptorTable)(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); -typedef void(*PFN_SetComputeRootDescriptorTable)(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor); -typedef void(*PFN_Dispatch)(ID3D12GraphicsCommandList* This, UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ); -typedef void(*PFN_DiscardResource)(ID3D12GraphicsCommandList* This, ID3D12Resource* pResource, D3D12_DISCARD_REGION* pRegion); - -// Original method calls for device -static PFN_CreateRenderTargetView o_CreateRenderTargetView = nullptr; -static PFN_CreateShaderResourceView o_CreateShaderResourceView = nullptr; -static PFN_CreateUnorderedAccessView o_CreateUnorderedAccessView = nullptr; -static PFN_CreateDescriptorHeap o_CreateDescriptorHeap = nullptr; -static PFN_CopyDescriptors o_CopyDescriptors = nullptr; -static PFN_CopyDescriptorsSimple o_CopyDescriptorsSimple = nullptr; - -// Original method calls for command list -static PFN_OMSetRenderTargets o_OMSetRenderTargets = nullptr; -static PFN_DrawInstanced o_DrawInstanced = nullptr; -static PFN_DrawIndexedInstanced o_DrawIndexedInstanced = nullptr; -#ifdef USE_COPY_RESOURCE -static PFN_CopyResource o_CopyResource = nullptr; -#endif -static PFN_CopyTextureRegion o_CopyTextureRegion = nullptr; -static PFN_SetGraphicsRootDescriptorTable o_SetGraphicsRootDescriptorTable = nullptr; -static PFN_SetComputeRootDescriptorTable o_SetComputeRootDescriptorTable = nullptr; -static PFN_Dispatch o_Dispatch = nullptr; -#ifdef USE_RESOURCE_DISCARD -static PFN_DiscardResource o_DiscardResource = nullptr; -#endif - -// FSR 3.x methods -static PfnFfxCreateContext _createContext = nullptr; -static PfnFfxDestroyContext _destroyContext = nullptr; -static PfnFfxConfigure _configure = nullptr; -static PfnFfxQuery _query = nullptr; -static PfnFfxDispatch _dispatch = nullptr; - -// swapchains variables -static ankerl::unordered_dense::map fgSwapChains; -static bool fgSkipSCWrapping = false; -static DXGI_SWAP_CHAIN_DESC fgScDesc{}; - -// queues -static std::vector fgQueues; - -// heaps -static std::vector fgHeaps; - -#ifdef USE_RESOURCE_DISCARD -// created resources -static ankerl::unordered_dense::map fgHandlesByResources; -#endif - -// possibleHudless lisy by cmdlist -static ankerl::unordered_dense::map > fgPossibleHudless[ImGuiOverlayDx::FG_BUFFER_SIZE]; - -// mutexes -static std::shared_mutex heapMutex; -static std::shared_mutex resourceMutex; -static std::shared_mutex hudlessMutex[ImGuiOverlayDx::FG_BUFFER_SIZE]; -static std::shared_mutex counterMutex[ImGuiOverlayDx::FG_BUFFER_SIZE]; - -// found hudless info -static ID3D12Resource* fgCopySource[ImGuiOverlayDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; -static ID3D12Resource* fgHudless[ImGuiOverlayDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; -static ID3D12Resource* fgHudlessBuffer[ImGuiOverlayDx::FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; - -static UINT fgFrameIndex = 0; - -// Last captured upscaled hudless frame number -static UINT64 fgHudlessFrame = 0; -static UINT64 fgPresentedFrame = 0; -static bool fgPresentRunning = false; - -// Used for frametime calculation -static double fgLastFrameTime = 0.0; -static double fgLastDeltaTime = 0.0; -static bool fgDispatchCalled = false; -static bool fgStopAfterNextPresent = false; - -// Swapchain frame counter -static UINT64 frameCounter = 0; - -// Swapchain frame target while capturing RTVs etc -static UINT64 fgLastFGFrame = 0; -static bool fgUpscaledFound = false; - -#pragma endregion - -// dxgi stuff -typedef HRESULT(*PFN_CreateDXGIFactory)(REFIID riid, IDXGIFactory** ppFactory); -typedef HRESULT(*PFN_CreateDXGIFactory1)(REFIID riid, IDXGIFactory1** ppFactory); -typedef HRESULT(*PFN_CreateDXGIFactory2)(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory); - -typedef HRESULT(*PFN_EnumAdapterByGpuPreference2)(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); -typedef HRESULT(*PFN_EnumAdapterByLuid2)(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); -typedef HRESULT(*PFN_EnumAdapters12)(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); -typedef HRESULT(*PFN_EnumAdapters2)(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); - -static PFN_CreateDXGIFactory o_CreateDXGIFactory = nullptr; -static PFN_CreateDXGIFactory1 o_CreateDXGIFactory1 = nullptr; -static PFN_CreateDXGIFactory2 o_CreateDXGIFactory2 = nullptr; - -inline static PFN_EnumAdapters2 ptrEnumAdapters = nullptr; -inline static PFN_EnumAdapters12 ptrEnumAdapters1 = nullptr; -inline static PFN_EnumAdapterByLuid2 ptrEnumAdapterByLuid = nullptr; -inline static PFN_EnumAdapterByGpuPreference2 ptrEnumAdapterByGpuPreference = nullptr; -inline static PFN_Present o_Present = nullptr; -inline static PFN_Present1 o_Present1 = nullptr; - -static PFN_CreateSwapChain oCreateSwapChain = nullptr; -static PFN_CreateSwapChainForHwnd oCreateSwapChainForHwnd = nullptr; - -// DirectX -typedef void(*PFN_CreateSampler)(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); -typedef HRESULT(*PFN_CreateSamplerState)(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); - -static PFN_D3D12_CREATE_DEVICE o_D3D12CreateDevice = nullptr; -static PFN_CreateSampler o_CreateSampler = nullptr; - -static PFN_D3D11_CREATE_DEVICE o_D3D11CreateDevice = nullptr; -static PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN o_D3D11CreateDeviceAndSwapChain = nullptr; -static PFN_CreateSamplerState o_CreateSamplerState = nullptr; -static PFN_D3D11ON12_CREATE_DEVICE o_D3D11On12CreateDevice = nullptr; -static ID3D11Device* d3d11Device = nullptr; -static ID3D11Device* d3d11on12Device = nullptr; - -// current command queue for dx12 swapchain -static IUnknown* currentSCCommandQueue = nullptr; - // menu static int const NUM_BACK_BUFFERS = 8; static bool _dx11Device = false; @@ -272,6 +29,9 @@ static ID3D12CommandAllocator* g_commandAllocators[NUM_BACK_BUFFERS] = { }; static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = { }; static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = { }; +// current command queue for dx12 swapchain +static IUnknown* currentSCCommandQueue = nullptr; + // status static bool _isInited = false; static bool _d3d12Captured = false; @@ -283,1119 +43,6 @@ static bool _showRenderImGuiDebugOnce = true; static std::mutex _dx11CleanMutex; static std::mutex _dx12CleanMutex; -static void RenderImGui_DX11(IDXGISwapChain* pSwapChain); -static void RenderImGui_DX12(IDXGISwapChain* pSwapChain); -static void DeatachAllHooks(); -static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor); -static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState); -static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter); -static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter); -static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter); -static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter); - -static void LoadFSR31Funcs() -{ - - ID3D12Resource* textureResource; - ID3D12DescriptorHeap* srvHeap; - D3D12_GPU_DESCRIPTOR_HANDLE srvGpuHandle; - - LOG_DEBUG("Loading amd_fidelityfx_dx12.dll methods"); - - auto file = Util::DllPath().parent_path() / "amd_fidelityfx_dx12.dll"; - LOG_INFO("Trying to load {}", file.string()); - - auto _dll = LoadLibrary(file.wstring().c_str()); - if (_dll != nullptr) - { - _configure = (PfnFfxConfigure)GetProcAddress(_dll, "ffxConfigure"); - _createContext = (PfnFfxCreateContext)GetProcAddress(_dll, "ffxCreateContext"); - _destroyContext = (PfnFfxDestroyContext)GetProcAddress(_dll, "ffxDestroyContext"); - _dispatch = (PfnFfxDispatch)GetProcAddress(_dll, "ffxDispatch"); - _query = (PfnFfxQuery)GetProcAddress(_dll, "ffxQuery"); - } - - if (_configure == nullptr) - { - LOG_INFO("Trying to load amd_fidelityfx_dx12.dll with detours"); - - _configure = (PfnFfxConfigure)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxConfigure"); - _createContext = (PfnFfxCreateContext)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxCreateContext"); - _destroyContext = (PfnFfxDestroyContext)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxDestroyContext"); - _dispatch = (PfnFfxDispatch)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxDispatch"); - _query = (PfnFfxQuery)DetourFindFunction("amd_fidelityfx_dx12.dll", "ffxQuery"); - } - - if (_configure != nullptr) - LOG_INFO("amd_fidelityfx_dx12.dll methods loaded!"); - else - LOG_ERROR("can't load amd_fidelityfx_dx12.dll methods!"); -} - -static void FfxFgLogCallback(uint32_t type, const wchar_t* message) -{ - std::wstring string(message); - LOG_DEBUG(" FG Log: {0}", wstring_to_string(string)); -} - -static bool CreateBufferResource(ID3D12Device* InDevice, ID3D12Resource* InSource, D3D12_RESOURCE_STATES InState, ID3D12Resource** OutResource) -{ - if (InDevice == nullptr || InSource == nullptr) - return false; - - D3D12_RESOURCE_DESC texDesc = InSource->GetDesc(); - - if (*OutResource != nullptr) - { - auto bufDesc = (*OutResource)->GetDesc(); - - if (bufDesc.Width != (UINT64)(texDesc.Width) || bufDesc.Height != (UINT)(texDesc.Height) || bufDesc.Format != texDesc.Format) - { - (*OutResource)->Release(); - (*OutResource) = nullptr; - } - else - return true; - } - - D3D12_HEAP_PROPERTIES heapProperties; - D3D12_HEAP_FLAGS heapFlags; - HRESULT hr = InSource->GetHeapProperties(&heapProperties, &heapFlags); - - if (hr != S_OK) - { - LOG_ERROR("GetHeapProperties result: {0:X}", (UINT64)hr); - return false; - } - - texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - - hr = InDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texDesc, InState, nullptr, IID_PPV_ARGS(OutResource)); - - if (hr != S_OK) - { - LOG_ERROR("CreateCommittedResource result: {0:X}", (UINT64)hr); - return false; - } - - (*OutResource)->SetName(L"fgHudlessSCBufferCopy"); - return true; -} - -static void ResourceBarrier(ID3D12GraphicsCommandList* InCommandList, ID3D12Resource* InResource, D3D12_RESOURCE_STATES InBeforeState, D3D12_RESOURCE_STATES InAfterState) -{ - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = InResource; - barrier.Transition.StateBefore = InBeforeState; - barrier.Transition.StateAfter = InAfterState; - barrier.Transition.Subresource = 0; - InCommandList->ResourceBarrier(1, &barrier); -} - -static SIZE_T GetGPUHandle(ID3D12Device* This, SIZE_T cpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE type) -{ - std::shared_lock lock(heapMutex); - for (auto& val : fgHeaps) - { - if (val.cpuStart <= cpuHandle && val.cpuEnd >= cpuHandle && val.gpuStart != 0) - { - auto incSize = This->GetDescriptorHandleIncrementSize(type); - auto addr = cpuHandle - val.cpuStart; - auto index = addr / incSize; - auto gpuAddr = val.gpuStart + (index * incSize); - - return gpuAddr; - } - } - - return NULL; -} - -static SIZE_T GetCPUHandle(ID3D12Device* This, SIZE_T gpuHandle, D3D12_DESCRIPTOR_HEAP_TYPE type) -{ - std::shared_lock lock(heapMutex); - for (auto& val : fgHeaps) - { - if (val.gpuStart <= gpuHandle && val.gpuEnd >= gpuHandle && val.cpuStart != 0) - { - auto incSize = This->GetDescriptorHandleIncrementSize(type); - auto addr = gpuHandle - val.gpuStart; - auto index = addr / incSize; - auto cpuAddr = val.cpuStart + (index * incSize); - - return cpuAddr; - } - } - - return NULL; -} - -static HeapInfo* GetHeapByCpuHandle(SIZE_T cpuHandle) -{ - std::shared_lock lock(heapMutex); - for (size_t i = 0; i < fgHeaps.size(); i++) - { - if (fgHeaps[i].cpuStart <= cpuHandle && fgHeaps[i].cpuEnd >= cpuHandle) - return &fgHeaps[i]; - } - - return nullptr; -} - -static HeapInfo* GetHeapByGpuHandle(SIZE_T gpuHandle) -{ - std::shared_lock lock(heapMutex); - for (size_t i = 0; i < fgHeaps.size(); i++) - { - if (fgHeaps[i].gpuStart <= gpuHandle && fgHeaps[i].gpuEnd >= gpuHandle) - return &fgHeaps[i]; - } - - return nullptr; -} - -static bool InUpscaledList(ID3D12Resource* resource) -{ - auto fIndex = fgFrameIndex; - if (ImGuiOverlayDx::fgUpscaledImage[fIndex] == resource) - { - LOG_DEBUG_ONLY("Found upscaled image!"); - fgUpscaledFound = true; - return true; - } - - return false; -} - -static void FillResourceInfo(ID3D12Resource* resource, ResourceInfo* info) -{ - auto desc = resource->GetDesc(); - info->buffer = resource; - info->width = desc.Width; - info->height = desc.Height; - info->format = desc.Format; -} - -static void GetHudless(ID3D12GraphicsCommandList* This) -{ - auto fIndex = fgFrameIndex; - if (This != g_pd3dCommandList && fgCopySource[fIndex] != nullptr && Config::Instance()->CurrentFeature != nullptr && - fgHudlessFrame != Config::Instance()->CurrentFeature->FrameCount() && ImGuiOverlayDx::fgTarget <= Config::Instance()->CurrentFeature->FrameCount()) - { - LOG_DEBUG("FrameCount: {0}, fgHudlessFrame: {1}, CommandList: {2:X}", Config::Instance()->CurrentFeature->FrameCount(), fgHudlessFrame, (UINT64)This); - - ImGuiOverlayDx::fgSkipHudlessChecks = true; - - // hudless captured for this frame - fgHudlessFrame = Config::Instance()->CurrentFeature->FrameCount(); - auto frame = fgHudlessFrame; - - LOG_DEBUG("running, frame: {0}", frame); - - // switch dlss targets for next depth and mv - ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; - - m_FrameGenerationConfig.HUDLessColor = ffxApiGetResourceDX12(fgHudless[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST, 0); - - m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; - m_FrameGenerationConfig.frameGenerationEnabled = true; // check here - m_FrameGenerationConfig.flags = 0; - - if (Config::Instance()->FGDebugView.value_or(false)) - m_FrameGenerationConfig.flags |= FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_VIEW; // check here - - m_FrameGenerationConfig.allowAsyncWorkloads = Config::Instance()->FGAsync.value_or(false); - - // assume symmetric letterbox - m_FrameGenerationConfig.generationRect.left = 0; - m_FrameGenerationConfig.generationRect.top = 0; - m_FrameGenerationConfig.generationRect.width = Config::Instance()->CurrentFeature->DisplayWidth(); - m_FrameGenerationConfig.generationRect.height = Config::Instance()->CurrentFeature->DisplayHeight(); - - m_FrameGenerationConfig.frameGenerationCallback = [](ffxDispatchDescFrameGeneration* params, void* pUserCtx) -> ffxReturnCode_t - { - HRESULT result; - ffxReturnCode_t dispatchResult; - auto fIndex = fgFrameIndex; - - // check for status - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || Config::Instance()->FGChanged || - ImGuiOverlayDx::fgContext == nullptr || ImGuiOverlayDx::fgCopyCommandList == nullptr || - ImGuiOverlayDx::fgCopyCommandQueue == nullptr || !ImGuiOverlayDx::fgIsActive) - { - LOG_WARN("Cancel async dispatch"); - fgDispatchCalled = false; - ImGuiOverlayDx::fgSkipHudlessChecks = false; - return FFX_API_RETURN_OK; - } - - // If fg is active but upscaling paused - if (!fgDispatchCalled || Config::Instance()->CurrentFeature == nullptr || fgLastFGFrame == Config::Instance()->CurrentFeature->FrameCount()) - { - LOG_WARN("Callback without hudless! frameID: {}", params->frameID); - - auto allocator = ImGuiOverlayDx::fgCopyCommandAllocators[fIndex]; - result = allocator->Reset(); - result = ImGuiOverlayDx::fgCopyCommandList->Reset(allocator, nullptr); - - params->frameID = fgLastFGFrame; - params->numGeneratedFrames = 0; - } - - if (Config::Instance()->CurrentFeature != nullptr) - fgLastFGFrame = Config::Instance()->CurrentFeature->FrameCount(); - - dispatchResult = _dispatch(reinterpret_cast(pUserCtx), ¶ms->header); - ID3D12CommandList* cl[1] = { nullptr }; - result = ImGuiOverlayDx::fgCopyCommandList->Close(); - cl[0] = ImGuiOverlayDx::fgCopyCommandList; - ImGuiOverlayDx::gameCommandQueue->ExecuteCommandLists(1, cl); - - LOG_DEBUG("_dispatch result: {0}", (UINT)result); - - fgDispatchCalled = false; - ImGuiOverlayDx::fgSkipHudlessChecks = false; - - return dispatchResult; - }; - - m_FrameGenerationConfig.frameGenerationCallbackUserContext = &ImGuiOverlayDx::fgContext; - - m_FrameGenerationConfig.onlyPresentGenerated = Config::Instance()->FGOnlyGenerated; - m_FrameGenerationConfig.frameID = Config::Instance()->CurrentFeature->FrameCount(); - m_FrameGenerationConfig.swapChain = ImGuiOverlayDx::currentSwapchain; - - ffxConfigureDescGlobalDebug1 debugDesc; - debugDesc.header.type = FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1; - debugDesc.debugLevel = FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_VERBOSE; - debugDesc.fpMessage = FfxFgLogCallback; - m_FrameGenerationConfig.header.pNext = &debugDesc.header; - - Config::Instance()->dxgiSkipSpoofing = true; - ffxReturnCode_t retCode = _configure(&ImGuiOverlayDx::fgContext, &m_FrameGenerationConfig.header); - Config::Instance()->dxgiSkipSpoofing = false; - LOG_DEBUG("_configure result: {0:X}, frame: {1}", retCode, frame); - - if (retCode == FFX_API_RETURN_OK) - { - ffxCreateBackendDX12Desc backendDesc{}; - backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12; - backendDesc.device = g_pd3dDeviceParam; - - ffxDispatchDescFrameGenerationPrepare dfgPrepare{}; - dfgPrepare.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION_PREPARE; - dfgPrepare.header.pNext = &backendDesc.header; - - dfgPrepare.commandList = ImGuiOverlayDx::fgCopyCommandList; // This; - - dfgPrepare.frameID = frame; - dfgPrepare.flags = m_FrameGenerationConfig.flags; - - dfgPrepare.renderSize = { Config::Instance()->CurrentFeature->RenderWidth(), Config::Instance()->CurrentFeature->RenderHeight() }; - - dfgPrepare.jitterOffset.x = ImGuiOverlayDx::jitterX; - dfgPrepare.jitterOffset.y = ImGuiOverlayDx::jitterY; - - // They will be always copies - dfgPrepare.motionVectors = ffxApiGetResourceDX12(ImGuiOverlayDx::paramVelocity[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST); - dfgPrepare.depth = ffxApiGetResourceDX12(ImGuiOverlayDx::paramDepth[fIndex], FFX_API_RESOURCE_STATE_COPY_DEST); - - dfgPrepare.motionVectorScale.x = ImGuiOverlayDx::mvScaleX; - dfgPrepare.motionVectorScale.y = ImGuiOverlayDx::mvScaleY; - - if (Config::Instance()->CurrentFeature->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_DepthInverted) - { - dfgPrepare.cameraFar = Config::Instance()->FsrCameraNear.value_or(0.01f); - dfgPrepare.cameraNear = Config::Instance()->FsrCameraFar.value_or(0.99f); - } - else - { - dfgPrepare.cameraFar = Config::Instance()->FsrCameraFar.value_or(0.99f); - dfgPrepare.cameraNear = Config::Instance()->FsrCameraNear.value_or(0.01f); - } - - dfgPrepare.cameraFovAngleVertical = 1.0471975511966f; - dfgPrepare.viewSpaceToMetersFactor = 1.0; - dfgPrepare.frameTimeDelta = ImGuiOverlayDx::fgFrameTime; - - // If somehow context is destroyed before this point - if (Config::Instance()->CurrentFeature == nullptr || ImGuiOverlayDx::fgContext == nullptr || !ImGuiOverlayDx::fgIsActive) - { - LOG_WARN("!! Config::Instance()->CurrentFeature == nullptr || ImGuiOverlayDx::fgContext == nullptr"); - return; - } - - Config::Instance()->dxgiSkipSpoofing = true; - retCode = _dispatch(&ImGuiOverlayDx::fgContext, &dfgPrepare.header); - fgDispatchCalled = true; - Config::Instance()->dxgiSkipSpoofing = false; - LOG_DEBUG("_dispatch result: {0}, frame: {1}", retCode, frame); - } - } -} - -static bool CheckCapture() -{ - auto fIndex = fgFrameIndex; - - { - std::unique_lock lock(counterMutex[fIndex]); - ImGuiOverlayDx::fgHUDlessCaptureCounter[fIndex]++; - - LOG_DEBUG("frameCounter: {}, fgHUDlessCaptureCounter: {}, Limit: {}", frameCounter, ImGuiOverlayDx::fgHUDlessCaptureCounter[fIndex], Config::Instance()->FGHUDLimit.value_or(1)); - - if (ImGuiOverlayDx::fgHUDlessCaptureCounter[fIndex] != Config::Instance()->FGHUDLimit.value_or(1)) - return false; - } - - return true; -} - -static void CaptureHudless(ID3D12GraphicsCommandList* cmdList, ResourceInfo* resource, D3D12_RESOURCE_STATES state) -{ - auto fIndex = fgFrameIndex; - ImGuiOverlayDx::upscaleRan = false; - fgUpscaledFound = false; - fgCopySource[fIndex] = resource->buffer; - - LOG_TRACE("Capture resource: {0:X}", (size_t)resource->buffer); - - if (resource->format != ImGuiOverlayDx::swapchainFormat && Config::Instance()->FGHUDFixExtended.value_or(false) && ImGuiOverlayDx::fgFormatTransfer != nullptr && - (resource->format == DXGI_FORMAT_R16G16B16A16_FLOAT || resource->format == DXGI_FORMAT_R11G11B10_FLOAT || resource->format == DXGI_FORMAT_R32G32B32A32_FLOAT || resource->format == DXGI_FORMAT_R32G32B32_FLOAT) && - (ImGuiOverlayDx::swapchainFormat == DXGI_FORMAT_R8G8B8A8_UNORM || ImGuiOverlayDx::swapchainFormat == DXGI_FORMAT_B8G8R8A8_UNORM || ImGuiOverlayDx::swapchainFormat == DXGI_FORMAT_R10G10B10A2_UNORM)) - { - if (ImGuiOverlayDx::fgFormatTransfer->CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS) && - CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, &fgHudlessBuffer[fIndex])) - { -#ifdef USE_RESOURCE_BARRIRER - ResourceBarrier(cmdList, resource->buffer, state, D3D12_RESOURCE_STATE_COPY_SOURCE); - ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); -#endif - - cmdList->CopyResource(fgHudlessBuffer[fIndex], resource->buffer); -#ifdef USE_RESOURCE_BARRIRER - ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); - ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, state); -#endif - - ImGuiOverlayDx::fgFormatTransfer->SetBufferState(ImGuiOverlayDx::fgCopyCommandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - ImGuiOverlayDx::fgFormatTransfer->Dispatch(g_pd3dDeviceParam, ImGuiOverlayDx::fgCopyCommandList, fgHudlessBuffer[fIndex], ImGuiOverlayDx::fgFormatTransfer->Buffer()); - ImGuiOverlayDx::fgFormatTransfer->SetBufferState(ImGuiOverlayDx::fgCopyCommandList, D3D12_RESOURCE_STATE_COPY_SOURCE); - - LOG_TRACE("Using fgFormatTransfer->Buffer()"); - fgHudless[fIndex] = ImGuiOverlayDx::fgFormatTransfer->Buffer(); - } - else - { - LOG_WARN("Can't create fgHudlessBuffer or fgFormatTransfer buffer!"); - return; - } - } - else - { -#ifdef USE_RESOURCE_BARRIRER - ResourceBarrier(cmdList, resource->buffer, state, D3D12_RESOURCE_STATE_COPY_SOURCE); -#endif - - if (CreateBufferResource(g_pd3dDeviceParam, resource->buffer, D3D12_RESOURCE_STATE_COPY_DEST, &fgHudless[fIndex])) - cmdList->CopyResource(fgHudless[fIndex], resource->buffer); - -#ifdef USE_RESOURCE_BARRIRER - ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, state); -#endif - } - - GetHudless(cmdList); -} - -static bool CheckForHudless(ResourceInfo* resource, bool checkFormat = true) -{ - if (ImGuiOverlayDx::currentSwapchain == nullptr) - return false; - - DXGI_SWAP_CHAIN_DESC scDesc{}; - if (ImGuiOverlayDx::currentSwapchain->GetDesc(&scDesc) != S_OK) - { - LOG_WARN("Can't get swapchain desc!"); - return false; - } - - if (scDesc.BufferDesc.Height != fgScDesc.BufferDesc.Height || scDesc.BufferDesc.Width != fgScDesc.BufferDesc.Width || scDesc.BufferDesc.Format != fgScDesc.BufferDesc.Format) - { - LOG_DEBUG("Format change, recreate the FormatTransfer"); - delete ImGuiOverlayDx::fgFormatTransfer; - ImGuiOverlayDx::fgFormatTransfer = nullptr; - ImGuiOverlayDx::fgFormatTransfer = new FT_Dx12("FormatTransfer", g_pd3dDeviceParam, scDesc.BufferDesc.Format); - - ImGuiOverlayDx::swapchainFormat = scDesc.BufferDesc.Format; - fgScDesc = scDesc; - } - - if (resource->height == fgScDesc.BufferDesc.Height && resource->width == fgScDesc.BufferDesc.Width && (!checkFormat || resource->format == fgScDesc.BufferDesc.Format || - (Config::Instance()->FGHUDFixExtended.value_or(false) && ImGuiOverlayDx::fgFormatTransfer != nullptr && - (resource->format == DXGI_FORMAT_R16G16B16A16_FLOAT || resource->format == DXGI_FORMAT_R11G11B10_FLOAT || resource->format == DXGI_FORMAT_R32G32B32A32_FLOAT || resource->format == DXGI_FORMAT_R32G32B32_FLOAT) && - (fgScDesc.BufferDesc.Format == DXGI_FORMAT_R8G8B8A8_UNORM || fgScDesc.BufferDesc.Format == DXGI_FORMAT_B8G8R8A8_UNORM || fgScDesc.BufferDesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM)))) - { - LOG_TRACE("Width: {}/{}, Height: {}/{}, Format: {}/{}, checkFormat: {} -> TRUE", - resource->width, fgScDesc.BufferDesc.Width, resource->height, fgScDesc.BufferDesc.Height, (UINT)resource->format, (UINT)fgScDesc.BufferDesc.Format, checkFormat); - - return true; - } - - LOG_TRACE("Width: {}/{}, Height: {}/{}, Format: {}/{}, checkFormat: {} -> FALSE", - resource->width, fgScDesc.BufferDesc.Width, resource->height, fgScDesc.BufferDesc.Height, (UINT)resource->format, (UINT)fgScDesc.BufferDesc.Format, checkFormat); - - return false; -} - -#ifdef USE_RESOURCE_DISCARD -static void hkDiscardResource(ID3D12GraphicsCommandList* This, ID3D12Resource* pResource, D3D12_DISCARD_REGION* pRegion) -{ - o_DiscardResource(This, pResource, pRegion); - - if (This != g_pd3dCommandList && pRegion == nullptr) - { - std::unique_lock lock(resourceMutex); - - if (!fgHandlesByResources.contains(pResource)) - return; - - auto heapInfo = &fgHandlesByResources[pResource]; - LOG_DEBUG_ONLY(" <-- {}", heapInfo->cpuStart); - - auto heap = GetHeapByCpuHandle(heapInfo->cpuStart); - if (heap != nullptr) - heap->SetByCpuHandle(heapInfo->cpuStart, {}); - - fgHandlesByResources.erase(pResource); - LOG_DEBUG_ONLY("Erased"); - } -} -#endif - -#pragma region "Resource inputs" - -static void hkCreateRenderTargetView(ID3D12Device* This, ID3D12Resource* pResource, const D3D12_RENDER_TARGET_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) -{ - o_CreateRenderTargetView(This, pResource, pDesc, DestDescriptor); - - - if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) - return; - - auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - ResourceHeapInfo info{}; - info.cpuStart = DestDescriptor.ptr; - info.gpuStart = gpuHandle; - - ResourceInfo resInfo{}; - FillResourceInfo(pResource, &resInfo); - resInfo.type = RTV; - -#ifdef USE_RESOURCE_DISCARD - { - std::unique_lock lock(resourceMutex); - fgHandlesByResources.insert_or_assign(pResource, info); - } -#endif - - auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); - if (heap != nullptr) - heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); -} - -static void hkCreateShaderResourceView(ID3D12Device* This, ID3D12Resource* pResource, D3D12_SHADER_RESOURCE_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) -{ - o_CreateShaderResourceView(This, pResource, pDesc, DestDescriptor); - - if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) - return; - - auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - ResourceHeapInfo info{}; - info.cpuStart = DestDescriptor.ptr; - info.gpuStart = gpuHandle; - - ResourceInfo resInfo{}; - FillResourceInfo(pResource, &resInfo); - resInfo.type = SRV; - -#ifdef USE_RESOURCE_DISCARD - { - std::unique_lock lock(resourceMutex); - fgHandlesByResources.insert_or_assign(pResource, info); - } -#endif - - auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); - if (heap != nullptr) - heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); -} - -static void hkCreateUnorderedAccessView(ID3D12Device* This, ID3D12Resource* pResource, ID3D12Resource* pCounterResource, D3D12_UNORDERED_ACCESS_VIEW_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) -{ - o_CreateUnorderedAccessView(This, pResource, pCounterResource, pDesc, DestDescriptor); - - - if (pResource == nullptr || pDesc == nullptr || pDesc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2D) - return; - - auto gpuHandle = GetGPUHandle(This, DestDescriptor.ptr, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - ResourceHeapInfo info{}; - info.cpuStart = DestDescriptor.ptr; - info.gpuStart = gpuHandle; - - ResourceInfo resInfo{}; - FillResourceInfo(pResource, &resInfo); - resInfo.type = UAV; - -#ifdef USE_RESOURCE_DISCARD - { - std::unique_lock lock(resourceMutex); - fgHandlesByResources.insert_or_assign(pResource, info); - } -#endif - - auto heap = GetHeapByCpuHandle(DestDescriptor.ptr); - if (heap != nullptr) - heap->SetByCpuHandle(DestDescriptor.ptr, resInfo); -} - -#pragma endregion - -#pragma region "Resource copy" - -#ifdef USE_COPY_RESOURCE -static void hkCopyResource(ID3D12GraphicsCommandList* This, ID3D12Resource* Dest, ID3D12Resource* Source) -{ - o_CopyResource(This, Dest, Source); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || - Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <--"); - - ResourceInfo resInfo{}; - FillResourceInfo(Dest, &resInfo); - - // Copy source is not in sources and dest is not matching for swapchain format - if (!InUpscaledList(Source) && !CheckForHudless(&resInfo, false)) - return; - - // not matching to swapchain format or limit is not ok - if (CheckForHudless(&resInfo) && CheckCapture()) - { - LOG_DEBUG("Capture"); - CaptureHudless(This, Dest); - } -} -#endif - -static void hkCopyTextureRegion(ID3D12GraphicsCommandList* This, D3D12_TEXTURE_COPY_LOCATION* pDst, UINT DstX, UINT DstY, UINT DstZ, D3D12_TEXTURE_COPY_LOCATION* pSrc, D3D12_BOX* pSrcBox) -{ - o_CopyTextureRegion(This, pDst, DstX, DstY, DstZ, pSrc, pSrcBox); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This || ImGuiOverlayDx::fgSkipHudlessChecks || - Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <--"); - - ResourceInfo resInfo{}; - FillResourceInfo(pDst->pResource, &resInfo); - - // Copy source is not in sources and dest is not matching for swapchain format - if (!InUpscaledList(pSrc->pResource) && !CheckForHudless(&resInfo, false)) - return; - - // not matching to swapchain format or limit is not ok - if (CheckForHudless(&resInfo) && CheckCapture()) - { - LOG_DEBUG("Capture"); - CaptureHudless(This, &resInfo, D3D12_RESOURCE_STATE_COPY_DEST); - } -} - -#pragma endregion - -#pragma region "Heap methods" - -static HRESULT hkCreateDescriptorHeap(ID3D12Device* This, D3D12_DESCRIPTOR_HEAP_DESC* pDescriptorHeapDesc, REFIID riid, void** ppvHeap) -{ - auto result = o_CreateDescriptorHeap(This, pDescriptorHeapDesc, riid, ppvHeap); - - // try to calculate handle ranges for heap - if (result == S_OK && (pDescriptorHeapDesc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || pDescriptorHeapDesc->Type == D3D12_DESCRIPTOR_HEAP_TYPE_RTV)) //&& pDescriptorHeapDesc->Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) - { - auto heap = (ID3D12DescriptorHeap*)(*ppvHeap); - auto increment = This->GetDescriptorHandleIncrementSize(pDescriptorHeapDesc->Type); - auto numDescriptors = pDescriptorHeapDesc->NumDescriptors; - auto cpuStart = (SIZE_T)(heap->GetCPUDescriptorHandleForHeapStart().ptr); - auto cpuEnd = cpuStart + (increment * numDescriptors); - auto gpuStart = (SIZE_T)(heap->GetGPUDescriptorHandleForHeapStart().ptr); - auto gpuEnd = gpuStart + (increment * numDescriptors); - auto type = (UINT)pDescriptorHeapDesc->Type; - HeapInfo info(cpuStart, cpuEnd, gpuStart, gpuEnd, numDescriptors, increment, type); - - LOG_DEBUG_ONLY("Heap type: {}, Cpu: {}-{}, Gpu: {}-{}, Desc count: {}", info.type, info.cpuStart, info.cpuEnd, info.gpuStart, info.gpuEnd, info.numDescriptors); - { - std::unique_lock lock(heapMutex); - fgHeaps.push_back(info); - } - } - else - { - auto heap = (ID3D12DescriptorHeap*)(*ppvHeap); - LOG_DEBUG_ONLY("Skipping, Heap type: {}, Cpu: {}, Gpu: {}", (UINT)pDescriptorHeapDesc->Type, heap->GetCPUDescriptorHandleForHeapStart().ptr, heap->GetGPUDescriptorHandleForHeapStart().ptr); - } - - return result; -} - - -static void hkCopyDescriptors(ID3D12Device* This, - UINT NumDestDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pDestDescriptorRangeStarts, UINT* pDestDescriptorRangeSizes, - UINT NumSrcDescriptorRanges, D3D12_CPU_DESCRIPTOR_HANDLE* pSrcDescriptorRangeStarts, UINT* pSrcDescriptorRangeSizes, - D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) -{ - o_CopyDescriptors(This, NumDestDescriptorRanges, pDestDescriptorRangeStarts, pDestDescriptorRangeSizes, NumSrcDescriptorRanges, pSrcDescriptorRangeStarts, pSrcDescriptorRangeSizes, DescriptorHeapsType); - - auto fIndex = fgFrameIndex; - - if (Config::Instance()->CurrentFeature == nullptr) - return; - - if (DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_RTV) - return; - - LOG_DEBUG_ONLY("SrcRanges: {}, DestRanges: {}, Type: {}", NumSrcDescriptorRanges, NumDestDescriptorRanges, (UINT)DescriptorHeapsType); - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - auto size = This->GetDescriptorHandleIncrementSize(DescriptorHeapsType); - - UINT destRangeIndex = 0; - UINT destIndex = 0; - - for (size_t i = 0; i < NumSrcDescriptorRanges; i++) - { - UINT copyCount = 1; - - if (pSrcDescriptorRangeSizes != nullptr) - copyCount = pSrcDescriptorRangeSizes[i]; - - for (size_t j = 0; j < copyCount; j++) - { - auto handle = pSrcDescriptorRangeStarts[i].ptr + j * size; - - auto heap = GetHeapByCpuHandle(handle); - if (heap == nullptr) - continue; - - auto buffer = heap->GetByCpuHandle(handle); - auto destHandle = pDestDescriptorRangeStarts[destRangeIndex].ptr + destIndex * size; - heap->SetByCpuHandle(destHandle, *buffer); - } - - if (pDestDescriptorRangeSizes == nullptr) - { - destIndex = 0; - destRangeIndex++; - } - else - { - if (pDestDescriptorRangeSizes[destRangeIndex] == destIndex) - { - destIndex = 0; - destRangeIndex++; - } - else - { - destIndex++; - } - } - } -} - -static void hkCopyDescriptorsSimple(ID3D12Device* This, UINT NumDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptorRangeStart, - D3D12_CPU_DESCRIPTOR_HANDLE SrcDescriptorRangeStart, D3D12_DESCRIPTOR_HEAP_TYPE DescriptorHeapsType) -{ - o_CopyDescriptorsSimple(This, NumDescriptors, DestDescriptorRangeStart, SrcDescriptorRangeStart, DescriptorHeapsType); - - auto fIndex = fgFrameIndex; - - if (Config::Instance()->CurrentFeature == nullptr) - return; - - if (DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && DescriptorHeapsType != D3D12_DESCRIPTOR_HEAP_TYPE_RTV) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - auto size = This->GetDescriptorHandleIncrementSize(DescriptorHeapsType); - - for (size_t i = 0; i < NumDescriptors; i++) - { - auto handle = SrcDescriptorRangeStart.ptr + i * size; - - auto heap = GetHeapByCpuHandle(handle); - if (heap == nullptr) - continue; - - auto buffer = heap->GetByCpuHandle(handle); - auto destHandle = DestDescriptorRangeStart.ptr + i * size; - heap->SetByCpuHandle(destHandle, *buffer); - } -} - -#pragma endregion - -#pragma region "Shader inputs" - -static void hkSetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) -{ - o_SetGraphicsRootDescriptorTable(This, RootParameterIndex, BaseDescriptor); - - auto fIndex = fgFrameIndex; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - auto heap = GetHeapByGpuHandle(BaseDescriptor.ptr); - if (heap == nullptr) - return; - - auto capturedBuffer = heap->GetByGpuHandle(BaseDescriptor.ptr); - if (capturedBuffer == nullptr || capturedBuffer->buffer == nullptr) - { - LOG_DEBUG_ONLY("Miss RootParameterIndex: {1}, CommandList: {0:X}, gpuHandle: {2}", (SIZE_T)This, RootParameterIndex, BaseDescriptor.ptr); - return; - } - - if (!InUpscaledList(capturedBuffer->buffer) && !CheckForHudless(capturedBuffer, false)) - return; - - capturedBuffer->state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - - { - std::unique_lock lock(hudlessMutex[fIndex]); - if (fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); - return; - } - - ankerl::unordered_dense::map newMap; - fgPossibleHudless[fIndex].insert_or_assign(This, newMap); - fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); - } -} - -#pragma endregion - -#pragma region "Shader outputs" - -static void hkOMSetRenderTargets(ID3D12GraphicsCommandList* This, UINT NumRenderTargetDescriptors, D3D12_CPU_DESCRIPTOR_HANDLE* pRenderTargetDescriptors, - BOOL RTsSingleHandleToDescriptorRange, D3D12_CPU_DESCRIPTOR_HANDLE* pDepthStencilDescriptor) -{ - o_OMSetRenderTargets(This, NumRenderTargetDescriptors, pRenderTargetDescriptors, RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - { - std::unique_lock lock(hudlessMutex[fIndex]); - - for (size_t i = 0; i < NumRenderTargetDescriptors; i++) - { - auto handle = pRenderTargetDescriptors[i]; - auto heap = GetHeapByCpuHandle(handle.ptr); - if (heap == nullptr) - continue; - - auto resource = heap->GetByCpuHandle(handle.ptr); - if (resource == nullptr || resource->buffer == nullptr) - { - LOG_DEBUG_ONLY("Miss index: {0}, cpu: {1}", i, handle.ptr); - continue; - } - - if (!CheckForHudless(resource, false)) - continue; - - resource->state = D3D12_RESOURCE_STATE_RENDER_TARGET; - - if (fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].insert_or_assign(resource->buffer, *resource); - return; - } - - ankerl::unordered_dense::map newMap; - fgPossibleHudless[fIndex].insert_or_assign(This, newMap); - fgPossibleHudless[fIndex][This].insert_or_assign(resource->buffer, *resource); - } - } -} - -#pragma endregion - -#pragma region "Compute paramters" - -static void hkSetComputeRootDescriptorTable(ID3D12GraphicsCommandList* This, UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) -{ - o_SetComputeRootDescriptorTable(This, RootParameterIndex, BaseDescriptor); - - auto fIndex = fgFrameIndex; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - auto heap = GetHeapByGpuHandle(BaseDescriptor.ptr); - if (heap == nullptr) - return; - - auto capturedBuffer = heap->GetByGpuHandle(BaseDescriptor.ptr); - if (capturedBuffer != nullptr && capturedBuffer->buffer != nullptr && (InUpscaledList(capturedBuffer->buffer) || CheckForHudless(capturedBuffer, false))) - { - if (capturedBuffer->type == UAV) - capturedBuffer->state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - else - capturedBuffer->state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - - std::unique_lock lock4(hudlessMutex[fIndex]); - if (fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); - return; - } - - ankerl::unordered_dense::map newMap; - fgPossibleHudless[fIndex].insert_or_assign(This, newMap); - fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); - } -} - -#pragma endregion - -#pragma region "Shader finalizers" - -// Capture if render target matches, wait for DrawIndexed -static void hkDrawInstanced(ID3D12GraphicsCommandList* This, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) -{ - o_DrawInstanced(This, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - { - std::unique_lock lock(hudlessMutex[fIndex]); - // if can't find output skip - if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].clear(); - return; - } - - do - { - auto& val0 = fgPossibleHudless[fIndex][This]; - - // if this command list does not have entries skip - if (val0.size() == 0) - break; - - for (auto& [key, val] : val0) - { - if (CheckForHudless(&val)) - { - if (CheckCapture()) - { - LOG_DEBUG("Capture"); - CaptureHudless(This, &val, val.state); - break; - } - } - } - - } while (false); - - fgPossibleHudless[fIndex][This].clear(); - LOG_DEBUG_ONLY("Clear"); - } -} - -static void hkDrawIndexedInstanced(ID3D12GraphicsCommandList* This, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) -{ - o_DrawIndexedInstanced(This, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - { - std::unique_lock lock(hudlessMutex[fIndex]); - // if can't find output skip - if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].clear(); - LOG_DEBUG_ONLY("Early exit"); - return; - } - - do - { - auto& val0 = fgPossibleHudless[fIndex][This]; - - // if this command list does not have entries skip - if (val0.size() == 0) - break; - - for (auto& [key, val] : val0) - { - if (CheckForHudless(&val)) - { - LOG_DEBUG_ONLY("Found matching final image"); - - if (CheckCapture()) - { - LOG_DEBUG("Capture"); - CaptureHudless(This, &val, val.state); - break; - } - } - } - - } while (false); - - fgPossibleHudless[fIndex][This].clear(); - LOG_DEBUG_ONLY("Clear"); - } -} - -static void hkDispatch(ID3D12GraphicsCommandList* This, UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) -{ - o_Dispatch(This, ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); - - auto fIndex = fgFrameIndex; - - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) - return; - - if (!Config::Instance()->FGEnabled.value_or(false) || !Config::Instance()->FGHUDFix.value_or(false) || ImGuiOverlayDx::fgContext == nullptr || - ImGuiOverlayDx::fgTarget > Config::Instance()->CurrentFeature->FrameCount() || !ImGuiOverlayDx::fgIsActive || - fgHudlessFrame == Config::Instance()->CurrentFeature->FrameCount() && fgCopySource[fIndex] != nullptr) - return; - - LOG_DEBUG_ONLY(" <-- {0:X}", (size_t)This); - - { - std::unique_lock lock(hudlessMutex[fIndex]); - // if can't find output skip - if (fgPossibleHudless[fIndex].size() == 0 || !fgPossibleHudless[fIndex].contains(This)) - { - fgPossibleHudless[fIndex][This].clear(); - LOG_DEBUG_ONLY("Early exit"); - return; - } - - do - { - auto& val0 = fgPossibleHudless[fIndex][This]; - - // if this command list does not have entries skip - if (val0.size() == 0) - break; - - for (auto& [key, val] : val0) - { - if (CheckForHudless(&val)) - { - LOG_DEBUG_ONLY("Found matching final image"); - - if (CheckCapture()) - { - LOG_DEBUG("Capture"); - CaptureHudless(This, &val, val.state); - break; - } - } - } - - } while (false); - - fgPossibleHudless[fIndex][This].clear(); - LOG_DEBUG_ONLY("Clear"); - } -} - -#pragma endregion - static int GetCorrectDXGIFormat(int eCurrentFormat) { switch (eCurrentFormat) @@ -1562,1254 +209,6 @@ static void CleanupRenderTargetDx11(bool shutDown) _isInited = false; } -#pragma region Callbacks for wrapped swapchain - -static void CleanupRenderTarget(bool clearQueue, HWND hWnd) -{ - LOG_FUNC(); - - if (clearQueue) - { - currentSCCommandQueue = nullptr; - ImGuiOverlayDx::fgCommandQueue = nullptr; - ImGuiOverlayDx::gameCommandQueue = nullptr; - } - - if (_dx11Device) - CleanupRenderTargetDx11(false); - else - CleanupRenderTargetDx12(clearQueue); - - // Releasing RTSS D3D11on12 device - if (clearQueue && d3d11on12Device != nullptr && GetModuleHandle(L"RTSSHooks64.dll") != nullptr) - { - LOG_DEBUG("Releasing D3d11on12 device"); - d3d11on12Device = nullptr; - } -} - -static HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd) -{ - LOG_DEBUG(""); - - HRESULT presentResult; - auto fIndex = fgFrameIndex; - - if (hWnd != Util::GetProcessWindow()) - { - //fgPresentRunning = true; - - if (pPresentParameters == nullptr) - presentResult = pSwapChain->Present(SyncInterval, Flags); - else - presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); - - //fgPresentRunning = false; - - ImGuiOverlayDx::currentSwapchain = nullptr; - ImGuiOverlayDx::swapchainFormat = DXGI_FORMAT_UNKNOWN; - ImGuiOverlayDx::fgSkipHudlessChecks = false; - - LOG_FUNC_RESULT(presentResult); - - //LOG_DEBUG("Return"); - - return presentResult; - } - - if (fgSwapChains.contains(hWnd)) - { - auto swInfo = &fgSwapChains[hWnd]; - ImGuiOverlayDx::currentSwapchain = swInfo->swapChain; - - if (ImGuiOverlayDx::swapchainFormat == DXGI_FORMAT_UNKNOWN) - ImGuiOverlayDx::swapchainFormat = swInfo->swapChainFormat; - - swInfo->fgCommandQueue = (ID3D12CommandQueue*)pDevice; - ImGuiOverlayDx::gameCommandQueue = swInfo->gameCommandQueue; - } - - //if (Config::Instance()->CurrentFeature != nullptr) - // LOG_DEBUG("FrameCount: {}, fgHudlessFrame: {}", Config::Instance()->CurrentFeature->FrameCount(), fgHudlessFrame); - - ID3D12CommandQueue* cq = nullptr; - ID3D11Device* device = nullptr; - ID3D12Device* device12 = nullptr; - - // try to obtain directx objects and find the path - if (pDevice->QueryInterface(IID_PPV_ARGS(&device)) == S_OK) - { - if (!_dx11Device) - LOG_DEBUG("D3D11Device captured"); - - _dx11Device = true; - } - else if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) - { - if (!_dx12Device) - LOG_DEBUG("D3D12CommandQueue captured"); - - currentSCCommandQueue = pDevice; - ImGuiOverlayDx::fgCommandQueue = (ID3D12CommandQueue*)pDevice; - ImGuiOverlayDx::fgCommandQueue->SetName(L"fgSwapChainQueue"); - ImGuiOverlayDx::GameCommandQueue = (ID3D12CommandQueue*)pDevice; - - if (cq->GetDevice(IID_PPV_ARGS(&device12)) == S_OK) - { - if (!_dx12Device) - LOG_DEBUG("D3D12Device captured"); - - _dx12Device = true; - } - } - - // DXVK check, it's here because of upscaler time calculations - if (Config::Instance()->IsRunningOnDXVK) - { - if (cq != nullptr) - cq->Release(); - - if (device != nullptr) - device->Release(); - - if (device12 != nullptr) - device12->Release(); - - //fgPresentRunning = true; - - if (pPresentParameters == nullptr) - presentResult = pSwapChain->Present(SyncInterval, Flags); - else - presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); - - ImGuiOverlayDx::fgSkipHudlessChecks = false; - - if (Config::Instance()->CurrentFeature != nullptr) - fgPresentedFrame = Config::Instance()->CurrentFeature->FrameCount(); - - if (fgStopAfterNextPresent) - { - ImGuiOverlayDx::StopAndDestroyFGContext(false, false); - fgStopAfterNextPresent = false; - } - - auto now = Util::MillisecondsNow(); - - if (fgLastFrameTime != 0) - { - fgLastDeltaTime = now - fgLastFrameTime; - LOG_DEBUG("fgLastDeltaTime: {0:.2f}, frameCounter: {1}", fgLastDeltaTime, frameCounter); - } - - fgLastFrameTime = now; - - //LOG_DEBUG("Return"); - - return presentResult; - } - - // Upscaler GPU time computation - if (ImGuiOverlayDx::dx12UpscaleTrig && ImGuiOverlayDx::readbackBuffer != nullptr && ImGuiOverlayDx::queryHeap != nullptr && cq != nullptr) - { - if (ImGuiOverlayBase::IsInited() && ImGuiOverlayBase::IsVisible()) - { - UINT64* timestampData; - ImGuiOverlayDx::readbackBuffer->Map(0, nullptr, reinterpret_cast(×tampData)); - - if (timestampData != nullptr) - { - // Get the GPU timestamp frequency (ticks per second) - UINT64 gpuFrequency; - cq->GetTimestampFrequency(&gpuFrequency); - - // Calculate elapsed time in milliseconds - UINT64 startTime = timestampData[0]; - UINT64 endTime = timestampData[1]; - double elapsedTimeMs = (endTime - startTime) / static_cast(gpuFrequency) * 1000.0; - - Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); - Config::Instance()->upscaleTimes.pop_front(); - } - else - { - LOG_WARN("timestampData is null!"); - } - - // Unmap the buffer - ImGuiOverlayDx::readbackBuffer->Unmap(0, nullptr); - } - - ImGuiOverlayDx::dx12UpscaleTrig = false; - } - else if (ImGuiOverlayDx::dx11UpscaleTrig[ImGuiOverlayDx::currentFrameIndex] && device != nullptr && ImGuiOverlayDx::disjointQueries[0] != nullptr && - ImGuiOverlayDx::startQueries[0] != nullptr && ImGuiOverlayDx::endQueries[0] != nullptr) - { - if (g_pd3dDeviceContext == nullptr) - device->GetImmediateContext(&g_pd3dDeviceContext); - - if (ImGuiOverlayBase::IsInited() && ImGuiOverlayBase::IsVisible()) - { - // Retrieve the results from the previous frame - D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; - if (g_pd3dDeviceContext->GetData(ImGuiOverlayDx::disjointQueries[ImGuiOverlayDx::previousFrameIndex], &disjointData, sizeof(disjointData), 0) == S_OK) - { - if (!disjointData.Disjoint && disjointData.Frequency > 0) - { - UINT64 startTime = 0, endTime = 0; - if (g_pd3dDeviceContext->GetData(ImGuiOverlayDx::startQueries[ImGuiOverlayDx::previousFrameIndex], &startTime, sizeof(UINT64), 0) == S_OK && - g_pd3dDeviceContext->GetData(ImGuiOverlayDx::endQueries[ImGuiOverlayDx::previousFrameIndex], &endTime, sizeof(UINT64), 0) == S_OK) - { - double elapsedTimeMs = (endTime - startTime) / static_cast(disjointData.Frequency) * 1000.0; - Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); - Config::Instance()->upscaleTimes.pop_front(); - } - } - } - } - - - ImGuiOverlayDx::dx11UpscaleTrig[ImGuiOverlayDx::currentFrameIndex] = false; - ImGuiOverlayDx::currentFrameIndex = (ImGuiOverlayDx::currentFrameIndex + 1) % ImGuiOverlayDx::QUERY_BUFFER_COUNT; - } - - // Process window handle changed, update base - if (ImGuiOverlayBase::Handle() != hWnd) - { - LOG_DEBUG("Handle changed"); - - if (ImGuiOverlayBase::IsInited()) - ImGuiOverlayBase::Shutdown(); - - ImGuiOverlayBase::Init(hWnd); - - _isInited = false; - } - - // Init - if (!_isInited) - { - if (_dx11Device) - { - CleanupRenderTargetDx11(false); - - g_pd3dDevice = device; - g_pd3dDevice->AddRef(); - - CreateRenderTargetDx11(pSwapChain); - ImGuiOverlayBase::Dx11Ready(); - _isInited = true; - } - else if (_dx12Device && (g_pd3dDeviceParam != nullptr || device12 != nullptr)) - { - if (g_pd3dDeviceParam != nullptr && device12 == nullptr) - device12 = g_pd3dDeviceParam; - - CleanupRenderTargetDx12(true); - - g_pd3dCommandQueue = cq; - g_pd3dDeviceParam = device12; - - g_pd3dCommandQueue->AddRef(); - g_pd3dDeviceParam->AddRef(); - - ImGuiOverlayBase::Dx12Ready(); - _isInited = true; - } - } - - // dx11 multi thread safety - ID3D11Multithread* dx11MultiThread = nullptr; - ID3D11DeviceContext* dx11Context = nullptr; - bool mtState = false; - - if (_dx11Device) - { - ID3D11Device* dx11Device = g_pd3dDevice; - if (dx11Device == nullptr) - dx11Device = d3d11Device; - - if (dx11Device == nullptr) - dx11Device = d3d11on12Device; - - if (dx11Device != nullptr) - { - dx11Device->GetImmediateContext(&dx11Context); - - if (dx11Context != nullptr && dx11Context->QueryInterface(IID_PPV_ARGS(&dx11MultiThread)) == S_OK && dx11MultiThread != nullptr) - { - mtState = dx11MultiThread->GetMultithreadProtected(); - dx11MultiThread->SetMultithreadProtected(TRUE); - dx11MultiThread->Enter(); - } - } - } - - // Render menu - if (_dx11Device) - RenderImGui_DX11(pSwapChain); - else if (_dx12Device) - RenderImGui_DX12(pSwapChain); - - frameCounter++; - - //fgPresentRunning = true; - - // swapchain present - if (pPresentParameters == nullptr) - presentResult = pSwapChain->Present(SyncInterval, Flags); - else - presentResult = ((IDXGISwapChain1*)pSwapChain)->Present1(SyncInterval, Flags, pPresentParameters); - - //fgPresentRunning = false; - ImGuiOverlayDx::fgSkipHudlessChecks = false; - - if (Config::Instance()->CurrentFeature != nullptr) - fgPresentedFrame = Config::Instance()->CurrentFeature->FrameCount(); - - // dx11 multi thread safety - if (_dx11Device && dx11MultiThread != nullptr) - { - dx11MultiThread->Leave(); - dx11MultiThread->SetMultithreadProtected(mtState); - - dx11MultiThread->Release(); - dx11Context->Release(); - } - - // release used objects - if (cq != nullptr) - cq->Release(); - - if (device != nullptr) - device->Release(); - - if (device12 != nullptr) - device12->Release(); - - auto now = Util::MillisecondsNow(); - - if (fgLastFrameTime != 0) - { - fgLastDeltaTime = now - fgLastFrameTime; - LOG_DEBUG("fgLastDeltaTime: {0:.2f}, frameCounter: {1}", fgLastDeltaTime, frameCounter); - } - - fgLastFrameTime = now; - - if (fgStopAfterNextPresent) - { - ImGuiOverlayDx::StopAndDestroyFGContext(false, false); - fgStopAfterNextPresent = false; - } - - return presentResult; -} - -#pragma endregion - -#pragma region DXGI hooks - -static void CheckAdapter(IUnknown* unkAdapter) -{ - if (Config::Instance()->IsRunningOnDXVK) - return; - - //DXVK VkInterface GUID - const GUID guid = { 0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff} }; - - IDXGIAdapter* adapter = nullptr; - bool adapterOk = unkAdapter->QueryInterface(IID_PPV_ARGS(&adapter)) == S_OK; - - void* dxvkAdapter = nullptr; - if (adapterOk && adapter->QueryInterface(guid, &dxvkAdapter) == S_OK) - { - - Config::Instance()->IsRunningOnDXVK = dxvkAdapter != nullptr; - ((IDXGIAdapter*)dxvkAdapter)->Release(); - } - - if (adapterOk) - adapter->Release(); -} - -static void AttachToFactory(IUnknown* unkFactory) -{ - PVOID* pVTable = *(PVOID**)unkFactory; - - IDXGIFactory* factory; - if (ptrEnumAdapters == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory)) == S_OK) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - ptrEnumAdapters = (PFN_EnumAdapters2)pVTable[7]; - - DetourAttach(&(PVOID&)ptrEnumAdapters, hkEnumAdapters); - - DetourTransactionCommit(); - - factory->Release(); - } - - IDXGIFactory1* factory1; - if (ptrEnumAdapters1 == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory1)) == S_OK) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - ptrEnumAdapters1 = (PFN_EnumAdapters12)pVTable[12]; - - DetourAttach(&(PVOID&)ptrEnumAdapters1, hkEnumAdapters1); - - DetourTransactionCommit(); - - factory1->Release(); - } - - IDXGIFactory4* factory4; - if (ptrEnumAdapterByLuid == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory4)) == S_OK) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - ptrEnumAdapterByLuid = (PFN_EnumAdapterByLuid2)pVTable[26]; - - DetourAttach(&(PVOID&)ptrEnumAdapterByLuid, hkEnumAdapterByLuid); - - DetourTransactionCommit(); - - factory4->Release(); - } - - IDXGIFactory6* factory6; - if (ptrEnumAdapterByGpuPreference == nullptr && unkFactory->QueryInterface(IID_PPV_ARGS(&factory6)) == S_OK) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - ptrEnumAdapterByGpuPreference = (PFN_EnumAdapterByGpuPreference2)pVTable[29]; - - DetourAttach(&(PVOID&)ptrEnumAdapterByGpuPreference, hkEnumAdapterByGpuPreference); - - DetourTransactionCommit(); - - factory6->Release(); - } -} - -static HRESULT hkCreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) -{ - LOG_FUNC(); - - *ppSwapChain = nullptr; - - if (Config::Instance()->VulkanCreatingSC) - { - LOG_WARN("Vulkan is creating swapchain!"); - - if (pDesc != nullptr) - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); - - return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - } - - if (pDevice == nullptr) - { - LOG_WARN("pDevice is nullptr!"); - return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - } - - if (pDesc->BufferDesc.Height == 2 && pDesc->BufferDesc.Width == 2) - { - LOG_WARN("RTSS call!"); - return oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - } - - ID3D12CommandQueue* cq = nullptr; - if (Config::Instance()->FGUseFGSwapChain.value_or(true) && !fgSkipSCWrapping && _createContext != nullptr && pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) - { - cq->SetName(L"GameQueue"); - SwapChainInfo scInfo{}; - scInfo.gameCommandQueue = cq; - cq->Release(); - - ffxCreateContextDescFrameGenerationSwapChainNewDX12 createSwapChainDesc{}; - createSwapChainDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_NEW_DX12; - - createSwapChainDesc.dxgiFactory = pFactory; - createSwapChainDesc.gameQueue = (ID3D12CommandQueue*)pDevice; - createSwapChainDesc.desc = pDesc; - createSwapChainDesc.swapchain = (IDXGISwapChain4**)ppSwapChain; - - - fgSkipSCWrapping = true; - Config::Instance()->dxgiSkipSpoofing = true; - Config::Instance()->SkipHeapCapture = true; - - auto result = _createContext(&ImGuiOverlayDx::fgSwapChainContext, &createSwapChainDesc.header, nullptr); - - Config::Instance()->SkipHeapCapture = false; - Config::Instance()->dxgiSkipSpoofing = false; - fgSkipSCWrapping = false; - - if (result == FFX_API_RETURN_OK) - { - scInfo.swapChainFormat = pDesc->BufferDesc.Format; - scInfo.swapChainBufferCount = pDesc->BufferCount; - scInfo.swapChain = (IDXGISwapChain4*)*ppSwapChain; - fgSwapChains.insert_or_assign(pDesc->OutputWindow, scInfo); - return S_OK; - } - - LOG_ERROR("_createContext error: {}", result); - - return E_INVALIDARG; - } - - auto result = oCreateSwapChain(pFactory, pDevice, pDesc, ppSwapChain); - if (result == S_OK) - { - // check for SL proxy - IID riid; - IDXGISwapChain* real = nullptr; - auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); - - if (iidResult == S_OK) - { - auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); - - if (qResult == S_OK && real != nullptr) - { - LOG_INFO("Streamline proxy found"); - real->Release(); - } - else - { - LOG_DEBUG("Streamline proxy not found"); - } - } - - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pDesc->BufferDesc.Width, pDesc->BufferDesc.Height, (UINT)pDesc->BufferDesc.Format, pDesc->BufferCount, pDesc->Windowed); - - if (Util::GetProcessWindow() == pDesc->OutputWindow) - { - Config::Instance()->ScreenWidth = pDesc->BufferDesc.Width; - Config::Instance()->ScreenHeight = pDesc->BufferDesc.Height; - } - - LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDesc->OutputWindow); - *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, pDesc->OutputWindow, Present, CleanupRenderTarget); - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); - } - - return result; -} - -static HRESULT hkCreateSwapChainForHwnd(IDXGIFactory* This, IUnknown* pDevice, HWND hWnd, DXGI_SWAP_CHAIN_DESC1* pDesc, - DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) -{ - LOG_FUNC(); - - *ppSwapChain = nullptr; - - if (Config::Instance()->VulkanCreatingSC) - { - LOG_WARN("Vulkan is creating swapchain!"); - return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - } - - if (pDevice == nullptr) - { - LOG_WARN("pDevice is nullptr!"); - return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - } - - if (pDesc->Height == 2 && pDesc->Width == 2) - { - LOG_WARN("RTSS call!"); - return oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - } - - ID3D12CommandQueue* cq = nullptr; - if (Config::Instance()->FGUseFGSwapChain.value_or(true) && !fgSkipSCWrapping && _createContext != nullptr && pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) - { - SwapChainInfo scInfo{}; - scInfo.gameCommandQueue = cq; - - cq->SetName(L"GameQueueHwnd"); - cq->Release(); - - fgQueues.push_back((ID3D12CommandQueue*)pDevice); - - ffxCreateContextDescFrameGenerationSwapChainForHwndDX12 createSwapChainDesc{}; - createSwapChainDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_FOR_HWND_DX12; - - createSwapChainDesc.fullscreenDesc = pFullscreenDesc; - createSwapChainDesc.hwnd = hWnd; - createSwapChainDesc.dxgiFactory = This; - createSwapChainDesc.gameQueue = (ID3D12CommandQueue*)pDevice; - createSwapChainDesc.desc = pDesc; - createSwapChainDesc.swapchain = (IDXGISwapChain4**)ppSwapChain; - - Config::Instance()->dxgiSkipSpoofing = true; - fgSkipSCWrapping = true; - Config::Instance()->SkipHeapCapture = true; - - auto result = _createContext(&ImGuiOverlayDx::fgSwapChainContext, &createSwapChainDesc.header, nullptr); - - Config::Instance()->SkipHeapCapture = false; - fgSkipSCWrapping = false; - Config::Instance()->dxgiSkipSpoofing = false; - - if (result == FFX_API_RETURN_OK) - { - scInfo.swapChainFormat = pDesc->Format; - scInfo.swapChainBufferCount = pDesc->BufferCount; - scInfo.swapChain = (IDXGISwapChain4*)*ppSwapChain; - fgSwapChains.insert_or_assign(hWnd, scInfo); - return S_OK; - } - - LOG_ERROR("_createContext error: {}", result); - - return result; - } - - auto result = oCreateSwapChainForHwnd(This, pDevice, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, ppSwapChain); - if (result == S_OK) - { - // check for SL proxy - IID riid; - IDXGISwapChain1* real = nullptr; - auto iidResult = IIDFromString(L"{ADEC44E2-61F0-45C3-AD9F-1B37379284FF}", &riid); - - if (iidResult == S_OK) - { - IUnknown* real = nullptr; - auto qResult = (*ppSwapChain)->QueryInterface(riid, (void**)&real); - - if (qResult == S_OK && real != nullptr) - { - LOG_INFO("Streamline proxy found"); - real->Release(); - } - else - { - LOG_DEBUG("Streamline proxy not found"); - } - } - - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Flags: {4:X}", pDesc->Width, pDesc->Height, (UINT)pDesc->Format, pDesc->BufferCount, pDesc->Flags); - - if (Util::GetProcessWindow() == hWnd) - { - Config::Instance()->ScreenWidth = pDesc->Width; - Config::Instance()->ScreenHeight = pDesc->Height; - } - - LOG_DEBUG("created new swapchain: {0:X}, hWnd: {1:X}", (UINT64)*ppSwapChain, (UINT64)hWnd); - *ppSwapChain = new WrappedIDXGISwapChain4(real == nullptr ? *ppSwapChain : real, pDevice, hWnd, Present, CleanupRenderTarget); - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)pDevice); - } - - return result; -} - -static HRESULT hkCreateDXGIFactory(REFIID riid, IDXGIFactory** ppFactory) -{ - auto result = o_CreateDXGIFactory(riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChain == nullptr) - { - void** pFactoryVTable = *reinterpret_cast(*ppFactory); - - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - - if (oCreateSwapChain != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourTransactionCommit(); - } - } - - return result; -} - -static HRESULT hkCreateDXGIFactory1(REFIID riid, IDXGIFactory1** ppFactory) -{ - auto result = o_CreateDXGIFactory1(riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChainForHwnd == nullptr) - { - IDXGIFactory2* factory2 = nullptr; - - if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) - { - void** pFactoryVTable = *reinterpret_cast(factory2); - - bool skip = false; - - if (oCreateSwapChain == nullptr) - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - else - skip = true; - - oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; - - if (oCreateSwapChainForHwnd != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (!skip) - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); - - DetourTransactionCommit(); - } - - factory2->Release(); - factory2 = nullptr; - } - } - - return result; -} - -static HRESULT hkCreateDXGIFactory2(UINT Flags, REFIID riid, IDXGIFactory2** ppFactory) -{ - auto result = o_CreateDXGIFactory2(Flags, riid, ppFactory); - - if (result == S_OK) - AttachToFactory(*ppFactory); - - if (result == S_OK && oCreateSwapChainForHwnd == nullptr) - { - IDXGIFactory2* factory2 = nullptr; - - if ((*ppFactory)->QueryInterface(IID_PPV_ARGS(&factory2)) == S_OK && factory2 != nullptr) - { - void** pFactoryVTable = *reinterpret_cast(factory2); - - bool skip = false; - - if (oCreateSwapChain == nullptr) - oCreateSwapChain = (PFN_CreateSwapChain)pFactoryVTable[10]; - else - skip = true; - - oCreateSwapChainForHwnd = (PFN_CreateSwapChainForHwnd)pFactoryVTable[15]; - - if (oCreateSwapChainForHwnd != nullptr) - { - LOG_INFO("Hooking native DXGIFactory"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (!skip) - DetourAttach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - - DetourAttach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); - - DetourTransactionCommit(); - } - - factory2->Release(); - factory2 = nullptr; - } - } - - return result; -} - -static HRESULT hkEnumAdapterByGpuPreference(IDXGIFactory6* This, UINT Adapter, DXGI_GPU_PREFERENCE GpuPreference, REFIID riid, IUnknown** ppvAdapter) -{ - auto result = ptrEnumAdapterByGpuPreference(This, Adapter, GpuPreference, riid, ppvAdapter); - - if (result == S_OK) - CheckAdapter(*ppvAdapter); - - return result; -} - -static HRESULT hkEnumAdapterByLuid(IDXGIFactory4* This, LUID AdapterLuid, REFIID riid, IUnknown** ppvAdapter) -{ - auto result = ptrEnumAdapterByLuid(This, AdapterLuid, riid, ppvAdapter); - - if (result == S_OK) - CheckAdapter(*ppvAdapter); - - return result; -} - -static HRESULT hkEnumAdapters1(IDXGIFactory1* This, UINT Adapter, IUnknown** ppAdapter) -{ - auto result = ptrEnumAdapters1(This, Adapter, ppAdapter); - - if (result == S_OK) - CheckAdapter(*ppAdapter); - - return result; -} - -static HRESULT hkEnumAdapters(IDXGIFactory* This, UINT Adapter, IUnknown** ppAdapter) -{ - auto result = ptrEnumAdapters(This, Adapter, ppAdapter); - - if (result == S_OK) - CheckAdapter(*ppAdapter); - - return result; -} - -#pragma endregion - -#pragma region DirectX hooks - - - -static void HookCommandList(ID3D12Device* InDevice) -{ - if (o_OMSetRenderTargets != nullptr || o_DrawIndexedInstanced != nullptr) - return; - - ID3D12GraphicsCommandList* commandList = nullptr; - ID3D12CommandAllocator* commandAllocator = nullptr; - - if (InDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)) == S_OK) - { - if (InDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, nullptr, IID_PPV_ARGS(&commandList)) == S_OK) - { - // Get the vtable pointer - PVOID* pVTable = *(PVOID**)commandList; - - // hudless shader - o_OMSetRenderTargets = (PFN_OMSetRenderTargets)pVTable[46]; - o_SetGraphicsRootDescriptorTable = (PFN_SetGraphicsRootDescriptorTable)pVTable[32]; - o_DrawInstanced = (PFN_DrawInstanced)pVTable[12]; - o_DrawIndexedInstanced = (PFN_DrawIndexedInstanced)pVTable[13]; - - // hudless compute - o_SetComputeRootDescriptorTable = (PFN_SetComputeRootDescriptorTable)pVTable[31]; - o_Dispatch = (PFN_Dispatch)pVTable[14]; - - // hudless copy -#ifdef USE_COPY_RESOURCE - o_CopyResource = (PFN_CopyResource)pVTable[17]; -#endif - o_CopyTextureRegion = (PFN_CopyTextureRegion)pVTable[16]; - -#ifdef USE_RESOURCE_DISCARD - // release resource - o_DiscardResource = (PFN_DiscardResource)pVTable[51]; -#endif - - if (o_OMSetRenderTargets != nullptr || o_DrawIndexedInstanced != nullptr || o_DrawInstanced != nullptr) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (o_OMSetRenderTargets != nullptr) - DetourAttach(&(PVOID&)o_OMSetRenderTargets, hkOMSetRenderTargets); - - if (o_DrawIndexedInstanced != nullptr) - DetourAttach(&(PVOID&)o_DrawIndexedInstanced, hkDrawIndexedInstanced); - - if (o_DrawInstanced != nullptr) - DetourAttach(&(PVOID&)o_DrawInstanced, hkDrawInstanced); - - if (o_CopyTextureRegion != nullptr) - DetourAttach(&(PVOID&)o_CopyTextureRegion, hkCopyTextureRegion); - -#ifdef USE_COPY_RESOURCE - if (o_CopyResource != nullptr) - DetourAttach(&(PVOID&)o_CopyResource, hkCopyResource); -#endif - if (o_SetGraphicsRootDescriptorTable != nullptr) - DetourAttach(&(PVOID&)o_SetGraphicsRootDescriptorTable, hkSetGraphicsRootDescriptorTable); - - if (o_SetComputeRootDescriptorTable != nullptr) - DetourAttach(&(PVOID&)o_SetComputeRootDescriptorTable, hkSetComputeRootDescriptorTable); - - if (o_Dispatch != nullptr) - DetourAttach(&(PVOID&)o_Dispatch, hkDispatch); - -#ifdef USE_RESOURCE_DISCARD - if (o_DiscardResource != nullptr) - DetourAttach(&(PVOID&)o_DiscardResource, hkDiscardResource); -#endif - DetourTransactionCommit(); - } - - commandList->Close(); - commandList->Release(); - } - - commandAllocator->Reset(); - commandAllocator->Release(); - } -} - -static void HookToDevice(ID3D12Device* InDevice) -{ - if (o_CreateSampler != nullptr || InDevice == nullptr) - return; - - LOG_FUNC(); - - // Get the vtable pointer - PVOID* pVTable = *(PVOID**)InDevice; - - // hudless - o_CreateSampler = (PFN_CreateSampler)pVTable[22]; - o_CreateRenderTargetView = (PFN_CreateRenderTargetView)pVTable[20]; - o_CreateDescriptorHeap = (PFN_CreateDescriptorHeap)pVTable[14]; - o_CopyDescriptors = (PFN_CopyDescriptors)pVTable[23]; - o_CopyDescriptorsSimple = (PFN_CopyDescriptorsSimple)pVTable[24]; - o_CreateShaderResourceView = (PFN_CreateShaderResourceView)pVTable[18]; - o_CreateUnorderedAccessView = (PFN_CreateUnorderedAccessView)pVTable[19]; - - // Apply the detour - if (o_CreateSampler != nullptr || o_CreateRenderTargetView != nullptr) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (o_CreateDescriptorHeap != nullptr) - DetourAttach(&(PVOID&)o_CreateDescriptorHeap, hkCreateDescriptorHeap); - - if (o_CreateSampler != nullptr) - DetourAttach(&(PVOID&)o_CreateSampler, hkCreateSampler); - - if (Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true)) - { - if (o_CreateRenderTargetView != nullptr) - DetourAttach(&(PVOID&)o_CreateRenderTargetView, hkCreateRenderTargetView); - - if (o_CreateShaderResourceView != nullptr) - DetourAttach(&(PVOID&)o_CreateShaderResourceView, hkCreateShaderResourceView); - - if (o_CreateUnorderedAccessView != nullptr) - DetourAttach(&(PVOID&)o_CreateUnorderedAccessView, hkCreateUnorderedAccessView); - - if (o_CopyDescriptors != nullptr) - DetourAttach(&(PVOID&)o_CopyDescriptors, hkCopyDescriptors); - - if (o_CopyDescriptorsSimple != nullptr) - DetourAttach(&(PVOID&)o_CopyDescriptorsSimple, hkCopyDescriptorsSimple); - } - - DetourTransactionCommit(); - } - - if (Config::Instance()->FGUseFGSwapChain.value_or(true) && Config::Instance()->OverlayMenu.value_or(true)) - HookCommandList(InDevice); -} - -static void HookToDevice(ID3D11Device* InDevice) -{ - if (o_CreateSamplerState != nullptr || InDevice == nullptr) - return; - - LOG_FUNC(); - - // Get the vtable pointer - PVOID* pVTable = *(PVOID**)InDevice; - - o_CreateSamplerState = (PFN_CreateSamplerState)pVTable[23]; - - // Apply the detour - if (o_CreateSamplerState != nullptr) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DetourAttach(&(PVOID&)o_CreateSamplerState, hkCreateSamplerState); - - DetourTransactionCommit(); - } -} - -static HRESULT hkD3D11On12CreateDevice(IUnknown* pDevice, UINT Flags, D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, IUnknown** ppCommandQueues, - UINT NumQueues, UINT NodeMask, ID3D11Device** ppDevice, ID3D11DeviceContext** ppImmediateContext, D3D_FEATURE_LEVEL* pChosenFeatureLevel) -{ - LOG_FUNC(); - - bool rtss = false; - - // Assuming RTSS is creating a D3D11on12 device, not sure why but sometimes RTSS tries to create - // it's D3D11on12 device with old CommandQueue which results crash - // I am changing it's CommandQueue with current swapchain's command queue - if (currentSCCommandQueue != nullptr && *ppCommandQueues != currentSCCommandQueue && GetModuleHandle(L"RTSSHooks64.dll") != nullptr && pDevice == g_pd3dDeviceParam) - { - LOG_INFO("Replaced RTSS CommandQueue with correct one {0:X} -> {1:X}", (UINT64)*ppCommandQueues, (UINT64)currentSCCommandQueue); - *ppCommandQueues = currentSCCommandQueue; - rtss = true; - } - - auto result = o_D3D11On12CreateDevice(pDevice, Flags, pFeatureLevels, FeatureLevels, ppCommandQueues, NumQueues, NodeMask, ppDevice, ppImmediateContext, pChosenFeatureLevel); - - if (result == S_OK && *ppDevice != nullptr && !rtss && !_d3d12Captured) - { - LOG_INFO("Device captured, D3D11Device: {0:X}", (UINT64)*ppDevice); - d3d11on12Device = *ppDevice; - HookToDevice(d3d11on12Device); - } - - LOG_FUNC_RESULT(result); - - return result; -} - -static HRESULT hkD3D11CreateDevice(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, - UINT FeatureLevels, UINT SDKVersion, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) -{ - LOG_FUNC(); - - static const D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_11_1, - }; - - D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; - - for (UINT i = 0; i < FeatureLevels; ++i) - { - maxLevel = std::max(maxLevel, pFeatureLevels[i]); - } - - if (maxLevel == D3D_FEATURE_LEVEL_11_0) - { - LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); - pFeatureLevels = levels; - FeatureLevels = ARRAYSIZE(levels); - } - - auto result = o_D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); - - if (result == S_OK && *ppDevice != nullptr && !_d3d12Captured) - { - LOG_INFO("Device captured"); - d3d11Device = *ppDevice; - - HookToDevice(d3d11Device); - } - - LOG_FUNC_RESULT(result); - - return result; -} - -static HRESULT hkD3D11CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, CONST D3D_FEATURE_LEVEL* pFeatureLevels, - UINT FeatureLevels, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D11Device** ppDevice, D3D_FEATURE_LEVEL* pFeatureLevel, ID3D11DeviceContext** ppImmediateContext) -{ - LOG_FUNC(); - - static const D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_11_1, - }; - - D3D_FEATURE_LEVEL maxLevel = D3D_FEATURE_LEVEL_1_0_CORE; - - for (UINT i = 0; i < FeatureLevels; ++i) - { - maxLevel = std::max(maxLevel, pFeatureLevels[i]); - } - - if (maxLevel == D3D_FEATURE_LEVEL_11_0) - { - LOG_INFO("Overriding D3D_FEATURE_LEVEL, Game requested D3D_FEATURE_LEVEL_11_0, we need D3D_FEATURE_LEVEL_11_1!"); - pFeatureLevels = levels; - FeatureLevels = ARRAYSIZE(levels); - } - - if (pSwapChainDesc != nullptr && pSwapChainDesc->BufferDesc.Height == 2 && pSwapChainDesc->BufferDesc.Width == 2) - { - LOG_WARN("RTSS call!"); - return o_D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); - } - - IDXGISwapChain* buffer = nullptr; - auto result = o_D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, &buffer, ppDevice, pFeatureLevel, ppImmediateContext); - - if (result == S_OK && *ppDevice != nullptr && !_d3d12Captured) - { - LOG_INFO("Device captured"); - d3d11Device = *ppDevice; - - HookToDevice(d3d11Device); - - if (pSwapChainDesc != nullptr) - { - LOG_DEBUG("Width: {0}, Height: {1}, Format: {2:X}, Count: {3}, Windowed: {4}", pSwapChainDesc->BufferDesc.Width, pSwapChainDesc->BufferDesc.Height, (UINT)pSwapChainDesc->BufferDesc.Format, pSwapChainDesc->BufferCount, pSwapChainDesc->Windowed); - - if (Util::GetProcessWindow() == pSwapChainDesc->OutputWindow) - { - Config::Instance()->ScreenWidth = pSwapChainDesc->BufferDesc.Width; - Config::Instance()->ScreenHeight = pSwapChainDesc->BufferDesc.Height; - } - - IDXGIFactory* factory = nullptr; - result = CreateDXGIFactory(IID_PPV_ARGS(&factory)); - if (result == S_OK) - { - LOG_DEBUG("creating new swapchain"); - result = factory->CreateSwapChain(*ppDevice, pSwapChainDesc, ppSwapChain); - - if (result == S_OK) - LOG_DEBUG("created new WrappedIDXGISwapChain4: {0:X}, pDevice: {1:X}", (UINT64)*ppSwapChain, (UINT64)d3d11Device); - else - LOG_DEBUG("factory->CreateSwapChain error: {0:X}", (UINT64)result); - - factory->Release(); - } - } - } - - LOG_FUNC_RESULT(result); - - return result; -} - -static HRESULT hkD3D12CreateDevice(IDXGIAdapter* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice) -{ - LOG_FUNC(); - - auto result = o_D3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); - - if (result == S_OK && *ppDevice != nullptr) - { - LOG_DEBUG("Device captured: {0:X}", (size_t)*ppDevice); - g_pd3dDeviceParam = (ID3D12Device*)*ppDevice; - HookToDevice(g_pd3dDeviceParam); - _d3d12Captured = true; - } - - LOG_FUNC_RESULT(result); - - return result; -} - -static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor) -{ - if (pDesc == nullptr || device == nullptr) - return; - - D3D12_SAMPLER_DESC newDesc{}; - - newDesc.AddressU = pDesc->AddressU; - newDesc.AddressV = pDesc->AddressV; - newDesc.AddressW = pDesc->AddressW; - newDesc.BorderColor[0] = pDesc->BorderColor[0]; - newDesc.BorderColor[1] = pDesc->BorderColor[1]; - newDesc.BorderColor[2] = pDesc->BorderColor[2]; - newDesc.BorderColor[3] = pDesc->BorderColor[3]; - newDesc.ComparisonFunc = pDesc->ComparisonFunc; - - if (Config::Instance()->AnisotropyOverride.has_value() && - (pDesc->Filter == D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT || pDesc->Filter == D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT || - pDesc->Filter == D3D12_FILTER_MIN_MAG_MIP_LINEAR || pDesc->Filter == D3D12_FILTER_ANISOTROPIC)) - { - LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pDesc->Filter); - newDesc.Filter = D3D12_FILTER_ANISOTROPIC; - newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); - } - else - { - newDesc.Filter = pDesc->Filter; - newDesc.MaxAnisotropy = pDesc->MaxAnisotropy; - } - - newDesc.MaxLOD = pDesc->MaxLOD; - newDesc.MinLOD = pDesc->MinLOD; - newDesc.MipLODBias = pDesc->MipLODBias; - - if (newDesc.MipLODBias < 0.0f) - { - if (Config::Instance()->MipmapBiasOverride.has_value()) - { - LOG_INFO("Overriding mipmap bias {0} -> {1}", pDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); - newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); - } - - Config::Instance()->lastMipBias = newDesc.MipLODBias; - } - - return o_CreateSampler(device, &newDesc, DestDescriptor); -} - -static HRESULT hkCreateSamplerState(ID3D11Device* This, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) -{ - if (pSamplerDesc == nullptr || This == nullptr) - return E_INVALIDARG; - - if (_d3d12Captured) - return o_CreateSamplerState(This, pSamplerDesc, ppSamplerState); - - LOG_FUNC(); - - D3D11_SAMPLER_DESC newDesc{}; - - newDesc.AddressU = pSamplerDesc->AddressU; - newDesc.AddressV = pSamplerDesc->AddressV; - newDesc.AddressW = pSamplerDesc->AddressW; - newDesc.ComparisonFunc = pSamplerDesc->ComparisonFunc; - newDesc.BorderColor[0] = pSamplerDesc->BorderColor[0]; - newDesc.BorderColor[1] = pSamplerDesc->BorderColor[1]; - newDesc.BorderColor[2] = pSamplerDesc->BorderColor[2]; - newDesc.BorderColor[3] = pSamplerDesc->BorderColor[3]; - newDesc.MinLOD = pSamplerDesc->MinLOD; - newDesc.MaxLOD = pSamplerDesc->MaxLOD; - - if (Config::Instance()->AnisotropyOverride.has_value() && - (pSamplerDesc->Filter == D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT || - pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT || - pSamplerDesc->Filter == D3D11_FILTER_MIN_MAG_MIP_LINEAR || - pSamplerDesc->Filter == D3D11_FILTER_ANISOTROPIC)) - { - LOG_INFO("Overriding Anisotrpic ({2}) filtering {0} -> {1}", pSamplerDesc->MaxAnisotropy, Config::Instance()->AnisotropyOverride.value(), (UINT)pSamplerDesc->Filter); - newDesc.Filter = D3D11_FILTER_ANISOTROPIC; - newDesc.MaxAnisotropy = Config::Instance()->AnisotropyOverride.value(); - } - else - { - newDesc.Filter = pSamplerDesc->Filter; - newDesc.MaxAnisotropy = pSamplerDesc->MaxAnisotropy; - } - - newDesc.MipLODBias = pSamplerDesc->MipLODBias; - - if (newDesc.MipLODBias < 0.0f) - { - if (Config::Instance()->MipmapBiasOverride.has_value()) - { - LOG_INFO("Overriding mipmap bias {0} -> {1}", pSamplerDesc->MipLODBias, Config::Instance()->MipmapBiasOverride.value()); - newDesc.MipLODBias = Config::Instance()->MipmapBiasOverride.value(); - } - - Config::Instance()->lastMipBias = newDesc.MipLODBias; - } - - return o_CreateSamplerState(This, &newDesc, ppSamplerState); -} - -#pragma endregion - static void RenderImGui_DX11(IDXGISwapChain* pSwapChain) { bool drawMenu = false; @@ -3069,8 +468,7 @@ static void RenderImGui_DX12(IDXGISwapChain* pSwapChainPlain) } ID3D12CommandList* ppCommandLists[] = { g_pd3dCommandList }; - ImGuiOverlayDx::fgCommandQueue->ExecuteCommandLists(1, ppCommandLists); - //LOG_DEBUG_ONLY("Menu ok"); + ((ID3D12CommandQueue*)currentSCCommandQueue)->ExecuteCommandLists(1, ppCommandLists); } else { @@ -3085,374 +483,109 @@ static void RenderImGui_DX12(IDXGISwapChain* pSwapChainPlain) pSwapChain->Release(); } -void DeatachAllHooks() +void ImGuiOverlayDx::CleanupRenderTarget(bool clearQueue, HWND hWnd) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); + LOG_FUNC(); - if (o_D3D11CreateDevice != nullptr) - { - DetourDetach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); - o_D3D11CreateDevice = nullptr; - } - - if (o_D3D11On12CreateDevice != nullptr) - { - DetourDetach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); - o_D3D11On12CreateDevice = nullptr; - } - - if (o_D3D12CreateDevice != nullptr) - { - DetourDetach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); - o_D3D12CreateDevice = nullptr; - } - - if (o_CreateDXGIFactory1 != nullptr) - { - DetourDetach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); - o_CreateDXGIFactory1 = nullptr; - } - - if (o_CreateDXGIFactory2 != nullptr) - { - DetourDetach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); - o_CreateDXGIFactory2 = nullptr; - } - - if (oCreateSwapChain != nullptr) - { - DetourDetach(&(PVOID&)oCreateSwapChain, hkCreateSwapChain); - oCreateSwapChain = nullptr; - } - - if (oCreateSwapChainForHwnd != nullptr) - { - DetourDetach(&(PVOID&)oCreateSwapChainForHwnd, hkCreateSwapChainForHwnd); - oCreateSwapChainForHwnd = nullptr; - } - - if (o_CreateSampler != nullptr) - { - DetourDetach(&(PVOID&)o_CreateSampler, hkCreateSampler); - o_CreateSampler = nullptr; - } - - DetourTransactionCommit(); + if (_dx11Device) + CleanupRenderTargetDx11(false); + else + CleanupRenderTargetDx12(clearQueue); } -void ImGuiOverlayDx::HookDx() +void ImGuiOverlayDx::Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd) { - if (_isInited) - return; + LOG_DEBUG(""); - o_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)DetourFindFunction("d3d12.dll", "D3D12CreateDevice"); - if (o_D3D12CreateDevice != nullptr) + HRESULT presentResult; + + ID3D12CommandQueue* cq = nullptr; + ID3D11Device* device = nullptr; + ID3D12Device* device12 = nullptr; + + // try to obtain directx objects and find the path + if (pDevice->QueryInterface(IID_PPV_ARGS(&device)) == S_OK) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); + if (!_dx11Device) + LOG_DEBUG("D3D11Device captured"); - DetourAttach(&(PVOID&)o_D3D12CreateDevice, hkD3D12CreateDevice); - - DetourTransactionCommit(); + _dx11Device = true; } - - o_D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11CreateDevice"); - o_D3D11CreateDeviceAndSwapChain = (PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)DetourFindFunction("d3d11.dll", "D3D11CreateDeviceAndSwapChain"); - o_D3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)DetourFindFunction("d3d11.dll", "D3D11On12CreateDevice"); - if (o_D3D11CreateDevice != nullptr || o_D3D11On12CreateDevice != nullptr || o_D3D11CreateDeviceAndSwapChain != nullptr) + else if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); + if (!_dx12Device) + LOG_DEBUG("D3D12CommandQueue captured"); - if (o_D3D11CreateDevice != nullptr) - DetourAttach(&(PVOID&)o_D3D11CreateDevice, hkD3D11CreateDevice); + currentSCCommandQueue = pDevice; - if (o_D3D11On12CreateDevice != nullptr) - DetourAttach(&(PVOID&)o_D3D11On12CreateDevice, hkD3D11On12CreateDevice); - - if (o_D3D11CreateDeviceAndSwapChain != nullptr) - DetourAttach(&(PVOID&)o_D3D11CreateDeviceAndSwapChain, hkD3D11CreateDeviceAndSwapChain); - - DetourTransactionCommit(); - } - - o_CreateDXGIFactory = (PFN_CreateDXGIFactory)DetourFindFunction("dxgi.dll", "CreateDXGIFactory"); - o_CreateDXGIFactory1 = (PFN_CreateDXGIFactory1)DetourFindFunction("dxgi.dll", "CreateDXGIFactory1"); - o_CreateDXGIFactory2 = (PFN_CreateDXGIFactory2)DetourFindFunction("dxgi.dll", "CreateDXGIFactory2"); - - if (o_CreateDXGIFactory1 != nullptr) - { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (o_CreateDXGIFactory != nullptr) - DetourAttach(&(PVOID&)o_CreateDXGIFactory, hkCreateDXGIFactory); - - if (o_CreateDXGIFactory1 != nullptr) - DetourAttach(&(PVOID&)o_CreateDXGIFactory1, hkCreateDXGIFactory1); - - if (o_CreateDXGIFactory2 != nullptr) - DetourAttach(&(PVOID&)o_CreateDXGIFactory2, hkCreateDXGIFactory2); - - DetourTransactionCommit(); - } - - LoadFSR31Funcs(); -} - -UINT ImGuiOverlayDx::ClearFrameResources() -{ - LOG_DEBUG_ONLY(" <-- {}", fgFrameIndex); - - fgFrameIndex = (fgFrameIndex + 1) % FG_BUFFER_SIZE; - - LOG_DEBUG_ONLY(" <-- {}", fgFrameIndex); - fgUpscaledFound = false; - - return fgFrameIndex; -} - -UINT ImGuiOverlayDx::GetFrame() -{ - return fgFrameIndex; -} - -void ImGuiOverlayDx::NewFrame() -{ - auto fIndex = fgFrameIndex; - auto newIndex = (fIndex + 2) % FG_BUFFER_SIZE; - - { - fgCopySource[newIndex] = nullptr; - } - - if (fgPossibleHudless[newIndex].size() != 0) - { - std::unique_lock lock(hudlessMutex[newIndex]); - fgPossibleHudless[newIndex].clear(); - } - - if (ImGuiOverlayDx::fgHUDlessCaptureCounter[newIndex] != 0) - { - std::unique_lock lock(counterMutex[newIndex]); - ImGuiOverlayDx::fgHUDlessCaptureCounter[newIndex] = 0; - } -} - -void ImGuiOverlayDx::UnHookDx() -{ - if (!Config::Instance()->IsRunningOnDXVK) - { - if (_isInited && ImGuiOverlayBase::IsInited() && ImGui::GetIO().BackendRendererUserData) + if (cq->GetDevice(IID_PPV_ARGS(&device12)) == S_OK) { - if (_dx11Device) - ImGui_ImplDX11_Shutdown(); - else - ImGui_ImplDX12_Shutdown(); - } + if (!_dx12Device) + LOG_DEBUG("D3D12Device captured"); - ImGuiOverlayBase::Shutdown(); - - if (_isInited) - { - if (_dx11Device) - CleanupRenderTargetDx11(true); - else - CleanupRenderTargetDx12(true); + _dx12Device = true; } } - DeatachAllHooks(); - - _isInited = false; -} - -void ImGuiOverlayDx::ReleaseFGObjects() -{ - for (size_t i = 0; i < 4; i++) + // Process window handle changed, update base + if (ImGuiOverlayBase::Handle() != hWnd) { - if (ImGuiOverlayDx::fgCopyCommandAllocators[i] != nullptr) + LOG_DEBUG("Handle changed"); + + if (ImGuiOverlayBase::IsInited()) + ImGuiOverlayBase::Shutdown(); + + ImGuiOverlayBase::Init(hWnd); + + _isInited = false; + } + + // Init + if (!_isInited) + { + if (_dx11Device) { - ImGuiOverlayDx::fgCopyCommandAllocators[i]->Release(); - ImGuiOverlayDx::fgCopyCommandAllocators[i] = nullptr; + CleanupRenderTargetDx11(false); + + g_pd3dDevice = device; + g_pd3dDevice->AddRef(); + + CreateRenderTargetDx11(pSwapChain); + ImGuiOverlayBase::Dx11Ready(); + _isInited = true; + } + else if (_dx12Device && (g_pd3dDeviceParam != nullptr || device12 != nullptr)) + { + if (g_pd3dDeviceParam != nullptr && device12 == nullptr) + device12 = g_pd3dDeviceParam; + + CleanupRenderTargetDx12(true); + + g_pd3dCommandQueue = cq; + g_pd3dDeviceParam = device12; + + g_pd3dCommandQueue->AddRef(); + g_pd3dDeviceParam->AddRef(); + + ImGuiOverlayBase::Dx12Ready(); + _isInited = true; } } - if (ImGuiOverlayDx::fgCopyCommandList != nullptr) - { - ImGuiOverlayDx::fgCopyCommandList->Release(); - ImGuiOverlayDx::fgCopyCommandList = nullptr; - } + // Render menu + if (_dx11Device) + RenderImGui_DX11(pSwapChain); + else if (_dx12Device) + RenderImGui_DX12(pSwapChain); - if (ImGuiOverlayDx::fgCopyCommandQueue != nullptr) - { - ImGuiOverlayDx::fgCopyCommandQueue->Release(); - ImGuiOverlayDx::fgCopyCommandQueue = nullptr; - } + // release used objects + if (cq != nullptr) + cq->Release(); - if (ImGuiOverlayDx::fgFormatTransfer != nullptr) - { - delete ImGuiOverlayDx::fgFormatTransfer; - ImGuiOverlayDx::fgFormatTransfer = nullptr; - } + if (device != nullptr) + device->Release(); + + if (device12 != nullptr) + device12->Release(); } -void ImGuiOverlayDx::CreateFGObjects(ID3D12Device* InDevice) -{ - if (ImGuiOverlayDx::fgCopyCommandQueue != nullptr) - return; - - do - { - HRESULT result; - - for (size_t i = 0; i < 4; i++) - { - result = InDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&ImGuiOverlayDx::fgCopyCommandAllocators[i])); - if (result != S_OK) - { - LOG_ERROR("CreateCommandAllocators[{0}]: {1:X}", i, (unsigned long)result); - break; - } - ImGuiOverlayDx::fgCopyCommandAllocators[i]->SetName(L"fgCopyCommandAllocator"); - } - - result = InDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, ImGuiOverlayDx::fgCopyCommandAllocators[0], NULL, IID_PPV_ARGS(&ImGuiOverlayDx::fgCopyCommandList)); - if (result != S_OK) - { - LOG_ERROR("CreateCommandList: {0:X}", (unsigned long)result); - break; - } - ImGuiOverlayDx::fgCopyCommandList->SetName(L"fgCopyCommandList"); - - result = ImGuiOverlayDx::fgCopyCommandList->Close(); - if (result != S_OK) - { - LOG_ERROR("ImGuiOverlayDx::fgCopyCommandList->Close: {0:X}", (unsigned long)result); - break; - } - - // Create a command queue for frame generation - D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}; - copyQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - copyQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - copyQueueDesc.NodeMask = 0; - - if (Config::Instance()->FGHighPriority.value_or(false)) - copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH; - else - copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; - - HRESULT hr = InDevice->CreateCommandQueue(©QueueDesc, IID_PPV_ARGS(&ImGuiOverlayDx::fgCopyCommandQueue)); - if (result != S_OK) - { - LOG_ERROR("CreateCommandQueue: {0:X}", (unsigned long)result); - break; - } - ImGuiOverlayDx::fgCopyCommandQueue->SetName(L"fgCopyCommandQueue"); - - ImGuiOverlayDx::fgFormatTransfer = new FT_Dx12("FormatTransfer", InDevice, ImGuiOverlayDx::swapchainFormat); - - } while (false); -} - -void ImGuiOverlayDx::CreateFGContext(ID3D12Device* InDevice, IFeature* deviceContext) -{ - if (ImGuiOverlayDx::fgContext != nullptr) - { - ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; - m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; - m_FrameGenerationConfig.frameGenerationEnabled = true; - m_FrameGenerationConfig.swapChain = ImGuiOverlayDx::currentSwapchain; - //m_FrameGenerationConfig.presentCallback = nullptr; - m_FrameGenerationConfig.HUDLessColor = FfxApiResource({}); - - auto result = _configure(&ImGuiOverlayDx::fgContext, &m_FrameGenerationConfig.header); - - ImGuiOverlayDx::fgIsActive = (result == FFX_API_RETURN_OK); - - LOG_DEBUG("Reactivate"); - - return; - } - - ffxCreateBackendDX12Desc backendDesc{}; - backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12; - backendDesc.device = InDevice; - - ffxCreateContextDescFrameGeneration createFg{}; - createFg.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATION; - createFg.displaySize = { deviceContext->DisplayWidth(), deviceContext->DisplayHeight() }; - createFg.maxRenderSize = { deviceContext->DisplayWidth(), deviceContext->DisplayHeight() }; - createFg.flags = 0; - - if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_IsHDR) - createFg.flags |= FFX_FRAMEGENERATION_ENABLE_HIGH_DYNAMIC_RANGE; - - if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_DepthInverted) - createFg.flags |= FFX_FRAMEGENERATION_ENABLE_DEPTH_INVERTED; - - if (deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_MVJittered) - createFg.flags |= FFX_FRAMEGENERATION_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; - - if ((deviceContext->GetFeatureFlags() & NVSDK_NGX_DLSS_Feature_Flags_MVLowRes) == 0) - createFg.flags |= FFX_FRAMEGENERATION_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS; - - if (Config::Instance()->FGAsync.value_or(false)) - createFg.flags |= FFX_FRAMEGENERATION_ENABLE_ASYNC_WORKLOAD_SUPPORT; - - createFg.backBufferFormat = ffxApiGetSurfaceFormatDX12(ImGuiOverlayDx::swapchainFormat); - createFg.header.pNext = &backendDesc.header; - - Config::Instance()->dxgiSkipSpoofing = true; - Config::Instance()->SkipHeapCapture = true; - ffxReturnCode_t retCode = _createContext(&ImGuiOverlayDx::fgContext, &createFg.header, nullptr); - Config::Instance()->SkipHeapCapture = false; - Config::Instance()->dxgiSkipSpoofing = false; - LOG_INFO("_createContext result: {0:X}", retCode); - - ImGuiOverlayDx::fgIsActive = (retCode == FFX_API_RETURN_OK); - - LOG_DEBUG("Create"); -} - -void ImGuiOverlayDx::StopAndDestroyFGContext(bool destroy, bool shutDown) -{ - ImGuiOverlayDx::fgSkipHudlessChecks = false; - Config::Instance()->dxgiSkipSpoofing = true; - - if (ImGuiOverlayDx::fgContext != nullptr) - { - std::this_thread::sleep_for(std::chrono::milliseconds(250)); - - ffxConfigureDescFrameGeneration m_FrameGenerationConfig = {}; - m_FrameGenerationConfig.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION; - m_FrameGenerationConfig.frameGenerationEnabled = false; - m_FrameGenerationConfig.swapChain = ImGuiOverlayDx::currentSwapchain; - m_FrameGenerationConfig.presentCallback = nullptr; - m_FrameGenerationConfig.HUDLessColor = FfxApiResource({}); - - auto result = _configure(&ImGuiOverlayDx::fgContext, &m_FrameGenerationConfig.header); - - ImGuiOverlayDx::fgIsActive = false; - - if (!shutDown) - LOG_INFO(" FG _configure result: {0:X}", result); - } - - if (destroy && ImGuiOverlayDx::fgContext != nullptr) - { - auto result = _destroyContext(&ImGuiOverlayDx::fgContext, nullptr); - - if (!shutDown) - LOG_INFO(" FG _destroyContext result: {0:X}", result); - - ImGuiOverlayDx::fgContext = nullptr; - } - - Config::Instance()->dxgiSkipSpoofing = false; - - if (shutDown) - ReleaseFGObjects(); -} diff --git a/OptiScaler/imgui/imgui_overlay_dx.h b/OptiScaler/imgui/imgui_overlay_dx.h index 581e9d36..95e2944f 100644 --- a/OptiScaler/imgui/imgui_overlay_dx.h +++ b/OptiScaler/imgui/imgui_overlay_dx.h @@ -5,62 +5,8 @@ #include #include -#include -#include -#include -#include "../format_transfer/FT_Dx12.h" -#include "../backends/IFeature.h" - namespace ImGuiOverlayDx { - inline ID3D12QueryHeap* queryHeap = nullptr; - inline ID3D12Resource* readbackBuffer = nullptr; - inline bool dx12UpscaleTrig = false; - - inline const int QUERY_BUFFER_COUNT = 3; - inline ID3D11Query* disjointQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; - inline ID3D11Query* startQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; - inline ID3D11Query* endQueries[QUERY_BUFFER_COUNT] = { nullptr, nullptr, nullptr }; - inline bool dx11UpscaleTrig[QUERY_BUFFER_COUNT] = { false, false, false }; - - inline ID3D12CommandQueue* GameCommandQueue = nullptr; - - inline int currentFrameIndex = 0; - inline int previousFrameIndex = 0; - - inline IDXGISwapChain* currentSwapchain = nullptr; - inline DXGI_FORMAT swapchainFormat = DXGI_FORMAT_UNKNOWN; - - inline ffxContext fgSwapChainContext = nullptr; - inline ffxContext fgContext = nullptr; - inline float jitterX = 0.0; - inline float jitterY = 0.0; - inline float mvScaleX = 0.0; - inline float mvScaleY = 0.0; - inline const int FG_BUFFER_SIZE = 4; - inline ID3D12Resource* paramVelocity[FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; - inline ID3D12Resource* paramDepth[FG_BUFFER_SIZE] = { nullptr, nullptr,nullptr, nullptr }; - inline UINT64 fgHUDlessCaptureCounter[FG_BUFFER_SIZE] = { 0,0,0,0 }; - inline bool upscaleRan = false; - inline bool fgSkipHudlessChecks = false; - inline double fgFrameTime = 0.0; - inline ID3D12CommandQueue* fgCommandQueue = nullptr; - inline ID3D12CommandQueue* gameCommandQueue = nullptr; - inline ID3D12CommandQueue* fgCopyCommandQueue = nullptr; - inline ID3D12GraphicsCommandList* fgCopyCommandList = nullptr; - inline ID3D12CommandAllocator* fgCopyCommandAllocators[FG_BUFFER_SIZE] = { }; - inline UINT64 fgTarget = 10; - inline ID3D12Resource* fgUpscaledImage[FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; - inline FT_Dx12* fgFormatTransfer = nullptr; - inline bool fgIsActive = false; - - void UnHookDx(); - void HookDx(); - UINT ClearFrameResources(); - UINT GetFrame(); - void NewFrame(); - void ReleaseFGObjects(); - void CreateFGObjects(ID3D12Device* InDevice); - void CreateFGContext(ID3D12Device* InDevice, IFeature* deviceContext); - void StopAndDestroyFGContext(bool destroy, bool shutDown); + void CleanupRenderTarget(bool clearQueue, HWND hWnd); + void Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters, IUnknown* pDevice, HWND hWnd); } diff --git a/OptiScaler/imgui/imgui_overlay_vk.cpp b/OptiScaler/imgui/imgui_overlay_vk.cpp index d0a6863e..e03d89f4 100644 --- a/OptiScaler/imgui/imgui_overlay_vk.cpp +++ b/OptiScaler/imgui/imgui_overlay_vk.cpp @@ -2,33 +2,17 @@ #include "imgui_overlay_vk.h" #include "../Util.h" +#include "../Config.h" #include "imgui/imgui_impl_vulkan.h" #include "imgui/imgui_impl_win32.h" -#include "../detours/detours.h" -#include "../Config.h" - // Vulkan overlay code adopted from here: // https://gist.github.com/mem99/0ec31ca302927457f86b1d6756aaa8c4 // Need to check resize & recreate fixes -typedef struct VkWin32SurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkFlags flags; - HINSTANCE hinstance; - HWND hwnd; -} VkWin32SurfaceCreateInfoKHR; - static bool _isInited = false; -// for menu rendering -static VkDevice _device = VK_NULL_HANDLE; -static VkInstance _instance = VK_NULL_HANDLE; -static VkPhysicalDevice _PD = VK_NULL_HANDLE; -static HWND _hwnd = nullptr; - static bool _vulkanObjectsCreated = false; static std::mutex _vkCleanMutex; static std::mutex _vkPresentMutex; @@ -39,91 +23,7 @@ struct ImGui_ImplVulkanH_Frame* _ImVulkan_Frames = VK_NULL_HANDLE; static VkSemaphore* _ImVulkan_Semaphores = VK_NULL_HANDLE; static VkRenderPass _vkRenderPass = VK_NULL_HANDLE; -// hooking -typedef VkResult(*PFN_QueuePresentKHR)(VkQueue, const VkPresentInfoKHR*); -typedef VkResult(*PFN_CreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*); -typedef VkResult(*PFN_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*); - -PFN_vkCreateDevice o_vkCreateDevice = nullptr; -PFN_vkCreateInstance o_vkCreateInstance = nullptr; -PFN_vkCreateWin32SurfaceKHR o_vkCreateWin32SurfaceKHR = nullptr; -PFN_QueuePresentKHR o_QueuePresentKHR = nullptr; -PFN_CreateSwapchainKHR o_CreateSwapchainKHR = nullptr; - -static VkResult hkvkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice); -static VkResult hkvkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo); -static VkResult hkvkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); - -static void DestroyVulkanObjects(bool shutdown) -{ - if (_ImVulkan_Info.Device == VK_NULL_HANDLE) - return; - - if (!shutdown) - LOG_FUNC(); - - _vkCleanMutex.lock(); - - auto result = vkDeviceWaitIdle(_ImVulkan_Info.Device); - if (result != VK_SUCCESS && !shutdown) - LOG_WARN("vkDeviceWaitIdle error: {0:X}", (UINT)result); - - if (shutdown) - { - if (_vkRenderPass) - vkDestroyRenderPass(_ImVulkan_Info.Device, _vkRenderPass, VK_NULL_HANDLE); - - if (_ImVulkan_Info.DescriptorPool) - vkDestroyDescriptorPool(_ImVulkan_Info.Device, _ImVulkan_Info.DescriptorPool, VK_NULL_HANDLE); - } - - for (uint32_t i = 0; i < _ImVulkan_Info.ImageCount; i++) - { - ImGui_ImplVulkanH_Frame* fd = &_ImVulkan_Frames[i]; - - if (fd->Fence != VK_NULL_HANDLE) - { - vkDestroyFence(_ImVulkan_Info.Device, fd->Fence, VK_NULL_HANDLE); - fd->Fence = VK_NULL_HANDLE; - } - - if (fd->CommandBuffer != VK_NULL_HANDLE) - { - vkFreeCommandBuffers(_ImVulkan_Info.Device, fd->CommandPool, 1, &fd->CommandBuffer); - fd->CommandBuffer = VK_NULL_HANDLE; - } - - if (fd->CommandPool != VK_NULL_HANDLE) - { - vkDestroyCommandPool(_ImVulkan_Info.Device, fd->CommandPool, VK_NULL_HANDLE); - fd->CommandPool = VK_NULL_HANDLE; - } - - if (fd->BackbufferView != VK_NULL_HANDLE) - { - vkDestroyImageView(_ImVulkan_Info.Device, fd->BackbufferView, VK_NULL_HANDLE); - fd->BackbufferView = VK_NULL_HANDLE; - } - - if (fd->BackbufferView != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(_ImVulkan_Info.Device, fd->Framebuffer, VK_NULL_HANDLE); - fd->Framebuffer = VK_NULL_HANDLE; - } - - if (_ImVulkan_Semaphores[i] != VK_NULL_HANDLE) - { - vkDestroySemaphore(_ImVulkan_Info.Device, _ImVulkan_Semaphores[i], VK_NULL_HANDLE); - _ImVulkan_Semaphores[i] = VK_NULL_HANDLE; - } - - _ImVulkan_Info = {}; - } - - _vkCleanMutex.unlock(); -} - -static void CreateVulkanObjects(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain) +static void CreateVulkanObjects(VkDevice device, VkPhysicalDevice pd, VkInstance instance, HWND hwnd, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain) { LOG_FUNC(); @@ -140,19 +40,19 @@ static void CreateVulkanObjects(VkDevice device, const VkSwapchainCreateInfoKHR* if (ImGui::GetIO().BackendRendererUserData != nullptr) ImGui_ImplVulkan_Shutdown(); - DestroyVulkanObjects(false); + ImGuiOverlayVk::DestroyVulkanObjects(false); _vulkanObjectsCreated = false; } // Initialize ImGui - if (!ImGuiOverlayBase::IsInited() || ImGuiOverlayBase::Handle() != _hwnd) + if (!ImGuiOverlayBase::IsInited() || ImGuiOverlayBase::Handle() != hwnd) { if (ImGuiOverlayBase::IsInited()) ImGuiOverlayBase::Shutdown(); LOG_DEBUG("ImGuiOverlayBase::Init"); - ImGuiOverlayBase::Init(_hwnd); + ImGuiOverlayBase::Init(hwnd); } ImGuiIO& io = ImGui::GetIO(); @@ -191,13 +91,13 @@ static void CreateVulkanObjects(VkDevice device, const VkSwapchainCreateInfoKHR* { // get count uint32_t count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(_PD, &count, NULL); + vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, NULL); // get queues if (count > 0) { VkQueueFamilyProperties queues[8]; - vkGetPhysicalDeviceQueueFamilyProperties(_PD, &count, queues); + vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, queues); // find graphic queue @@ -402,8 +302,8 @@ static void CreateVulkanObjects(VkDevice device, const VkSwapchainCreateInfoKHR* // Initialize ImGui and upload fonts { - _ImVulkan_Info.Instance = _instance; - _ImVulkan_Info.PhysicalDevice = _PD; + _ImVulkan_Info.Instance = instance; + _ImVulkan_Info.PhysicalDevice = pd; _ImVulkan_Info.Device = device; _ImVulkan_Info.QueueFamily = queueFamily; _ImVulkan_Info.Queue = queue; @@ -470,147 +370,92 @@ static void CreateVulkanObjects(VkDevice device, const VkSwapchainCreateInfoKHR* LOG_FUNC_RESULT(_vulkanObjectsCreated); } -static void HookDevice(VkDevice InDevice) +void ImGuiOverlayVk::DestroyVulkanObjects(bool shutdown) { - if (o_CreateSwapchainKHR != nullptr || Config::Instance()->VulkanSkipHooks) + if (_ImVulkan_Info.Device == VK_NULL_HANDLE) return; - LOG_FUNC(); + if (!shutdown) + LOG_FUNC(); - o_QueuePresentKHR = (PFN_QueuePresentKHR)(vkGetDeviceProcAddr(InDevice, "vkQueuePresentKHR")); - o_CreateSwapchainKHR = (PFN_CreateSwapchainKHR)(vkGetDeviceProcAddr(InDevice, "vkCreateSwapchainKHR")); + _vkCleanMutex.lock(); - if (o_CreateSwapchainKHR) + auto result = vkDeviceWaitIdle(_ImVulkan_Info.Device); + if (result != VK_SUCCESS && !shutdown) + LOG_WARN("vkDeviceWaitIdle error: {0:X}", (UINT)result); + + if (shutdown) { - LOG_DEBUG("Hooking VkDevice"); + if (_vkRenderPass) + vkDestroyRenderPass(_ImVulkan_Info.Device, _vkRenderPass, VK_NULL_HANDLE); - // Hook - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DetourAttach(&(PVOID&)o_QueuePresentKHR, hkvkQueuePresentKHR); - DetourAttach(&(PVOID&)o_CreateSwapchainKHR, hkvkCreateSwapchainKHR); - - DetourTransactionCommit(); - } -} - -static VkResult hkvkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) -{ - LOG_FUNC(); - - auto result = o_vkCreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); - - auto procHwnd = Util::GetProcessWindow(); - LOG_DEBUG("procHwnd: {0:X}, swapchain hwnd: {1:X}", (UINT64)procHwnd, (UINT64)pCreateInfo->hwnd); - - if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks && procHwnd == pCreateInfo->hwnd) - { - DestroyVulkanObjects(false); - - _instance = instance; - LOG_DEBUG("_instance captured: {0:X}", (UINT64)_instance); - _hwnd = pCreateInfo->hwnd; - LOG_DEBUG("_hwnd captured: {0:X}", (UINT64)_hwnd); + if (_ImVulkan_Info.DescriptorPool) + vkDestroyDescriptorPool(_ImVulkan_Info.Device, _ImVulkan_Info.DescriptorPool, VK_NULL_HANDLE); } - LOG_FUNC_RESULT(result); - - return result; - -} - -static VkResult hkvkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) -{ - LOG_FUNC(); - - auto result = o_vkCreateInstance(pCreateInfo, pAllocator, pInstance); - - if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks) + for (uint32_t i = 0; i < _ImVulkan_Info.ImageCount; i++) { - DestroyVulkanObjects(false); + ImGui_ImplVulkanH_Frame* fd = &_ImVulkan_Frames[i]; - _instance = *pInstance; - LOG_DEBUG("_instance captured: {0:X}", (UINT64)_instance); + if (fd->Fence != VK_NULL_HANDLE) + { + vkDestroyFence(_ImVulkan_Info.Device, fd->Fence, VK_NULL_HANDLE); + fd->Fence = VK_NULL_HANDLE; + } + + if (fd->CommandBuffer != VK_NULL_HANDLE) + { + vkFreeCommandBuffers(_ImVulkan_Info.Device, fd->CommandPool, 1, &fd->CommandBuffer); + fd->CommandBuffer = VK_NULL_HANDLE; + } + + if (fd->CommandPool != VK_NULL_HANDLE) + { + vkDestroyCommandPool(_ImVulkan_Info.Device, fd->CommandPool, VK_NULL_HANDLE); + fd->CommandPool = VK_NULL_HANDLE; + } + + if (fd->BackbufferView != VK_NULL_HANDLE) + { + vkDestroyImageView(_ImVulkan_Info.Device, fd->BackbufferView, VK_NULL_HANDLE); + fd->BackbufferView = VK_NULL_HANDLE; + } + + if (fd->BackbufferView != VK_NULL_HANDLE) + { + vkDestroyFramebuffer(_ImVulkan_Info.Device, fd->Framebuffer, VK_NULL_HANDLE); + fd->Framebuffer = VK_NULL_HANDLE; + } + + if (_ImVulkan_Semaphores[i] != VK_NULL_HANDLE) + { + vkDestroySemaphore(_ImVulkan_Info.Device, _ImVulkan_Semaphores[i], VK_NULL_HANDLE); + _ImVulkan_Semaphores[i] = VK_NULL_HANDLE; + } + + _ImVulkan_Info = {}; } - LOG_FUNC_RESULT(result); - - return result; + _vkCleanMutex.unlock(); } -static VkResult hkvkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) -{ - LOG_FUNC(); - - auto result = o_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice); - - if (result == VK_SUCCESS && !Config::Instance()->VulkanSkipHooks) - { - DestroyVulkanObjects(false); - - _PD = physicalDevice; - LOG_DEBUG("_PD captured: {0:X}", (UINT64)_PD); - _device = *pDevice; - LOG_DEBUG("_device captured: {0:X}", (UINT64)_device); - HookDevice(_device); - } - - LOG_FUNC_RESULT(result); - - return result; -} - -static VkResult hkvkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo) +bool ImGuiOverlayVk::QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo) { LOG_FUNC(); if (!_vulkanObjectsCreated) { LOG_TRACE("!_vulkanObjectsCreated return o_QueuePresentKHR"); - - Config::Instance()->VulkanCreatingSC = true; - auto r0 = o_QueuePresentKHR(queue, pPresentInfo); - Config::Instance()->VulkanCreatingSC = false; - - if (r0 != VK_SUCCESS) - LOG_ERROR("r0 = o_QueuePresentKHR(queue, pPresentInfo): {0:X}", (UINT)r0); - - return r0; + return true; } if (!ImGuiOverlayBase::IsInited() || !ImGuiOverlayBase::IsVisible() || _ImVulkan_Info.Device == VK_NULL_HANDLE) { - Config::Instance()->VulkanCreatingSC = true; - auto r1 = o_QueuePresentKHR(queue, pPresentInfo); - Config::Instance()->VulkanCreatingSC = false; - - if (r1 != VK_SUCCESS) - LOG_ERROR("r1 = o_QueuePresentKHR(queue, pPresentInfo): {0:X}", (UINT)r1); - - return r1; + return true; } _vkPresentMutex.lock(); - if (ImGuiOverlayVk::vkUpscaleTrig && ImGuiOverlayVk::queryPool != VK_NULL_HANDLE) - { - // Retrieve timestamps - uint64_t timestamps[2]; - vkGetQueryPoolResults(_device, ImGuiOverlayVk::queryPool, 0, 2, sizeof(timestamps), timestamps, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); - - // Calculate elapsed time in milliseconds - double elapsedTimeMs = (timestamps[1] - timestamps[0]) * ImGuiOverlayVk::timeStampPeriod / 1e6; - - if (elapsedTimeMs > 0.0 && elapsedTimeMs < 5000.0) - { - Config::Instance()->upscaleTimes.push_back(elapsedTimeMs); - Config::Instance()->upscaleTimes.pop_front(); - } - - ImGuiOverlayVk::vkUpscaleTrig = false; - } - LOG_DEBUG("rendering menu, swapchain count: {0}", pPresentInfo->swapchainCount); bool errorWhenRenderingMenu = true; @@ -702,120 +547,37 @@ static VkResult hkvkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInf // if there are errors when rendering try to recreate swapchain _vkPresentMutex.unlock(); LOG_FUNC_RESULT(VK_ERROR_OUT_OF_DATE_KHR); - return VK_ERROR_OUT_OF_DATE_KHR; + return false; } - // original call - Config::Instance()->VulkanCreatingSC = true; - auto result = o_QueuePresentKHR(queue, pPresentInfo); - Config::Instance()->VulkanCreatingSC = false; - LOG_FUNC_RESULT(result); _vkPresentMutex.unlock(); - return result; + + return true; } -static VkResult hkvkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) +void ImGuiOverlayVk::CreateSwapchain(VkDevice device, VkPhysicalDevice pd, VkInstance instance, HWND hwnd, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { LOG_FUNC(); - Config::Instance()->VulkanCreatingSC = true; - auto result = o_CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain); - Config::Instance()->VulkanCreatingSC = false; - - if (result == VK_SUCCESS && device != VK_NULL_HANDLE && pCreateInfo != nullptr && *pSwapchain != VK_NULL_HANDLE && !Config::Instance()->VulkanSkipHooks) + if (ImGuiOverlayBase::Handle() != hwnd) { - Config::Instance()->ScreenWidth = pCreateInfo->imageExtent.width; - Config::Instance()->ScreenHeight = pCreateInfo->imageExtent.height; + LOG_DEBUG("ImGuiOverlayBase::Handle() != _hwnd"); - LOG_DEBUG("if (result == VK_SUCCESS && device != VK_NULL_HANDLE && pCreateInfo != nullptr && pSwapchain != VK_NULL_HANDLE)"); - - _device = device; - LOG_DEBUG("_device captured: {0:X}", (UINT64)_device); - - if (ImGuiOverlayBase::Handle() != _hwnd) + if (ImGuiOverlayBase::IsInited()) { - LOG_DEBUG("ImGuiOverlayBase::Handle() != _hwnd"); - - if (ImGuiOverlayBase::IsInited()) - { - LOG_DEBUG("ImGuiOverlayBase::Shutdown();"); - ImGuiOverlayBase::Shutdown(); - } - - LOG_DEBUG("ImGuiOverlayBase::Init({0:X})", (UINT64)_hwnd); - ImGuiOverlayBase::Init(_hwnd); + LOG_DEBUG("ImGuiOverlayBase::Shutdown();"); + ImGuiOverlayBase::Shutdown(); } - CreateVulkanObjects(_device, pCreateInfo, pSwapchain); - - if (_ImVulkan_Info.Device != VK_NULL_HANDLE) - { - _isInited = true; - ImGuiOverlayBase::VulkanReady(); - } + LOG_DEBUG("ImGuiOverlayBase::Init({0:X})", (UINT64)hwnd); + ImGuiOverlayBase::Init(hwnd); } - LOG_FUNC_RESULT(result); - return result; -} + CreateVulkanObjects(device, pd, instance, hwnd, pCreateInfo, pSwapchain); -void ImGuiOverlayVk::HookVk() -{ - if (o_vkCreateDevice != nullptr) - return; - - o_vkCreateDevice = (PFN_vkCreateDevice)DetourFindFunction("vulkan-1.dll", "vkCreateDevice"); - o_vkCreateInstance = (PFN_vkCreateInstance)DetourFindFunction("vulkan-1.dll", "vkCreateInstance"); - o_vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)DetourFindFunction("vulkan-1.dll", "vkCreateWin32SurfaceKHR"); - - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (o_vkCreateDevice != nullptr) - DetourAttach(&(PVOID&)o_vkCreateDevice, hkvkCreateDevice); - - if (o_vkCreateInstance != nullptr) - DetourAttach(&(PVOID&)o_vkCreateInstance, hkvkCreateInstance); - - if (o_vkCreateWin32SurfaceKHR != nullptr) - DetourAttach(&(PVOID&)o_vkCreateWin32SurfaceKHR, hkvkCreateWin32SurfaceKHR); - - DetourTransactionCommit(); -} - -void ImGuiOverlayVk::UnHookVk() -{ - if (_isInited) - ImGui_ImplVulkan_Shutdown(); - - ImGuiOverlayBase::Shutdown(); - - if (_vulkanObjectsCreated) - DestroyVulkanObjects(true); - - if (_isInited) + if (_ImVulkan_Info.Device != VK_NULL_HANDLE) { - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - if (o_QueuePresentKHR != nullptr) - DetourDetach(&(PVOID&)o_QueuePresentKHR, hkvkQueuePresentKHR); - - if (o_CreateSwapchainKHR != nullptr) - DetourDetach(&(PVOID&)o_CreateSwapchainKHR, hkvkCreateSwapchainKHR); - - if (o_vkCreateDevice != nullptr) - DetourDetach(&(PVOID&)o_vkCreateDevice, hkvkCreateDevice); - - if (o_vkCreateInstance != nullptr) - DetourDetach(&(PVOID&)o_vkCreateInstance, hkvkCreateInstance); - - if (o_vkCreateWin32SurfaceKHR != nullptr) - DetourDetach(&(PVOID&)o_vkCreateWin32SurfaceKHR, hkvkCreateWin32SurfaceKHR); - - DetourTransactionCommit(); + _isInited = true; + ImGuiOverlayBase::VulkanReady(); } - - _isInited = false; - _vulkanObjectsCreated = false; } diff --git a/OptiScaler/imgui/imgui_overlay_vk.h b/OptiScaler/imgui/imgui_overlay_vk.h index 2a136845..36a48498 100644 --- a/OptiScaler/imgui/imgui_overlay_vk.h +++ b/OptiScaler/imgui/imgui_overlay_vk.h @@ -5,10 +5,7 @@ namespace ImGuiOverlayVk { - inline VkQueryPool queryPool = VK_NULL_HANDLE; - inline double timeStampPeriod = 1.0; - inline bool vkUpscaleTrig = false; - - void HookVk(); - void UnHookVk(); + void CreateSwapchain(VkDevice device, VkPhysicalDevice pd, VkInstance instance, HWND hwnd, const VkSwapchainCreateInfoKHR* pCreateInfo, VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain); + bool QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo); + void DestroyVulkanObjects(bool shutdown); }