XinJiangBBH_LBE/Plugins/Streamline/Source/StreamlineD3D11RHI/Private/StreamlineD3D11RHI.cpp

360 lines
12 KiB
C++
Raw Permalink Normal View History

2025-03-13 11:09:44 +08:00
/*
* Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include "StreamlineD3D11RHI.h"
#include "Features/IModularFeatures.h"
#include "GenericPlatform/GenericPlatformFile.h"
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
#include "ID3D11DynamicRHI.h"
#include "Windows/D3D11ThirdParty.h" // for dxgi1_6.h
#else
#include "D3D11RHIPrivate.h"
THIRD_PARTY_INCLUDES_START
#include "dxgi1_6.h"
THIRD_PARTY_INCLUDES_END
#endif
#include "D3D11Util.h"
#include "HAL/IConsoleManager.h"
#include "Misc/Paths.h"
#include "Modules/ModuleManager.h"
#include "Windows/IDXGISwapchainProvider.h"
#include "StreamlineAPI.h"
#include "StreamlineConversions.h"
#include "StreamlineRHI.h"
#include "sl.h"
#include "sl_dlss_g.h"
// The UE module
DEFINE_LOG_CATEGORY_STATIC(LogStreamlineD3D11RHI, Log, All);
#define LOCTEXT_NAMESPACE "StreamlineD3D11RHI"
class FStreamlineD3D11DXGISwapchainProvider : public IDXGISwapchainProvider
{
public:
FStreamlineD3D11DXGISwapchainProvider(const FStreamlineRHI* InRHI) : StreamlineRHI(InRHI) {}
virtual ~FStreamlineD3D11DXGISwapchainProvider() = default;
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1
bool SupportsRHI(ERHIInterfaceType RHIType) const override final { return RHIType == ERHIInterfaceType::D3D11; }
#else
bool SupportsRHI(const TCHAR* RHIName) const override final { return FString(RHIName) == FString("D3D11"); }
#endif
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3
const TCHAR* GetProviderName() const override final { return TEXT("FStreamlineD3D11DXGISwapchainProvider"); }
#else
TCHAR* GetName() const override final
{
static TCHAR Name[] = TEXT("FStreamlineD3D11DXGISwapchainProvider");
return Name;
}
#endif
HRESULT CreateSwapChainForHwnd(IDXGIFactory2* pFactory, IUnknown* pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* pDesc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullScreenDesc, IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) override final
{
HRESULT DXGIResult = LONG_ERROR;
if (!StreamlineRHI->IsSwapchainHookingAllowed())
{
DXGIResult = pFactory->CreateSwapChainForHwnd(pDevice, hWnd, pDesc, pFullScreenDesc, pRestrictToOutput, ppSwapChain);
}
else
{
// TODO: what happens if a second swapchain is created while PIE is active?
IDXGIFactory2* SLFactory = pFactory;
sl::Result SLResult = SLUpgradeInterface(reinterpret_cast<void**>(&SLFactory));
checkf(SLResult == sl::Result::eOk, TEXT("%s: error upgrading IDXGIFactory (%s)"), ANSI_TO_TCHAR(__FUNCTION__), ANSI_TO_TCHAR(sl::getResultAsStr(SLResult)));
DXGIResult = SLFactory->CreateSwapChainForHwnd(pDevice, hWnd, pDesc, pFullScreenDesc, pRestrictToOutput, ppSwapChain);
}
StreamlineRHI->OnSwapchainCreated(ppSwapChain);
return DXGIResult;
}
HRESULT CreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI_SWAP_CHAIN_DESC* pDesc, IDXGISwapChain** ppSwapChain) override final
{
HRESULT DXGIResult = LONG_ERROR;
if (!StreamlineRHI->IsSwapchainHookingAllowed())
{
DXGIResult = pFactory->CreateSwapChain(pDevice, pDesc, ppSwapChain);
}
else
{
// TODO: what happens if a second swapchain is created while PIE is active?
IDXGIFactory* SLFactory = pFactory;
sl::Result SLResult = SLUpgradeInterface(reinterpret_cast<void**>(&SLFactory));
checkf(SLResult == sl::Result::eOk, TEXT("%s: error upgrading IDXGIFactory (%s)"), ANSI_TO_TCHAR(__FUNCTION__), ANSI_TO_TCHAR(sl::getResultAsStr(SLResult)));
DXGIResult = SLFactory->CreateSwapChain(pDevice, pDesc, ppSwapChain);
}
StreamlineRHI->OnSwapchainCreated(*ppSwapChain);
return DXGIResult;
}
private:
const FStreamlineRHI* StreamlineRHI;
};
class STREAMLINED3D11RHI_API FStreamlineD3D11RHI : public FStreamlineRHI
{
public:
FStreamlineD3D11RHI(const FStreamlineRHICreateArguments& Arguments)
: FStreamlineRHI(Arguments)
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
, D3D11RHI(CastDynamicRHI<ID3D11DynamicRHI>(Arguments.DynamicRHI))
#else
, D3D11RHI(static_cast<FD3D11DynamicRHI*>(Arguments.DynamicRHI))
#endif
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Enter"), ANSI_TO_TCHAR(__FUNCTION__));
check(D3D11RHI != nullptr);
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
DXGI_ADAPTER_DESC DXGIAdapterDesc;
D3D11RHI->RHIGetAdapter()->GetDesc(&DXGIAdapterDesc);
#elif ENGINE_MAJOR_VERSION > 4
DXGI_ADAPTER_DESC DXGIAdapterDesc = D3D11RHI->GetAdapter().DXGIAdapterDesc;
#else
ID3D11Device* NativeD3D11Device = static_cast<ID3D11Device*>(D3D11RHI->RHIGetNativeDevice());
check(NativeD3D11Device != nullptr);
TRefCountPtr<IDXGIDevice> DXGIDevice;
NativeD3D11Device->QueryInterface(__uuidof(IDXGIDevice), (void**)DXGIDevice.GetInitReference());
check(DXGIDevice.IsValid());
TRefCountPtr<IDXGIAdapter> DXGIAdapter;
DXGIDevice->GetAdapter(DXGIAdapter.GetInitReference());
check(DXGIAdapter.IsValid());
DXGI_ADAPTER_DESC DXGIAdapterDesc;
DXGIAdapter->GetDesc(&DXGIAdapterDesc);
#endif
AdapterLuid = DXGIAdapterDesc.AdapterLuid;
SLAdapterInfo.deviceLUID = reinterpret_cast<uint8_t*>(&AdapterLuid);
SLAdapterInfo.deviceLUIDSizeInBytes = sizeof(AdapterLuid);
SLAdapterInfo.vkPhysicalDevice = nullptr;
if (IsStreamlineSupported())
{
TTuple<bool, FString> bSwapchainProvider = IsSwapChainProviderRequired(SLAdapterInfo);
if (bSwapchainProvider.Get<0>())
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("Registering FStreamlineD3D11DXGISwapchainProvider as IDXGISwapchainProvider, due to %s"), *bSwapchainProvider.Get<1>());
CustomSwapchainProvider = MakeUnique<FStreamlineD3D11DXGISwapchainProvider>(this);
IModularFeatures::Get().RegisterModularFeature(IDXGISwapchainProvider::GetModularFeatureName(), CustomSwapchainProvider.Get());
bIsSwapchainProviderInstalled = true;
}
else
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("Skip registering IDXGISwapchainProvider, due to %s"), *bSwapchainProvider.Get<1>());
bIsSwapchainProviderInstalled = false;
}
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Leave"), ANSI_TO_TCHAR(__FUNCTION__));
}
virtual ~FStreamlineD3D11RHI()
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Enter"), ANSI_TO_TCHAR(__FUNCTION__));
if (CustomSwapchainProvider.IsValid())
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("Unregistering FStreamlineD3D11DXGISwapchainProvider as IDXGISwapchainProvider"));
IModularFeatures::Get().UnregisterModularFeature(IDXGISwapchainProvider::GetModularFeatureName(), CustomSwapchainProvider.Get());
CustomSwapchainProvider.Reset();
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Leave"), ANSI_TO_TCHAR(__FUNCTION__));
}
virtual void TagTextures(FRHICommandList& CmdList, uint32 InViewID, const TArrayView<const FRHIStreamlineResource> InResources) final
{
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
void* NativeCmdBuffer = D3D11RHI->RHIGetDeviceContext();
#else
void* NativeCmdBuffer = D3D11RHI->GetDeviceContext();
#endif
for (const FRHIStreamlineResource& Resource : InResources)
{
sl::Resource SLResource;
FMemory::Memzero(SLResource);
if (Resource.Texture && Resource.Texture->IsValid())
{
SLResource.native = Resource.Texture->GetNativeResource();
}
SLResource.type = sl::ResourceType::eTex2d;
// no resource state in d3d11
SLResource.state = 0;
sl::ResourceTag Tag;
Tag.resource = &SLResource;
Tag.type = ToSL(Resource.StreamlineTag);
// TODO: sl::ResourceLifecycle::eValidUntilPreset would be more efficient, are there any textures where it's applicable?
Tag.lifecycle = sl::ResourceLifecycle::eOnlyValidNow;
Tag.extent = ToSL(Resource.ViewRect);
SLsetTag(sl::ViewportHandle(InViewID), &Tag, 1, NativeCmdBuffer);
}
}
virtual void* GetCommandBuffer(FRHICommandList& CmdList, FRHITexture* Texture) override final
{
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
return D3D11RHI->RHIGetDeviceContext();
#else
return D3D11RHI->GetDeviceContext();
#endif
}
virtual void PostStreamlineFeatureEvaluation(FRHICommandList& CmdList, FRHITexture* Texture) final
{
}
virtual const sl::AdapterInfo* GetAdapterInfo() override final
{
return &SLAdapterInfo;
}
virtual bool IsDLSSGSupportedByRHI() const override final
{
return true;
}
virtual bool IsDeepDVCSupportedByRHI() const override final
{
return true;
}
virtual void APIErrorHandler(const sl::APIError& LastError) final
{
// Not all DXGI return codes are errors, e.g. DXGI_STATUS_OCCLUDED
if (IsDXGIStatus(LastError.hres))
{
return;
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("DLSSG D3D11/DXGI Error %d"), LastError.hres);
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3
D3D11RHI->RHIVerifyResult(D3D11RHI->RHIGetDevice(), LastError.hres, "Streamline/DLSSG present", __FILE__, __LINE__);
#else
VerifyD3D11Result(LastError.hres, "Streamline/DLSSG present", __FILE__, __LINE__, static_cast<ID3D11Device*>(GDynamicRHI->RHIGetNativeDevice()));
#endif
}
virtual bool IsStreamlineSwapchainProxy(void* NativeSwapchain) const override final
{
TRefCountPtr<IUnknown> NativeInterface;
const sl::Result Result = SLgetNativeInterface(NativeSwapchain, IID_PPV_ARGS_Helper(NativeInterface.GetInitReference()));
if (Result == sl::Result::eOk)
{
return NativeInterface != NativeSwapchain;
}
else
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("SLgetNativeInterface(%p) failed (%d, %s)"), NativeSwapchain, Result, ANSI_TO_TCHAR(sl::getResultAsStr(Result)));
}
return false;
}
protected:
private:
#if ENGINE_PROVIDES_ID3D11DYNAMICRHI
ID3D11DynamicRHI* D3D11RHI = nullptr;
#else
FD3D11DynamicRHI* D3D11RHI = nullptr;
#endif
LUID AdapterLuid;
sl::AdapterInfo SLAdapterInfo;
TUniquePtr<FStreamlineD3D11DXGISwapchainProvider> CustomSwapchainProvider;
};
/** IModuleInterface implementation */
void FStreamlineD3D11RHIModule::StartupModule()
{
auto CVarInitializePlugin = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streamline.InitializePlugin"));
if (CVarInitializePlugin && !CVarInitializePlugin->GetBool() || (FParse::Param(FCommandLine::Get(), TEXT("slno"))))
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("Initialization of StreamlineD3D11RHI is disabled."));
return;
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Enter"), ANSI_TO_TCHAR(__FUNCTION__));
if(FApp::CanEverRender())
{
if ((GDynamicRHI != nullptr) && (GDynamicRHI->GetName() == FString("D3D11")))
{
FStreamlineRHIModule& StreamlineRHIModule = FModuleManager::LoadModuleChecked<FStreamlineRHIModule>(TEXT("StreamlineRHI"));
if (AreStreamlineFunctionsLoaded())
{
StreamlineRHIModule.InitializeStreamline();
if (IsStreamlineSupported())
{
sl::Result Result = SLsetD3DDevice(GDynamicRHI->RHIGetNativeDevice());
checkf(Result == sl::Result::eOk, TEXT("%s: SLsetD3DDevice failed (%s)"), ANSI_TO_TCHAR(__FUNCTION__), ANSI_TO_TCHAR(sl::getResultAsStr(Result)));
}
}
}
else
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("D3D11RHI is not the active DynamicRHI; skipping of setting up the custom swapchain factory"));
}
}
else
{
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("This UE instance does not render, skipping initalizing of Streamline and registering of custom DXGI and D3D11 functions"));
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Leave"), ANSI_TO_TCHAR(__FUNCTION__));
}
void FStreamlineD3D11RHIModule::ShutdownModule()
{
auto CVarInitializePlugin = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streamline.InitializePlugin"));
if (CVarInitializePlugin && !CVarInitializePlugin->GetBool())
{
return;
}
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Enter"), ANSI_TO_TCHAR(__FUNCTION__));
UE_LOG(LogStreamlineD3D11RHI, Log, TEXT("%s Leave"), ANSI_TO_TCHAR(__FUNCTION__));
}
TUniquePtr<FStreamlineRHI> FStreamlineD3D11RHIModule::CreateStreamlineRHI(const FStreamlineRHICreateArguments& Arguments)
{
TUniquePtr<FStreamlineRHI> Result(new FStreamlineD3D11RHI(Arguments));
return Result;
}
IMPLEMENT_MODULE(FStreamlineD3D11RHIModule, StreamlineD3D11RHI )
#undef LOCTEXT_NAMESPACE