From 94d729d6f31dbd9e7e7cfc73a1a1811fe81d10a3 Mon Sep 17 00:00:00 2001 From: "matthieu.begoghina" <12561988+Voulz@users.noreply.github.com> Date: Mon, 25 Mar 2024 23:55:27 +1100 Subject: [PATCH] DirectX11 fixes for UR-190 and UR-177 Properly handles DirectX11 states within UE, as well as proper handling of UAVs --- .../Platform/RiveRenderTargetD3D11.cpp | 35 ++------ .../Private/Platform/RiveRendererD3D11.cpp | 89 ++----------------- .../Private/Platform/RiveRendererD3D11.h | 18 +--- Source/RiveRenderer/RiveRenderer.Build.cs | 16 +++- 4 files changed, 26 insertions(+), 132 deletions(-) diff --git a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp index e595195f..1f7327c0 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp +++ b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp @@ -70,43 +70,18 @@ void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::CacheTextureTarget_Ren void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::Render_RenderThread(FRHICommandListImmediate& RHICmdList, const TArray& RiveRenderCommands) { - // -- First, we start a render pass todo: might not be needed here + // First, we transition the texture to a RenderTextureView FTextureRHIRef TargetTexture = RenderTarget->GetResource()->TextureRHI; RHICmdList.Transition(FRHITransitionInfo(TargetTexture, ERHIAccess::Unknown, ERHIAccess::RTV)); - FRHIRenderPassInfo RPInfo(TargetTexture, ERenderTargetActions::Load_Store); - RHICmdList.BeginRenderPass(RPInfo, TEXT("RiveRenderingTexture")); - - // -- Then we render Rive, ensuring the DX11 states are reset before the call + // Then we render Rive, ensuring the DX11 states are reset before and after the call RHICmdList.EnqueueLambda([this, RiveRenderCommands](FRHICommandListImmediate& RHICmdList) { - RiveRendererD3D11->ResetDXStateForRive(); + RiveRendererD3D11->ResetDXState(); FRiveRenderTarget::Render_Internal(RiveRenderCommands); RiveRendererD3D11->ResetDXState(); }); - - // -- Lastly, now that we have manually reset DX11, we need to update the state to ensure it matches the direct calls we just made - { - FGlobalShaderMap* ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel); - TShaderMapRef VertexShader(ShaderMap); - TShaderMapRef PixelShader(ShaderMap); - - FGraphicsPipelineStateInitializer GraphicsPSOInit; - RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); - // same as default D3D11_BLEND_DESC which is same as passing null to OMSetBlendState - GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); - // NOT the same as default D3D11_RASTERIZER_DESC, a matching Rasterizer has been created in FRiveRendererD3D11GPUAdapter::InitBlendState - GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); - // NOT the same as default D3D11_DEPTH_STENCIL_DESC, a matching DepthStencil has been created in FRiveRendererD3D11GPUAdapter::InitBlendState - GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); - GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; - GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader(); - GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); - GraphicsPSOInit.PrimitiveType = PT_TriangleList; - SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0, EApplyRendertargetOption::CheckApply, false); - } - RHICmdList.EndRenderPass(); - RHICmdList.Transition(FRHITransitionInfo(TargetTexture, ERHIAccess::RTV, ERHIAccess::SRVMask)); - + // Finally we transition the texture to a UAV Graphics + RHICmdList.Transition(FRHITransitionInfo(TargetTexture, ERHIAccess::RTV, ERHIAccess::UAVGraphics)); } rive::rcp UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::GetRenderTarget() const diff --git a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp index 18a2f79a..e61a8dcb 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp +++ b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp @@ -8,6 +8,7 @@ #include "ProfilingDebugging/RealtimeGPUProfiler.h" #include "RiveRenderTargetD3D11.h" #include "Windows/D3D11ThirdParty.h" +#include "D3D11RHIPrivate.h" #if WITH_RIVE #include "RiveCore/Public/PreRiveHeaders.h" @@ -40,87 +41,16 @@ void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::Initialize(rive: AdapterDesc.VendorId == 0x8086 || AdapterDesc.VendorId == 0x8087; } } - - // Init Blend State to fix the issue with Slate UI rendering - InitBlendState(); } #endif // WITH_RIVE -void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::ResetDXStateForRive() -{ - if (!D3D11DeviceContext) - { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DeviceContext is nullptr while resetting the DirectX state")); - return; - } - - // Rive is resetting the Rasterizer and BlendState in PLSRenderContextD3DImpl::flush, so no need to call them - // the DepthStencil is not set by Rive, so we reset to default - D3D11DeviceContext->OMSetDepthStencilState(nullptr, 0); -} - void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::ResetDXState() { - if (!D3D11DeviceContext) + // Clear the internal state kept by UE and reset DX + FD3D11DynamicRHI* DynRHI = static_cast(D3D11RHI); + if (ensure(DynRHI)) { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DeviceContext is nullptr while resetting the DirectX state")); - return; - } - - // We don't need to set a BlendState because we can match the default with TStaticBlendState<>::GetRHI(); - D3D11DeviceContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF); - // We need a Rasterizer because the default state sets D3D11_RASTERIZER_DESC::FrontCounterClockwise to false, but UE sets it to true - D3D11DeviceContext->RSSetState(DefaultRasterState); - // We also need a DepthStencil because the default raster state states D3D11_DEPTH_STENCIL_DESC::DepthWriteMask to D3D11_DEPTH_WRITE_MASK_ALL, but UE crashed with that option - D3D11DeviceContext->OMSetDepthStencilState(DefaultDepthStencilState, 0); -} - -void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::InitBlendState() -{ - check(IsInRenderingThread()); - check(D3D11DevicePtr); - - // Below is matching TStaticRasterizerState<>::GetRHI(); - D3D11_RASTERIZER_DESC RasterDesc; - FMemory::Memzero(&RasterDesc,sizeof(D3D11_RASTERIZER_DESC)); - RasterDesc.CullMode = D3D11_CULL_NONE; - RasterDesc.FillMode = D3D11_FILL_SOLID; - RasterDesc.SlopeScaledDepthBias = 0.f; - RasterDesc.FrontCounterClockwise = true; - RasterDesc.DepthBias = 0.f; - RasterDesc.DepthClipEnable = true; - RasterDesc.MultisampleEnable = true; - RasterDesc.ScissorEnable = true; - - RasterDesc.AntialiasedLineEnable = false; - RasterDesc.DepthBiasClamp = 0.f; - - HRESULT Hr = D3D11DevicePtr->CreateRasterizerState(&RasterDesc, DefaultRasterState.GetInitReference()); - if (FAILED(Hr)) - { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DevicePtr->CreateRasterizerState( &RasterDesc, NormalRasterState.GetInitReference() ) Failed")); - } - - // Below is matching TStaticDepthStencilState::GetRHI(); - D3D11_DEPTH_STENCIL_DESC DepthStencilDesc; - FMemory::Memzero(&DepthStencilDesc,sizeof(D3D11_DEPTH_STENCIL_DESC)); - DepthStencilDesc.DepthEnable = true; // because DepthTest = CF_DepthNearOrEqual - DepthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - DepthStencilDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; // CF_DepthNearOrEqual has no match - - DepthStencilDesc.StencilEnable = false; - DepthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS ; - DepthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - DepthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - DepthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - DepthStencilDesc.BackFace = DepthStencilDesc.FrontFace; - DepthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - DepthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - - Hr = D3D11DevicePtr->CreateDepthStencilState( &DepthStencilDesc, DefaultDepthStencilState.GetInitReference() ); - if (FAILED(Hr)) - { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DevicePtr->CreateDepthStencilState( &DepthStencilDesc, DepthStencilState.GetInitReference() ) Failed")); + DynRHI->ClearState(); } } @@ -167,15 +97,6 @@ void UE::Rive::Renderer::Private::FRiveRendererD3D11::CreatePLSRenderer_RenderTh RIVE_DEBUG_FUNCTION_INDENT; } -void UE::Rive::Renderer::Private::FRiveRendererD3D11::ResetDXStateForRive() const -{ - check(IsInRenderingThread()); - check(D3D11GPUAdapter.IsValid()); - - FScopeLock Lock(&ThreadDataCS); - D3D11GPUAdapter->ResetDXStateForRive(); -} - void UE::Rive::Renderer::Private::FRiveRendererD3D11::ResetDXState() const { check(IsInRenderingThread()); diff --git a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h index 7070a0fc..154c5473 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h +++ b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h @@ -35,24 +35,18 @@ namespace UE::Rive::Renderer::Private #if WITH_RIVE void Initialize(rive::pls::PLSRenderContextD3DImpl::ContextOptions& OutContextOptions); #endif // WITH_RIVE - void ResetDXStateForRive(); void ResetDXState(); ID3D11DynamicRHI* GetD3D11RHI() const { return D3D11RHI; } ID3D11Device* GetD3D11DevicePtr() const { return D3D11DevicePtr; } ID3D11DeviceContext* GetD3D11DeviceContext() const { return D3D11DeviceContext; } IDXGIDevice* GetDXGIDevice() const { return DXGIDevice; } - - private: - void InitBlendState(); + private: ID3D11DynamicRHI* D3D11RHI = nullptr; ID3D11Device* D3D11DevicePtr = nullptr; ID3D11DeviceContext* D3D11DeviceContext = nullptr; TRefCountPtr DXGIDevice = nullptr; - - TRefCountPtr DefaultDepthStencilState; - TRefCountPtr DefaultRasterState; }; class RIVERENDERER_API FRiveRendererD3D11 : public FRiveRenderer @@ -60,21 +54,13 @@ namespace UE::Rive::Renderer::Private /** * Structor(s) */ - public: //~ BEGIN : IRiveRenderer Interface - - public: - virtual IRiveRenderTargetPtr CreateTextureTarget_GameThread(const FName& InRiveName, UTexture2DDynamic* InRenderTarget) override; - virtual void CreatePLSContext_RenderThread(FRHICommandListImmediate& RHICmdList) override; - virtual void CreatePLSRenderer_RenderThread(FRHICommandListImmediate& RHICmdList) override; - //~ END : IRiveRenderer Interface - - void ResetDXStateForRive() const; + void ResetDXState() const; private: diff --git a/Source/RiveRenderer/RiveRenderer.Build.cs b/Source/RiveRenderer/RiveRenderer.Build.cs index 6863cec2..3b35d452 100644 --- a/Source/RiveRenderer/RiveRenderer.Build.cs +++ b/Source/RiveRenderer/RiveRenderer.Build.cs @@ -46,10 +46,22 @@ public RiveRenderer(ReadOnlyTargetRules Target) : base(Target) if (Target.Platform.IsInGroup(UnrealPlatformGroup.Windows)) { - PublicIncludePathModuleNames.AddAll("D3D11RHI"); // , "D3D12RHI"); + PublicDependencyModuleNames.Add("D3D11RHI"); + PublicIncludePathModuleNames.AddAll("RHICore", "D3D11RHI"); // , "D3D12RHI"); AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11"); - // AddEngineThirdPartyPrivateStaticDependencies(Target, "DX12"); + // AddEngineThirdPartyPrivateStaticDependencies(Target, "DX12"); + + // Adding the path needed to include the private file D3D11RHIPrivate.h + string enginePath = Path.GetFullPath(Target.RelativeEnginePath); + string sourcePath = Path.Combine(enginePath, "Source", "Runtime"); + PrivateIncludePaths.Add(Path.Combine(sourcePath, "Windows", "D3D11RHI", "Private")); + PublicIncludePaths.Add(Path.Combine(sourcePath, "Windows", "D3D11RHI", "Private")); + + // Copied from D3D11RHI.build.cs, needed to include the private file D3D11RHIPrivate.h + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelExtensionsFramework"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelMetricsDiscovery"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "NVAftermath"); } else if (Target.Platform.IsInGroup(UnrealPlatformGroup.Android)) {