Skip to content

Commit

Permalink
DirectX11 fixes for UR-190 and UR-177
Browse files Browse the repository at this point in the history
Properly handles DirectX11 states within UE, as well as proper handling of UAVs
  • Loading branch information
Voulz committed Mar 25, 2024
1 parent 3ec248d commit 94d729d
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 132 deletions.
35 changes: 5 additions & 30 deletions Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,43 +70,18 @@ void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::CacheTextureTarget_Ren

void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::Render_RenderThread(FRHICommandListImmediate& RHICmdList, const TArray<FRiveRenderCommand>& 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<FScreenVS> VertexShader(ShaderMap);
TShaderMapRef<FScreenPS> 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<false>::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<rive::pls::PLSRenderTarget> UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::GetRenderTarget() const
Expand Down
89 changes: 5 additions & 84 deletions Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<FD3D11DynamicRHI*>(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<false>::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();
}
}

Expand Down Expand Up @@ -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());
Expand Down
18 changes: 2 additions & 16 deletions Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,46 +35,32 @@ 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<IDXGIDevice> DXGIDevice = nullptr;

TRefCountPtr<ID3D11DepthStencilState> DefaultDepthStencilState;
TRefCountPtr<ID3D11RasterizerState> DefaultRasterState;
};

class RIVERENDERER_API FRiveRendererD3D11 : public FRiveRenderer
{
/**
* 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:
Expand Down
16 changes: 14 additions & 2 deletions Source/RiveRenderer/RiveRenderer.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down

0 comments on commit 94d729d

Please sign in to comment.