From 8828fa65f8e4e867fab8d105e06f2fdd76db07b2 Mon Sep 17 00:00:00 2001 From: cdozdil Date: Wed, 16 Oct 2024 09:38:37 +0300 Subject: [PATCH] pre22 --- OptiScaler/Config.cpp | 6 +- OptiScaler/Config.h | 5 +- OptiScaler/NVNGX_DLSS_Dx12.cpp | 21 +- OptiScaler/OptiScaler.vcxproj | 3 + OptiScaler/OptiScaler.vcxproj.filters | 12 +- OptiScaler/format_transfer/FT_Common.h | 118 +++++++ OptiScaler/format_transfer/FT_Dx12.cpp | 422 +++++++++++++++++++++++++ OptiScaler/format_transfer/FT_Dx12.h | 45 +++ OptiScaler/imgui/imgui_common.cpp | 12 +- OptiScaler/imgui/imgui_overlay_dx.cpp | 91 ++++-- OptiScaler/imgui/imgui_overlay_dx.h | 4 +- OptiScaler/resource.h | 2 +- 12 files changed, 676 insertions(+), 65 deletions(-) create mode 100644 OptiScaler/format_transfer/FT_Common.h create mode 100644 OptiScaler/format_transfer/FT_Dx12.cpp create mode 100644 OptiScaler/format_transfer/FT_Dx12.h diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp index 4df785e9..5b5fdf1c 100644 --- a/OptiScaler/Config.cpp +++ b/OptiScaler/Config.cpp @@ -55,9 +55,8 @@ bool Config::Reload(std::filesystem::path iniPath) FGDebugView = readBool("FrameGen", "DebugView"); FGAsync = readBool("FrameGen", "AllowAsync"); FGHUDFix = readBool("FrameGen", "HUDFix"); + FGHUDFixExtended = readBool("FrameGen", "HUDFixExtended"); FGHUDLimit = readInt("FrameGen", "HUDLimit"); - FGSkipInstanced = readBool("FrameGen", "HUDSkipInstanced"); - FGSkipIndexedInstanced = readBool("FrameGen", "HUDSkipIndexed"); } // FSR @@ -479,9 +478,8 @@ bool Config::SaveIni() ini.SetValue("FrameGen", "DebugView", GetBoolValue(Instance()->FGDebugView).c_str()); ini.SetValue("FrameGen", "AllowAsync", GetBoolValue(Instance()->FGAsync).c_str()); ini.SetValue("FrameGen", "HUDFix", GetBoolValue(Instance()->FGHUDFix).c_str()); + ini.SetValue("FrameGen", "HUDFixExtended", GetBoolValue(Instance()->FGHUDFixExtended).c_str()); ini.SetValue("FrameGen", "HUDLimit", GetIntValue(Instance()->FGHUDLimit).c_str()); - ini.SetValue("FrameGen", "HUDSkipInstanced", GetBoolValue(Instance()->FGSkipInstanced).c_str()); - ini.SetValue("FrameGen", "HUDSkipIndexed", GetBoolValue(Instance()->FGSkipIndexedInstanced).c_str()); } // Output Scaling diff --git a/OptiScaler/Config.h b/OptiScaler/Config.h index 388ce1ea..14096f3a 100644 --- a/OptiScaler/Config.h +++ b/OptiScaler/Config.h @@ -164,12 +164,11 @@ public: std::optional FGDebugView; std::optional FGAsync; std::optional FGHUDFix; - std::optional FGSkipInstanced; - std::optional FGSkipIndexedInstanced; + std::optional FGHUDFixExtended; std::optional FGHUDLimit; bool FGOnlyGenerated = false; bool FGChanged = false; - bool SCChanged = false; + bool SCChanged = true; bool SkipHeapCapture = false; diff --git a/OptiScaler/NVNGX_DLSS_Dx12.cpp b/OptiScaler/NVNGX_DLSS_Dx12.cpp index a337c42a..99dcad65 100644 --- a/OptiScaler/NVNGX_DLSS_Dx12.cpp +++ b/OptiScaler/NVNGX_DLSS_Dx12.cpp @@ -72,6 +72,12 @@ static void ReleaseFGObjects() ImGuiOverlayDx::fgCopyCommandQueue->Release(); ImGuiOverlayDx::fgCopyCommandQueue = nullptr; } + + if (ImGuiOverlayDx::fgFormatTransfer != nullptr) + { + delete ImGuiOverlayDx::fgFormatTransfer; + ImGuiOverlayDx::fgFormatTransfer = nullptr; + } } static void CreateFGObjects() @@ -112,7 +118,7 @@ static void CreateFGObjects() // Create a command queue for copy operations D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}; copyQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + copyQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH; copyQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; copyQueueDesc.NodeMask = 0; @@ -123,6 +129,9 @@ static void CreateFGObjects() break; } ImGuiOverlayDx::fgCopyCommandQueue->SetName(L"fgCopyCommandQueue"); + + ImGuiOverlayDx::fgFormatTransfer = new FT_Dx12("FormatTransfer", D3D12Device, ImGuiOverlayDx::swapchainFormat); + } while (false); } @@ -1575,8 +1584,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom }; m_FrameGenerationConfig.frameGenerationCallbackUserContext = &ImGuiOverlayDx::fgContext; - - m_FrameGenerationConfig.onlyPresentGenerated = Config::Instance()->FGOnlyGenerated; // check here m_FrameGenerationConfig.frameID = deviceContext->FrameCount(); m_FrameGenerationConfig.swapChain = ImGuiOverlayDx::currentSwapchain; @@ -1679,8 +1686,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom ImGuiOverlayDx::fgUpscaledImage[frameIndex] = output; LOG_DEBUG("Set fgUpscaledImage[{}]", frameIndex); - ImGuiOverlayDx::upscaleRan = true; - auto allocator = ImGuiOverlayDx::fgCopyCommandAllocators[frameIndex]; auto result = allocator->Reset(); result = ImGuiOverlayDx::fgCopyCommandList->Reset(allocator, nullptr); @@ -1694,18 +1699,14 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom 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); - } 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); - } InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_X, &ImGuiOverlayDx::mvScaleX); InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_Y, &ImGuiOverlayDx::mvScaleY); @@ -1721,6 +1722,8 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom fgLastFrameTime = now; ImGuiOverlayDx::fgFrameTime = msDelta; + ImGuiOverlayDx::upscaleRan = true; + LOG_DEBUG(" FG HUDFix done, frame: {0}", deviceContext->FrameCount()); } diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index f215f4e9..3e857614 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -206,6 +206,8 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ + + @@ -292,6 +294,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\ + diff --git a/OptiScaler/OptiScaler.vcxproj.filters b/OptiScaler/OptiScaler.vcxproj.filters index afa52c28..3a0e95a1 100644 --- a/OptiScaler/OptiScaler.vcxproj.filters +++ b/OptiScaler/OptiScaler.vcxproj.filters @@ -242,15 +242,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - Header Files @@ -446,6 +437,9 @@ Source Files + + Source Files + Source Files diff --git a/OptiScaler/format_transfer/FT_Common.h b/OptiScaler/format_transfer/FT_Common.h new file mode 100644 index 00000000..22bb0664 --- /dev/null +++ b/OptiScaler/format_transfer/FT_Common.h @@ -0,0 +1,118 @@ +#pragma once +#include "../pch.h" +#include +#include + +inline static std::string ftR10G10B10A2Code = R"( +Texture2D SourceTexture : register(t0); +RWTexture2D DestinationTexture : register(u0); // R10G10B10A2_UNORM destination texture + +// Shader to perform the conversion +[numthreads(512, 1, 1)] +void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + // Read from the source texture + float4 srcColor = SourceTexture.Load(int3(dispatchThreadID.xy, 0)); + + // Clamp color channels to [0, 1] range, as R10G10B10A2_UNORM is normalized + srcColor = saturate(srcColor); // Ensures all values are between 0 and 1 + + // Convert each channel to its corresponding bit range + uint R = (uint)(srcColor.r * 1023.0f); // 10 bits for Red + uint G = (uint)(srcColor.g * 1023.0f); // 10 bits for Green + uint B = (uint)(srcColor.b * 1023.0f); // 10 bits for Blue + uint A = (uint)(srcColor.a * 3.0f); // 2 bits for Alpha + + // Pack the values into a single 32-bit unsigned int + uint packedColor = R | G << 10 | B << 20 | A << 30; + + // Write the packed color to the destination texture + DestinationTexture[dispatchThreadID.xy] = packedColor; +} +)"; + +inline static std::string ftR8G8B8A8Code = R"( +Texture2D SourceTexture : register(t0); +RWTexture2D DestinationTexture : register(u0); // R8G8B8A8_UNORM destination texture + +// Shader to perform the conversion +[numthreads(512, 1, 1)] +void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + // Read from the source texture + float4 srcColor = SourceTexture.Load(int3(dispatchThreadID.xy, 0)); + + // Clamp color channels to [0, 1] range, as R8G8B8A8_UNORM is normalized + srcColor = saturate(srcColor); // Ensures all values are between 0 and 1 + + // Convert each channel to its corresponding bit range + uint R = (uint)(srcColor.r * 255.0f); // 8 bits for Red + uint G = (uint)(srcColor.g * 255.0f); // 8 bits for Green + uint B = (uint)(srcColor.b * 255.0f); // 8 bits for Blue + uint A = (uint)(srcColor.a * 255.0f); // 8 bits for Alpha + + // Pack the values into a single 32-bit unsigned int + uint packedColor = R | G << 8 | B << 16 | A << 24; + + // Write the packed color to the destination texture + DestinationTexture[dispatchThreadID.xy] = packedColor; +} +)"; + +inline static std::string ftB8G8R8A8Code = R"( +Texture2D SourceTexture : register(t0); +RWTexture2D DestinationTexture : register(u0); // R8G8B8A8_UNORM destination texture + +// Shader to perform the conversion +[numthreads(512, 1, 1)] +void CSMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + // Read from the source texture + float4 srcColor = SourceTexture.Load(int3(dispatchThreadID.xy, 0)); + + // Clamp color channels to [0, 1] range, as R8G8B8A8_UNORM is normalized + srcColor = saturate(srcColor); // Ensures all values are between 0 and 1 + + // Convert each channel to its corresponding bit range + uint R = (uint)(srcColor.r * 255.0f); // 8 bits for Red + uint G = (uint)(srcColor.g * 255.0f); // 8 bits for Green + uint B = (uint)(srcColor.b * 255.0f); // 8 bits for Blue + uint A = (uint)(srcColor.a * 255.0f); // 8 bits for Alpha + + // Pack the values into a single 32-bit unsigned int + uint packedColor = B | R << 8 | G << 16 | A << 24; + + // Write the packed color to the destination texture + DestinationTexture[dispatchThreadID.xy] = packedColor; +} +)"; + + +inline static ID3DBlob* FT_CompileShader(const char* shaderCode, const char* entryPoint, const char* target) +{ + ID3DBlob* shaderBlob = nullptr; + ID3DBlob* errorBlob = nullptr; + + HRESULT hr = D3DCompile(shaderCode, strlen(shaderCode), nullptr, nullptr, nullptr, entryPoint, target, D3DCOMPILE_OPTIMIZATION_LEVEL3, 0, &shaderBlob, &errorBlob); + + if (FAILED(hr)) + { + LOG_ERROR("error while compiling shader"); + + if (errorBlob) + { + LOG_ERROR("error while compiling shader : {0}", (char*)errorBlob->GetBufferPointer()); + errorBlob->Release(); + } + + if (shaderBlob) + shaderBlob->Release(); + + return nullptr; + } + + if (errorBlob) + errorBlob->Release(); + + return shaderBlob; +} \ No newline at end of file diff --git a/OptiScaler/format_transfer/FT_Dx12.cpp b/OptiScaler/format_transfer/FT_Dx12.cpp new file mode 100644 index 00000000..cea6f1a0 --- /dev/null +++ b/OptiScaler/format_transfer/FT_Dx12.cpp @@ -0,0 +1,422 @@ +#include "FT_Dx12.h" + +#include "../Config.h" + +inline static DXGI_FORMAT TranslateTypelessFormats(DXGI_FORMAT format) +{ + switch (format) { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case DXGI_FORMAT_R32G32B32_TYPELESS: + return DXGI_FORMAT_R32G32B32_FLOAT; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + return DXGI_FORMAT_R10G10B10A2_UINT; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case DXGI_FORMAT_R16G16_TYPELESS: + return DXGI_FORMAT_R16G16_FLOAT; + case DXGI_FORMAT_R32G32_TYPELESS: + return DXGI_FORMAT_R32G32_FLOAT; + case DXGI_FORMAT_R32G8X24_TYPELESS: + return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + case DXGI_FORMAT_R32_TYPELESS: + return DXGI_FORMAT_R32_FLOAT; + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + return format; + } +} + +static bool CreateComputeShader(ID3D12Device* device, ID3D12RootSignature* rootSignature, ID3D12PipelineState** pipelineState, ID3DBlob* shaderBlob) +{ + D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.pRootSignature = rootSignature; + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + psoDesc.CS = CD3DX12_SHADER_BYTECODE(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize()); + + HRESULT hr = device->CreateComputePipelineState(&psoDesc, __uuidof(ID3D12PipelineState*), (void**)pipelineState); + + if (FAILED(hr)) + { + LOG_ERROR("CreateComputePipelineState error {0:x}", hr); + return false; + } + + return true; +} + +bool FT_Dx12::CreateBufferResource(ID3D12Device* InDevice, ID3D12Resource* InSource, D3D12_RESOURCE_STATES InState) +{ + if (InDevice == nullptr || InSource == nullptr) + return false; + + LOG_FUNC(); + + D3D12_RESOURCE_DESC texDesc = InSource->GetDesc(); + + if (_buffer != nullptr) + { + auto bufDesc = _buffer->GetDesc(); + + if (bufDesc.Width != texDesc.Width || bufDesc.Height != texDesc.Height || bufDesc.Format != format) + { + _buffer->Release(); + _buffer = nullptr; + } + else + return true; + } + + LOG_DEBUG("[{0}] Start!", _name); + + LOG_INFO("Texture Format: {}", (UINT)texDesc.Format); + + D3D12_HEAP_PROPERTIES heapProperties; + D3D12_HEAP_FLAGS heapFlags; + HRESULT hr = InSource->GetHeapProperties(&heapProperties, &heapFlags); + + if (hr != S_OK) + { + LOG_ERROR("[{0}] GetHeapProperties result: {1:x}", _name.c_str(), hr); + return false; + } + + texDesc.Format = format; + texDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS; + + hr = InDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texDesc, InState, nullptr, IID_PPV_ARGS(&_buffer)); + + if (hr != S_OK) + { + LOG_ERROR("[{0}] CreateCommittedResource result: {1:x}", _name, hr); + return false; + } + + + _buffer->SetName(L"HUDless_Buffer"); + _bufferState = InState; + + return true; +} + + +void FT_Dx12::SetBufferState(ID3D12GraphicsCommandList* InCommandList, D3D12_RESOURCE_STATES InState) +{ + if (_bufferState == InState) + return; + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = _buffer; + barrier.Transition.StateBefore = _bufferState; + barrier.Transition.StateAfter = InState; + barrier.Transition.Subresource = 0; + InCommandList->ResourceBarrier(1, &barrier); + _bufferState = InState; +} + +bool FT_Dx12::Dispatch(ID3D12Device* InDevice, ID3D12GraphicsCommandList* InCmdList, ID3D12Resource* InResource, ID3D12Resource* OutResource) +{ + if (!_init || InDevice == nullptr || InCmdList == nullptr || InResource == nullptr || OutResource == nullptr) + return false; + + LOG_DEBUG("[{0}] Start!", _name); + + _counter++; + _counter = _counter % 2; + + if (_cpuSrvHandle[_counter].ptr == NULL) + _cpuSrvHandle[_counter] = _srvHeap[_counter]->GetCPUDescriptorHandleForHeapStart(); + + if (_cpuUavHandle[_counter].ptr == NULL) + { + _cpuUavHandle[_counter] = _cpuSrvHandle[_counter]; + _cpuUavHandle[_counter].ptr += InDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + if (_gpuSrvHandle[_counter].ptr == NULL) + _gpuSrvHandle[_counter] = _srvHeap[_counter]->GetGPUDescriptorHandleForHeapStart(); + + if (_gpuUavHandle[_counter].ptr == NULL) + { + _gpuUavHandle[_counter] = _gpuSrvHandle[_counter]; + _gpuUavHandle[_counter].ptr += InDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + auto inDesc = InResource->GetDesc(); + auto outDesc = OutResource->GetDesc(); + + // Create SRV for Input Texture + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Format = TranslateTypelessFormats(inDesc.Format); + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; + InDevice->CreateShaderResourceView(InResource, &srvDesc, _cpuSrvHandle[_counter]); + + // Create UAV for Output Texture + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + uavDesc.Format = DXGI_FORMAT_R32_UINT; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + uavDesc.Texture2D.MipSlice = 0; + InDevice->CreateUnorderedAccessView(OutResource, nullptr, &uavDesc, _cpuUavHandle[_counter]); + + ID3D12DescriptorHeap* heaps[] = { _srvHeap[_counter] }; + InCmdList->SetDescriptorHeaps(_countof(heaps), heaps); + + InCmdList->SetComputeRootSignature(_rootSignature); + InCmdList->SetPipelineState(_pipelineState); + + InCmdList->SetComputeRootDescriptorTable(0, _gpuSrvHandle[_counter]); + InCmdList->SetComputeRootDescriptorTable(1, _gpuUavHandle[_counter]); + + UINT dispatchWidth = 0; + UINT dispatchHeight = 0; + + dispatchWidth = static_cast((Config::Instance()->CurrentFeature->DisplayWidth() + InNumThreadsX - 1) / InNumThreadsX); + dispatchHeight = (Config::Instance()->CurrentFeature->DisplayHeight() + InNumThreadsY - 1) / InNumThreadsY; + + InCmdList->Dispatch(dispatchWidth, dispatchHeight, 1); + + return true; +} + +FT_Dx12::FT_Dx12(std::string InName, ID3D12Device* InDevice, DXGI_FORMAT InFormat) : _name(InName), _device(InDevice), format(InFormat) +{ + if (InDevice == nullptr) + { + LOG_ERROR("InDevice is nullptr!"); + return; + } + + LOG_DEBUG("{0} start!", _name); + + // Describe and create the root signature + // --------------------------------------------------- + D3D12_DESCRIPTOR_RANGE descriptorRange[2]; + + // SRV Range (Input Texture) + descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange[0].NumDescriptors = 1; + descriptorRange[0].BaseShaderRegister = 0; // Assuming t0 register in HLSL for SRV + descriptorRange[0].RegisterSpace = 0; + descriptorRange[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + + // UAV Range (Output Texture) + descriptorRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + descriptorRange[1].NumDescriptors = 1; + descriptorRange[1].BaseShaderRegister = 0; // Assuming u0 register in HLSL for UAV + descriptorRange[1].RegisterSpace = 0; + descriptorRange[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + + // Define the root parameter (descriptor table) + // --------------------------------------------------- + D3D12_ROOT_PARAMETER rootParameters[2]; + + // Root Parameter for SRV + rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameters[0].DescriptorTable.NumDescriptorRanges = 1; // One range (SRV) + rootParameters[0].DescriptorTable.pDescriptorRanges = &descriptorRange[0]; // Point to the SRV range + rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + // Root Parameter for UAV + rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameters[1].DescriptorTable.NumDescriptorRanges = 1; // One range (UAV) + rootParameters[1].DescriptorTable.pDescriptorRanges = &descriptorRange[1]; // Point to the UAV range + rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + // A root signature is an array of root parameters + // --------------------------------------------------- + D3D12_ROOT_SIGNATURE_DESC rootSigDesc; + rootSigDesc.NumParameters = 2; // Two root parameters + rootSigDesc.pParameters = rootParameters; + rootSigDesc.NumStaticSamplers = 0; + rootSigDesc.pStaticSamplers = nullptr; + rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; + + ID3DBlob* errorBlob; + ID3DBlob* signatureBlob; + + do + { + auto hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signatureBlob, &errorBlob); + + if (FAILED(hr)) + { + LOG_ERROR("[{0}] D3D12SerializeRootSignature error {1:x}", _name, hr); + break; + } + + hr = InDevice->CreateRootSignature(0, signatureBlob->GetBufferPointer(), signatureBlob->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)); + + if (FAILED(hr)) + { + LOG_ERROR("[{0}] CreateRootSignature error {1:x}", _name, hr); + break; + } + + } while (false); + + if (errorBlob != nullptr) + { + errorBlob->Release(); + errorBlob = nullptr; + } + + if (signatureBlob != nullptr) + { + signatureBlob->Release(); + signatureBlob = nullptr; + } + + if (_rootSignature == nullptr) + { + LOG_ERROR("[{0}] _rootSignature is null!", _name); + return; + } + + // Compile shader blobs + ID3DBlob* _recEncodeShader = nullptr; + + if (InFormat == DXGI_FORMAT_R10G10B10A2_UNORM) + { + _recEncodeShader = FT_CompileShader(ftR10G10B10A2Code.c_str(), "CSMain", "cs_5_0"); + } + else if (InFormat == DXGI_FORMAT_R8G8B8A8_UNORM) + { + _recEncodeShader = FT_CompileShader(ftR8G8B8A8Code.c_str(), "CSMain", "cs_5_0"); + } + else if (InFormat == DXGI_FORMAT_B8G8R8A8_UNORM) + { + _recEncodeShader = FT_CompileShader(ftB8G8R8A8Code.c_str(), "CSMain", "cs_5_0"); + } + else + { + LOG_ERROR("[{0}] texture format is not found!", _name); + return; + } + + if (_recEncodeShader == nullptr) + { + LOG_ERROR("[{0}] CompileShader error!", _name); + return; + } + + // create pso objects + if (!CreateComputeShader(InDevice, _rootSignature, &_pipelineState, _recEncodeShader)) + { + LOG_ERROR("[{0}] CreateComputeShader error!", _name); + return; + } + + if (_recEncodeShader != nullptr) + { + _recEncodeShader->Release(); + _recEncodeShader = nullptr; + } + + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; + heapDesc.NumDescriptors = 2; // SRV + UAV + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + + auto hr = InDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap[0])); + + if (FAILED(hr)) + { + LOG_ERROR("[{0}] CreateDescriptorHeap[0] error {1:x}", _name, hr); + return; + } + + hr = InDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap[1])); + + if (FAILED(hr)) + { + LOG_ERROR("[{0}] CreateDescriptorHeap[1] error {1:x}", _name, hr); + return; + } + + hr = InDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap[2])); + + if (FAILED(hr)) + { + LOG_ERROR("[{0}] CreateDescriptorHeap[2] error {1:x}", _name, hr); + return; + } + + _init = _srvHeap[2] != nullptr; +} + +FT_Dx12::~FT_Dx12() +{ + if (!_init) + return; + + ID3D12Fence* d3d12Fence = nullptr; + + do + { + if (_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d12Fence)) != S_OK) + break; + + d3d12Fence->Signal(999); + + HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); + + if (fenceEvent != NULL && d3d12Fence->SetEventOnCompletion(999, fenceEvent) == S_OK) + { + WaitForSingleObject(fenceEvent, INFINITE); + CloseHandle(fenceEvent); + } + + } while (false); + + if (d3d12Fence != nullptr) + { + d3d12Fence->Release(); + d3d12Fence = nullptr; + } + + if (_pipelineState != nullptr) + { + _pipelineState->Release(); + _pipelineState = nullptr; + } + + if (_rootSignature != nullptr) + { + _rootSignature->Release(); + _rootSignature = nullptr; + } + + if (_srvHeap[0] != nullptr) + { + _srvHeap[0]->Release(); + _srvHeap[0] = nullptr; + } + + if (_srvHeap[1] != nullptr) + { + _srvHeap[1]->Release(); + _srvHeap[1] = nullptr; + } + + if (_srvHeap[2] != nullptr) + { + _srvHeap[2]->Release(); + _srvHeap[2] = nullptr; + } + + if (_buffer != nullptr) + { + _buffer->Release(); + _buffer = nullptr; + } +} diff --git a/OptiScaler/format_transfer/FT_Dx12.h b/OptiScaler/format_transfer/FT_Dx12.h new file mode 100644 index 00000000..8d7bbe47 --- /dev/null +++ b/OptiScaler/format_transfer/FT_Dx12.h @@ -0,0 +1,45 @@ +#pragma once + +#include "../pch.h" + +#include "FT_Common.h" + +#include +#include "../d3dx/d3dx12.h" + +class FT_Dx12 +{ +private: + std::string _name = ""; + bool _init = false; + ID3D12RootSignature* _rootSignature = nullptr; + ID3D12PipelineState* _pipelineState = nullptr; + ID3D12DescriptorHeap* _srvHeap[3] = { nullptr, nullptr, nullptr }; + D3D12_CPU_DESCRIPTOR_HANDLE _cpuSrvHandle[2]{ { NULL }, { NULL } }; + D3D12_CPU_DESCRIPTOR_HANDLE _cpuUavHandle[2]{ { NULL }, { NULL } }; + D3D12_GPU_DESCRIPTOR_HANDLE _gpuSrvHandle[2]{ { NULL }, { NULL } }; + D3D12_GPU_DESCRIPTOR_HANDLE _gpuUavHandle[2]{ { NULL }, { NULL } }; + int _counter = 0; + + uint32_t InNumThreadsX = 512; + uint32_t InNumThreadsY = 1; + + ID3D12Device* _device = nullptr; + ID3D12Resource* _buffer = nullptr; + D3D12_RESOURCE_STATES _bufferState = D3D12_RESOURCE_STATE_COMMON; + DXGI_FORMAT format; + +public: + bool CreateBufferResource(ID3D12Device* InDevice, ID3D12Resource* InSource, D3D12_RESOURCE_STATES InState); + void SetBufferState(ID3D12GraphicsCommandList* InCommandList, D3D12_RESOURCE_STATES InState); + bool Dispatch(ID3D12Device* InDevice, ID3D12GraphicsCommandList* InCmdList, ID3D12Resource* InResource, ID3D12Resource* OutResource); + + ID3D12Resource* Buffer() { return _buffer; } + bool IsInit() const { return _init; } + bool CanRender() const { return _init && _buffer != nullptr; } + DXGI_FORMAT Format() const { return format; } + + FT_Dx12(std::string InName, ID3D12Device* InDevice, DXGI_FORMAT InFormat); + + ~FT_Dx12(); +}; \ No newline at end of file diff --git a/OptiScaler/imgui/imgui_common.cpp b/OptiScaler/imgui/imgui_common.cpp index 956430a1..c7f41a44 100644 --- a/OptiScaler/imgui/imgui_common.cpp +++ b/OptiScaler/imgui/imgui_common.cpp @@ -925,15 +925,15 @@ void ImGuiCommon::RenderMenu() Config::Instance()->FGHUDLimit = hudFixLimit; } - ImGui::PopItemWidth(); ShowHelpMarker("Delay HUDless capture, high values might cause crash!"); - //ImGui::SameLine(0.0f, 16.0f); + ImGui::SameLine(0.0f, 16.0f); + auto hudExtended = Config::Instance()->FGHUDFixExtended.value_or(false); + if (ImGui::Checkbox("Extended", &hudExtended)) + Config::Instance()->FGHUDFixExtended = hudExtended; + ShowHelpMarker("Extended HUDless checks, might cause crash and slowdowns!"); - //auto hudExtended = Config::Instance()->FGHUDPrevious.value_or(false); - //if (ImGui::Checkbox("Extended", &hudExtended)) - // Config::Instance()->FGHUDPrevious = hudExtended; - //ShowHelpMarker("Extended HUDless checks, might cause crash and slowdowns!"); + ImGui::PopItemWidth(); ImGui::EndDisabled(); diff --git a/OptiScaler/imgui/imgui_overlay_dx.cpp b/OptiScaler/imgui/imgui_overlay_dx.cpp index 7b6170e4..63522104 100644 --- a/OptiScaler/imgui/imgui_overlay_dx.cpp +++ b/OptiScaler/imgui/imgui_overlay_dx.cpp @@ -189,6 +189,7 @@ 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; @@ -477,7 +478,7 @@ static void FillResourceInfo(ID3D12Resource* resource, ResourceInfo* info) info->format = desc.Format; } -static void GetHudless(ID3D12GraphicsCommandList* This) //, D3D12_RESOURCE_STATES State) +static void GetHudless(ID3D12GraphicsCommandList* This, bool SkipCopy) //, D3D12_RESOURCE_STATES State) { auto fIndex = fgFrameIndex; if (This != g_pd3dCommandList && fgCopySource[fIndex] != nullptr && Config::Instance()->CurrentFeature != nullptr && @@ -504,11 +505,14 @@ static void GetHudless(ID3D12GraphicsCommandList* This) //, D3D12_RESOURCE_STATE This->ResourceBarrier(1, &barrier); #endif - // Take hudless copy - if (CreateBufferResource(g_pd3dDeviceParam, fgCopySource[fIndex], D3D12_RESOURCE_STATE_COPY_DEST, &fgHudless[fIndex])) - This->CopyResource(fgHudless[fIndex], fgCopySource[fIndex]); - else - return; + if (!SkipCopy) + { + // Take hudless copy + if (CreateBufferResource(g_pd3dDeviceParam, fgCopySource[fIndex], D3D12_RESOURCE_STATE_COPY_DEST, &fgHudless[fIndex])) + This->CopyResource(fgHudless[fIndex], fgCopySource[fIndex]); + else + return; + } #ifdef USE_RESOURCE_BARRIRER // Not sure about source state, skipping for now @@ -561,6 +565,7 @@ static void GetHudless(ID3D12GraphicsCommandList* This) //, D3D12_RESOURCE_STATE result = ImGuiOverlayDx::fgCopyCommandList->Reset(allocator, nullptr); LOG_WARN("Callback without hudless!"); + params->reset = true; } if (Config::Instance()->CurrentFeature != nullptr) @@ -702,13 +707,13 @@ static bool CheckCapture() LOG_DEBUG_ONLY("lockcounterMutex[{}])", fIndex); 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; } - 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; } @@ -716,9 +721,36 @@ static void CaptureHudless(ID3D12GraphicsCommandList* cmdList, ID3D12Resource* r { auto fIndex = fgFrameIndex; ImGuiOverlayDx::upscaleRan = false; - fgCopySource[fIndex] = resource; - GetHudless(cmdList); fgUpscaledFound = false; + fgCopySource[fIndex] = resource; + + auto resInfo = resource->GetDesc(); + if (resInfo.Format != ImGuiOverlayDx::swapchainFormat && Config::Instance()->FGHUDFixExtended.value_or(false) && ImGuiOverlayDx::fgFormatTransfer != nullptr && + (resInfo.Format == DXGI_FORMAT_R16G16B16A16_FLOAT || resInfo.Format == DXGI_FORMAT_R11G11B10_FLOAT || resInfo.Format == DXGI_FORMAT_R32G32B32A32_FLOAT || resInfo.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, D3D12_RESOURCE_STATE_UNORDERED_ACCESS) && + CreateBufferResource(g_pd3dDeviceParam, resource, D3D12_RESOURCE_STATE_COPY_SOURCE, &fgHudlessBuffer[fIndex])) + { + ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); + cmdList->CopyResource(fgHudlessBuffer[fIndex], resource); + ResourceBarrier(cmdList, fgHudlessBuffer[fIndex], D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + + 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_DEBUG_ONLY("Using fgFormatTransfer->Buffer()"); + fgHudless[fIndex] = ImGuiOverlayDx::fgFormatTransfer->Buffer(); + } + } + else + { + if (CreateBufferResource(g_pd3dDeviceParam, resource, D3D12_RESOURCE_STATE_COPY_DEST, &fgHudless[fIndex])) + cmdList->CopyResource(fgHudless[fIndex], resource); + } + + GetHudless(cmdList, true); } static bool CheckForHudless(ResourceInfo* resource, bool checkFormat = true) @@ -739,8 +771,10 @@ static bool CheckForHudless(ResourceInfo* resource, bool checkFormat = true) Config::Instance()->SCChanged = false; } - if (resource->height == fgScDesc.BufferDesc.Height && resource->width == fgScDesc.BufferDesc.Width && - (!checkFormat || resource->format == fgScDesc.BufferDesc.Format)) + 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_DEBUG_ONLY("Width: {}/{}, Height: {}/{}, Format: {}/{}, checkFormat: {} -> TRUE", resource->width, fgScDesc.BufferDesc.Width, resource->height, fgScDesc.BufferDesc.Height, (UINT)resource->format, (UINT)fgScDesc.BufferDesc.Format, checkFormat); @@ -748,6 +782,9 @@ static bool CheckForHudless(ResourceInfo* resource, bool checkFormat = true) return true; } + LOG_DEBUG_ONLY("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; } @@ -911,7 +948,7 @@ static void hkCopyTextureRegion(ID3D12GraphicsCommandList* This, D3D12_TEXTURE_C auto fIndex = fgFrameIndex; - if (This == g_pd3dCommandList || ImGuiOverlayDx::fgCopyCommandList == This /* || fgPresentRunning */ || ImGuiOverlayDx::fgSkipHudlessChecks || Config::Instance()->CurrentFeature == nullptr || !ImGuiOverlayDx::upscaleRan) + 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 || @@ -1317,7 +1354,7 @@ static void hkDrawIndexedInstanced(ID3D12GraphicsCommandList* This, UINT IndexCo do { std::shared_lock lock2(hudlessMutex[fIndex]); - auto val0 = fgPossibleHudless[fIndex][This]; + auto& val0 = fgPossibleHudless[fIndex][This]; // if this command list does not have entries skip if (val0.size() == 0) @@ -1377,7 +1414,7 @@ static void hkDispatch(ID3D12GraphicsCommandList* This, UINT ThreadGroupCountX, do { std::shared_lock lock2(hudlessMutex[fIndex]); - auto val0 = fgPossibleHudless[fIndex][This]; + auto& val0 = fgPossibleHudless[fIndex][This]; // if this command list does not have entries skip if (val0.size() == 0) @@ -3218,29 +3255,19 @@ void ImGuiOverlayDx::NewFrame() auto newIndex = (fIndex + 2) % FG_BUFFER_SIZE; - //{ - // // LOG_DEBUG_ONLY("lockframeResourceMutex[{}])", newIndex); - // std::unique_lock lock(frameResourceMutex[newIndex]); - // fgFrameResourcesByCpuHandle[newIndex].clear(); - // fgFrameResourcesByGpuHandle[newIndex].clear(); - //} - { - // LOG_DEBUG_ONLY("locksourceMutex[{}])", newIndex); - //std::unique_lock lock(sourceMutex[newIndex]); - //fgSources[newIndex].clear(); fgCopySource[newIndex] = nullptr; } { - // LOG_DEBUG_ONLY("lockshaderMutex[{}])", newIndex); std::unique_lock lock(hudlessMutex[newIndex]); - //fgShaderInputs[newIndex].clear(); fgPossibleHudless[newIndex].clear(); } - std::unique_lock lock(counterMutex[newIndex]); - ImGuiOverlayDx::fgHUDlessCaptureCounter[newIndex] = 0; + { + std::unique_lock lock(counterMutex[newIndex]); + ImGuiOverlayDx::fgHUDlessCaptureCounter[newIndex] = 0; + } } void ImGuiOverlayDx::UnHookDx() diff --git a/OptiScaler/imgui/imgui_overlay_dx.h b/OptiScaler/imgui/imgui_overlay_dx.h index 8f9480be..c37f6eff 100644 --- a/OptiScaler/imgui/imgui_overlay_dx.h +++ b/OptiScaler/imgui/imgui_overlay_dx.h @@ -8,6 +8,7 @@ #include #include #include +#include "../format_transfer/FT_Dx12.h" namespace ImGuiOverlayDx { @@ -48,7 +49,8 @@ namespace ImGuiOverlayDx 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 ID3D12Resource* fgUpscaledImage[FG_BUFFER_SIZE] = { nullptr, nullptr, nullptr, nullptr }; + inline FT_Dx12* fgFormatTransfer = nullptr; void UnHookDx(); void HookDx(); diff --git a/OptiScaler/resource.h b/OptiScaler/resource.h index e09a7bfa..71099fa0 100644 --- a/OptiScaler/resource.h +++ b/OptiScaler/resource.h @@ -21,7 +21,7 @@ #define VER_MAJOR_VERSION 0 #define VER_MINOR_VERSION 7 #define VER_HOTFIX_VERSION 0 -#define VER_BUILD_NUMBER 21 +#define VER_BUILD_NUMBER 22 #define VER_PRE_RELEASE