#include "pch.h" #include "XeSSFeature_Dx11.h" #include "Config.h" #include "dxgi1_6.h" #include #define ASSIGN_DESC(dest, src) dest->Width = src.Width; dest->Height = src.Height; dest->Format = src.Format; dest->BindFlags = src.BindFlags; #define SAFE_RELEASE(p) \ do { \ if(p && p != nullptr) \ { \ (p)->Release(); \ (p) = nullptr; \ } \ } while((void)0, 0); bool XeSSFeatureDx11::CopyTextureFrom11To12(ID3D11Resource* d3d11texture, ID3D11Texture2D** pSharedTexture, D3D11_TEXTURE2D_DESC_C* sharedDesc, bool copy = true) { ID3D11Texture2D* originalTexture = nullptr; D3D11_TEXTURE2D_DESC desc{}; auto result = d3d11texture->QueryInterface(IID_PPV_ARGS(&originalTexture)); if (result != S_OK) return false; originalTexture->GetDesc(&desc); if ((desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED) == 0) { if (desc.Width != sharedDesc->Width || desc.Height != sharedDesc->Height || desc.Format != sharedDesc->Format || desc.BindFlags != sharedDesc->BindFlags || (*pSharedTexture) == nullptr) { if ((*pSharedTexture) != nullptr) (*pSharedTexture)->Release(); ASSIGN_DESC(sharedDesc, desc); sharedDesc->pointer = nullptr; sharedDesc->handle = NULL; desc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED; result = Dx11Device->CreateTexture2D(&desc, nullptr, pSharedTexture); IDXGIResource1* resource; result = (*pSharedTexture)->QueryInterface(IID_PPV_ARGS(&resource)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CopyTextureFrom11To12 QueryInterface(resource) error: {0:x}", result); return false; } // Get shared handle result = resource->GetSharedHandle(&sharedDesc->handle); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CopyTextureFrom11To12 GetSharedHandle error: {0:x}", result); return false; } resource->Release(); sharedDesc->pointer = (*pSharedTexture); } if (copy) Dx11DeviceContext->CopyResource(*pSharedTexture, d3d11texture); } else { if (sharedDesc->pointer != d3d11texture) { IDXGIResource1* resource; result = originalTexture->QueryInterface(IID_PPV_ARGS(&resource)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CopyTextureFrom11To12 QueryInterface(resource) error: {0:x}", result); return false; } // Get shared handle result = resource->GetSharedHandle(&sharedDesc->handle); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CopyTextureFrom11To12 GetSharedHandle error: {0:x}", result); return false; } resource->Release(); sharedDesc->pointer = d3d11texture; } } originalTexture->Release(); return true; } void XeSSFeatureDx11::ReleaseSharedResources() { spdlog::debug("XeSSFeatureDx11::ReleaseSharedResources start!"); SAFE_RELEASE(dx11Color.SharedTexture); SAFE_RELEASE(dx11Mv.SharedTexture); SAFE_RELEASE(dx11Out.SharedTexture); SAFE_RELEASE(dx11Depth.SharedTexture); SAFE_RELEASE(dx11Tm.SharedTexture); SAFE_RELEASE(dx11Exp.SharedTexture); } void XeSSFeatureDx11::GetHardwareAdapter(IDXGIFactory1* pFactory, IDXGIAdapter** ppAdapter, D3D_FEATURE_LEVEL featureLevel, bool requestHighPerformanceAdapter) { spdlog::debug("XeSSFeatureDx11::GetHardwareAdapter"); *ppAdapter = nullptr; IDXGIAdapter1* adapter; IDXGIFactory6* factory6; if (SUCCEEDED(pFactory->QueryInterface(IID_PPV_ARGS(&factory6)))) { for ( UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != factory6->EnumAdapterByGpuPreference( adapterIndex, requestHighPerformanceAdapter == true ? DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE : DXGI_GPU_PREFERENCE_UNSPECIFIED, IID_PPV_ARGS(&adapter)); ++adapterIndex) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { // Don't select the Basic Render Driver adapter. // If you want a software adapter, pass in "/warp" on the command line. continue; } // Check to see whether the adapter supports Direct3D 12, but don't create the // actual device yet. auto result = D3D12CreateDevice(adapter, featureLevel, _uuidof(ID3D12Device), nullptr); if (result == S_FALSE) { *ppAdapter = adapter; break; } } } else { for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1(adapterIndex, &adapter); ++adapterIndex) { DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { // Don't select the Basic Render Driver adapter. // If you want a software adapter, pass in "/warp" on the command line. continue; } // Check to see whether the adapter supports Direct3D 12, but don't create the // actual device yet. auto result = D3D12CreateDevice(adapter, featureLevel, _uuidof(ID3D12Device), nullptr); if (result == S_FALSE) { *ppAdapter = adapter; break; } } } } HRESULT XeSSFeatureDx11::CreateDx12Device(D3D_FEATURE_LEVEL featureLevel) { spdlog::debug("XeSSFeatureDx11::CreateDx12Device"); if (Dx12on11Device) return S_OK; HRESULT result; IDXGIFactory4* factory; result = CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CreateDx12Device Can't create factory: {0:x}", result); return result; } IDXGIAdapter* hardwareAdapter = nullptr; GetHardwareAdapter(factory, &hardwareAdapter, featureLevel, true); if (hardwareAdapter == nullptr) { spdlog::error("XeSSFeatureDx11::CreateDx12Device Can't get hardwareAdapter!"); return E_NOINTERFACE; } result = D3D12CreateDevice(hardwareAdapter, featureLevel, IID_PPV_ARGS(&Dx12on11Device)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CreateDx12Device Can't create device: {0:x}", result); return result; } D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; // CreateCommandQueue result = Dx12on11Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&Dx12CommandQueue)); if (result != S_OK || Dx12CommandQueue == nullptr) { spdlog::debug("XeSSFeatureDx11::CreateDx12Device CreateCommandQueue result: {0:x}", result); return E_NOINTERFACE; } result = Dx12on11Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&Dx12CommandAllocator)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CreateDx12Device CreateCommandAllocator error: {0:x}", result); return E_NOINTERFACE; } // CreateCommandList result = Dx12on11Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, Dx12CommandAllocator, nullptr, IID_PPV_ARGS(&Dx12CommandList)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::CreateDx12Device CreateCommandList error: {0:x}", result); return E_NOINTERFACE; } return S_OK; } void XeSSFeatureDx11::SetInit(bool value) { XeSSFeature::SetInit(value); } bool XeSSFeatureDx11::IsInited() { return XeSSFeature::IsInited(); } bool XeSSFeatureDx11::Init(ID3D11Device* device, ID3D11DeviceContext* context, const NVSDK_NGX_Parameter* initParams) { spdlog::debug("XeSSFeatureDx11::Init!"); if (IsInited()) return true; Device = device; DeviceContext = context; if (!context) { spdlog::error("XeSSFeatureDx11::Init context is null!"); return false; } auto contextResult = context->QueryInterface(IID_PPV_ARGS(&Dx11DeviceContext)); if (contextResult != S_OK) { spdlog::error("XeSSFeatureDx11::Init QueryInterface ID3D11DeviceContext4 result: {0:x}", contextResult); return false; } if (!device) Dx11DeviceContext->GetDevice(&device); auto dx11DeviceResult = device->QueryInterface(IID_PPV_ARGS(&Dx11Device)); if (dx11DeviceResult != S_OK) { spdlog::error("XeSSFeatureDx11::Init QueryInterface ID3D11Device5 result: {0:x}", dx11DeviceResult); return false; } if (!Dx12on11Device) { auto fl = Dx11Device->GetFeatureLevel(); auto result = CreateDx12Device(fl); if (result != S_OK || !Dx12on11Device) { spdlog::error("XeSSFeatureDx11::Init QueryInterface Dx12Device result: {0:x}", result); return false; } } spdlog::debug("XeSSFeatureDx11::Init calling InitXeSS"); if (Dx12on11Device && !InitXeSS(Dx12on11Device, initParams)) { spdlog::error("XeSSFeatureDx11::Init InitXeSS fail!"); return false; } return true; } bool XeSSFeatureDx11::Evaluate(ID3D11DeviceContext* InDeviceContext, const NVSDK_NGX_Parameter* InParameters) { spdlog::debug("XeSSFeatureDx11::Evaluate"); if (!IsInited() || !_xessContext) return false; ID3D11DeviceContext4* dc; auto result = InDeviceContext->QueryInterface(IID_PPV_ARGS(&dc)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate CreateFence d3d12fence error: {0:x}", result); return false; } if (dc != Dx11DeviceContext) { spdlog::warn("XeSSFeatureDx11::Evaluate Dx11DeviceContext changed!"); ReleaseSharedResources(); Dx11DeviceContext = dc; } // Fence for syncing ID3D12Fence* d3d12Fence; result = Dx12on11Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d12Fence)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate CreateFence d3d12fence error: {0:x}", result); return false; } // creatimg params for XeSS xess_result_t xessResult; xess_d3d12_execute_params_t params{}; InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_X, ¶ms.jitterOffsetX); InParameters->Get(NVSDK_NGX_Parameter_Jitter_Offset_Y, ¶ms.jitterOffsetY); if (InParameters->Get(NVSDK_NGX_Parameter_DLSS_Exposure_Scale, ¶ms.exposureScale) != NVSDK_NGX_Result_Success) params.exposureScale = 1.0f; InParameters->Get(NVSDK_NGX_Parameter_Reset, ¶ms.resetHistory); XeSSFeature::SetRenderResolution(InParameters, ¶ms); spdlog::debug("FeatureContext::XeSSInit Input Resolution: {0}x{1}", params.inputWidth, params.inputHeight); #pragma region Texture copies D3D11_QUERY_DESC pQueryDesc; pQueryDesc.Query = D3D11_QUERY_EVENT; pQueryDesc.MiscFlags = 0; ID3D11Query* query1 = nullptr; result = Dx11Device->CreateQuery(&pQueryDesc, &query1); if (result != S_OK || query1 == nullptr || query1 == NULL) { spdlog::error("XeSSFeatureDx11::Evaluate can't create query1!"); return false; } // Associate the query with the copy operation Dx11DeviceContext->Begin(query1); ID3D11Resource* paramColor; if (InParameters->Get(NVSDK_NGX_Parameter_Color, ¶mColor) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_Color, (void**)¶mColor); if (paramColor) { spdlog::debug("XeSSFeatureDx11::Evaluate Color exist.."); if (CopyTextureFrom11To12(paramColor, &dx11Color.SharedTexture, &dx11Color.Desc) == NULL) return false; } else { spdlog::error("XeSSFeatureDx11::Evaluate Color not exist!!"); return false; } ID3D11Resource* paramMv; if (InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, ¶mMv) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_MotionVectors, (void**)¶mMv); if (paramMv) { spdlog::debug("XeSSFeatureDx11::Evaluate MotionVectors exist.."); if (CopyTextureFrom11To12(paramMv, &dx11Mv.SharedTexture, &dx11Mv.Desc) == false) return false; } else { spdlog::error("XeSSFeatureDx11::Evaluate MotionVectors not exist!!"); return false; } ID3D11Resource* paramOutput; if (InParameters->Get(NVSDK_NGX_Parameter_Output, ¶mOutput) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_Output, (void**)¶mOutput); if (paramOutput) { spdlog::debug("XeSSFeatureDx11::Evaluate Output exist.."); if (CopyTextureFrom11To12(paramOutput, &dx11Out.SharedTexture, &dx11Out.Desc, false) == false) return false; } else { spdlog::error("XeSSFeatureDx11::Evaluate Output not exist!!"); return false; } ID3D11Resource* paramDepth; if (InParameters->Get(NVSDK_NGX_Parameter_Depth, ¶mDepth) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_Depth, (void**)¶mDepth); if (paramDepth) { spdlog::debug("XeSSFeatureDx11::Evaluate Depth exist.."); if (CopyTextureFrom11To12(paramDepth, &dx11Depth.SharedTexture, &dx11Depth.Desc) == false) return false; } else spdlog::error("XeSSFeatureDx11::Evaluate Depth not exist!!"); ID3D11Resource* paramExposure = nullptr; if (!Config::Instance()->AutoExposure.value_or(false)) { if (InParameters->Get(NVSDK_NGX_Parameter_ExposureTexture, ¶mExposure) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_ExposureTexture, (void**)¶mExposure); if (paramExposure) { spdlog::debug("XeSSFeatureDx11::Evaluate ExposureTexture exist.."); if (CopyTextureFrom11To12(paramExposure, &dx11Exp.SharedTexture, &dx11Exp.Desc) == false) return false; } else spdlog::warn("XeSSFeatureDx11::Evaluate AutoExposure disabled but ExposureTexture is not exist, it may cause problems!!"); } else spdlog::debug("XeSSFeatureDx11::Evaluate AutoExposure enabled!"); ID3D11Resource* paramMask = nullptr; if (!Config::Instance()->DisableReactiveMask.value_or(true)) { if (InParameters->Get(NVSDK_NGX_Parameter_DLSS_Input_Bias_Current_Color_Mask, ¶mMask) != NVSDK_NGX_Result_Success) InParameters->Get(NVSDK_NGX_Parameter_DLSS_Input_Bias_Current_Color_Mask, (void**)¶mMask); if (paramMask) { spdlog::debug("XeSSFeatureDx11::Evaluate Bias mask exist.."); if (CopyTextureFrom11To12(paramMask, &dx11Tm.SharedTexture, &dx11Tm.Desc) == false) return false; } else spdlog::warn("XeSSFeatureDx11::Evaluate bias mask not exist and its enabled in config, it may cause problems!!"); } // Execute dx11 commands Dx11DeviceContext->End(query1); Dx11DeviceContext->Flush(); // Wait for the query to be ready while (Dx11DeviceContext->GetData(query1, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_FALSE) { // } // Release the query query1->Release(); if (paramColor) { result = Dx12on11Device->OpenSharedHandle(dx11Color.Desc.handle, IID_PPV_ARGS(¶ms.pColorTexture)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate Color OpenSharedHandle error: {0:x}", result); return false; } } if (paramMv) { result = Dx12on11Device->OpenSharedHandle(dx11Mv.Desc.handle, IID_PPV_ARGS(¶ms.pVelocityTexture)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate MotionVectors OpenSharedHandle error: {0:x}", result); return false; } } if (paramOutput) { result = Dx12on11Device->OpenSharedHandle(dx11Out.Desc.handle, IID_PPV_ARGS(¶ms.pOutputTexture)); dx11Out.SharedHandle = dx11Out.Desc.handle; if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate Output OpenSharedHandle error: {0:x}", result); return false; } } if (paramDepth) { result = Dx12on11Device->OpenSharedHandle(dx11Depth.Desc.handle, IID_PPV_ARGS(¶ms.pDepthTexture)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate Depth OpenSharedHandle error: {0:x}", result); return false; } } if (!Config::Instance()->AutoExposure.value_or(false) && paramExposure) { result = Dx12on11Device->OpenSharedHandle(dx11Exp.Desc.handle, IID_PPV_ARGS(¶ms.pExposureScaleTexture)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate ExposureTexture OpenSharedHandle error: {0:x}", result); return false; } } if (!Config::Instance()->DisableReactiveMask.value_or(true) && paramMask) { result = Dx12on11Device->OpenSharedHandle(dx11Tm.Desc.handle, IID_PPV_ARGS(¶ms.pResponsivePixelMaskTexture)); if (result != S_OK) { spdlog::error("XeSSFeatureDx11::Evaluate TransparencyMask OpenSharedHandle error: {0:x}", result); return false; } } #pragma endregion float MVScaleX; float MVScaleY; if (InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_X, &MVScaleX) == NVSDK_NGX_Result_Success && InParameters->Get(NVSDK_NGX_Parameter_MV_Scale_Y, &MVScaleY) == NVSDK_NGX_Result_Success) { xessResult = xessSetVelocityScale(_xessContext, MVScaleX, MVScaleY); if (xessResult != XESS_RESULT_SUCCESS) { spdlog::error("XeSSFeatureDx11::Evaluate xessSetVelocityScale error: {0}", ResultToString(xessResult)); return false; } } else spdlog::warn("FeatureContext::XeSSExecuteDx12 Can't get motion vector scales!"); // Execute xess spdlog::debug("XeSSFeatureDx11::Evaluate Executing!!"); xessResult = xessD3D12Execute(_xessContext, Dx12CommandList, ¶ms); if (xessResult != XESS_RESULT_SUCCESS) { spdlog::error("XeSSFeatureDx11::Evaluate xessD3D12Execute error: {0}", ResultToString(xessResult)); return false; } // Execute dx12 commands to process xess Dx12CommandList->Close(); ID3D12CommandList* ppCommandLists[] = { Dx12CommandList }; Dx12CommandQueue->ExecuteCommandLists(1, ppCommandLists); // xess done Dx12CommandQueue->Signal(d3d12Fence, 20); // wait for end of copy if (d3d12Fence->GetCompletedValue() < 20) { auto fenceEvent12 = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (fenceEvent12) { d3d12Fence->SetEventOnCompletion(20, fenceEvent12); WaitForSingleObject(fenceEvent12, INFINITE); CloseHandle(fenceEvent12); } } d3d12Fence->Release(); //copy output back ID3D11Query* query2 = nullptr; result = Dx11Device->CreateQuery(&pQueryDesc, &query2); if (result != S_OK || !query2) { spdlog::error("XeSSFeatureDx11::Evaluate can't create query2!"); return false; } // Associate the query with the copy operation Dx11DeviceContext->Begin(query2); Dx11DeviceContext->CopyResource(paramOutput, dx11Out.SharedTexture); // Execute dx11 commands Dx11DeviceContext->End(query2); Dx11DeviceContext->Flush(); // Wait for the query to be ready while (Dx11DeviceContext->GetData(query2, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_FALSE) { // } // Release the query query2->Release(); if (paramColor) params.pColorTexture->Release(); if (paramMv) params.pVelocityTexture->Release(); if (paramDepth) params.pDepthTexture->Release(); if (!Config::Instance()->AutoExposure.value_or(false) && paramExposure) params.pExposureScaleTexture->Release(); if (!Config::Instance()->DisableReactiveMask.value_or(true) && paramMask) params.pResponsivePixelMaskTexture->Release(); if (paramOutput) params.pOutputTexture->Release(); Dx12CommandAllocator->Reset(); Dx12CommandList->Reset(Dx12CommandAllocator, nullptr); return true; } void XeSSFeatureDx11::ReInit(const NVSDK_NGX_Parameter* InParameters) { spdlog::debug("XeSSFeatureDx11::ReInit!"); SetInit(false); if (_xessContext) xessDestroyContext(_xessContext); SetInit(Init(Device, DeviceContext, InParameters)); } XeSSFeatureDx11::~XeSSFeatureDx11() { spdlog::debug("XeSSFeatureDx11::Destroy!"); if (Dx12on11Device && Dx12CommandQueue && Dx12CommandList) { ID3D12Fence* d3d12Fence; Dx12on11Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d12Fence)); Dx12CommandQueue->Signal(d3d12Fence, 999); Dx12CommandList->Close(); ID3D12CommandList* ppCommandLists[] = { Dx12CommandList }; Dx12CommandQueue->ExecuteCommandLists(1, ppCommandLists); auto fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); d3d12Fence->SetEventOnCompletion(999, fenceEvent); WaitForSingleObject(fenceEvent, INFINITE); CloseHandle(fenceEvent); d3d12Fence->Release(); SAFE_RELEASE(Dx12CommandList); SAFE_RELEASE(Dx12CommandQueue); SAFE_RELEASE(Dx12CommandAllocator); SAFE_RELEASE(Dx12on11Device); } ReleaseSharedResources(); }