diff --git a/Source/Rive/Private/Game/RiveActor.cpp b/Source/Rive/Private/Game/RiveActor.cpp index d6e089a0..8f0ad53b 100644 --- a/Source/Rive/Private/Game/RiveActor.cpp +++ b/Source/Rive/Private/Game/RiveActor.cpp @@ -119,7 +119,7 @@ void ARiveActor::EndPlay(const EEndPlayReason::Type EndPlayReason) } } - if (EndPlayReason == EEndPlayReason::EndPlayInEditor) + if (EndPlayReason == EEndPlayReason::EndPlayInEditor && IsValid(RiveFile)) { RiveFile->InstantiateArtboard(); } diff --git a/Source/Rive/Private/Rive/RiveFile.cpp b/Source/Rive/Private/Rive/RiveFile.cpp index b8d27242..5ae16078 100644 --- a/Source/Rive/Private/Rive/RiveFile.cpp +++ b/Source/Rive/Private/Rive/RiveFile.cpp @@ -433,6 +433,7 @@ void URiveFile::Initialize() UE_LOG(LogRive, Error, TEXT("Failed to instantiate the Artboard after importing the rive file.")); BroadcastInitializationResult(false); } + OnArtboardChangedRaw.Broadcast(this, Artboard); OnArtboardChanged.Broadcast(this, Artboard); // Now we can broadcast the Artboard Changed Event return; } @@ -528,6 +529,7 @@ void URiveFile::InstantiateArtboard(bool bRaiseArtboardChangedEvent) if (bRaiseArtboardChangedEvent) { + OnArtboardChangedRaw.Broadcast(this, Artboard); OnArtboardChanged.Broadcast(this, Artboard); } } diff --git a/Source/Rive/Private/Slate/SRiveWidget.cpp b/Source/Rive/Private/Slate/SRiveWidget.cpp index 4d2ae1a2..dc65d7ef 100644 --- a/Source/Rive/Private/Slate/SRiveWidget.cpp +++ b/Source/Rive/Private/Slate/SRiveWidget.cpp @@ -4,6 +4,14 @@ #include "RiveWidgetView.h" #include "Rive/RiveFile.h" +SRiveWidget::~SRiveWidget() +{ + if (IsValid(RiveFile)) + { + RiveFile->OnArtboardChangedRaw.Remove(OnArtboardChangedHandle); + } +} + void SRiveWidget::Construct(const FArguments& InArgs) { ChildSlot @@ -38,9 +46,52 @@ void SRiveWidget::RegisterArtboardInputs(const TArray& InArtboar void SRiveWidget::SetRiveFile(URiveFile* InRiveFile) { - if (RiveWidgetView && IsValid(InRiveFile)) + if (!RiveWidgetView || InRiveFile == RiveFile) + { + return; + } + + if (IsValid(RiveFile)) + { + RiveFile->OnArtboardChangedRaw.Remove(OnArtboardChangedHandle); + } + + if (IsValid(InRiveFile)) + { + RiveFile = InRiveFile; + RiveWidgetView->SetRiveTexture(RiveFile); + if (URiveArtboard* Artboard = RiveFile->GetArtboard()) + { + RiveWidgetView->RegisterArtboardInputs({ Artboard }); + } + else + { + RiveWidgetView->RegisterArtboardInputs({}); + } + + TWeakPtr WeakRiveWidget = SharedThis(this).ToWeakPtr(); + OnArtboardChangedHandle = InRiveFile->OnArtboardChangedRaw.AddSPLambda(this, [WeakRiveWidget, InRiveFile](URiveFile* File, URiveArtboard* Artboard) + { + if (const TSharedPtr RiveWidget = WeakRiveWidget.Pin()) + { + if (ensure(InRiveFile == File) && RiveWidget->RiveWidgetView) + { + if (Artboard) + { + RiveWidget->RiveWidgetView->RegisterArtboardInputs({ Artboard }); + } + else + { + RiveWidget->RiveWidgetView->RegisterArtboardInputs({}); + } + } + } + }); + } + else { - RiveWidgetView->SetRiveTexture(InRiveFile); - RiveWidgetView->RegisterArtboardInputs({ InRiveFile->GetArtboard() }); + RiveFile = nullptr; + RiveWidgetView->SetRiveTexture(RiveFile); + RiveWidgetView->RegisterArtboardInputs({}); } } diff --git a/Source/Rive/Public/Rive/RiveFile.h b/Source/Rive/Public/Rive/RiveFile.h index d69fba83..bb32bc1c 100644 --- a/Source/Rive/Public/Rive/RiveFile.h +++ b/Source/Rive/Public/Rive/RiveFile.h @@ -34,7 +34,8 @@ class RIVE_API URiveFile : public URiveTexture, public FTickableGameObject GENERATED_BODY() public: - DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnArtboardChanged, URiveFile*, RiveFile, URiveArtboard*, Artboard); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnArtboardChangedDynamic, URiveFile*, RiveFile, URiveArtboard*, Artboard); + DECLARE_MULTICAST_DELEGATE_TwoParams(FOnArtboardChanged, URiveFile* /* RiveFile */, URiveArtboard* /* Artboard */); DECLARE_MULTICAST_DELEGATE_TwoParams(FOnRiveFileInitialized, URiveFile*, bool /* bSuccess */ ); DECLARE_MULTICAST_DELEGATE_OneParam(FOnRiveFileEvent, URiveFile*); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FRiveReadyDelegate); @@ -162,7 +163,8 @@ class RIVE_API URiveFile : public URiveTexture, public FTickableGameObject public: UPROPERTY(BlueprintAssignable, Category = Rive) - FOnArtboardChanged OnArtboardChanged; + FOnArtboardChangedDynamic OnArtboardChanged; + FOnArtboardChanged OnArtboardChangedRaw; UPROPERTY() TArray RiveFileData; diff --git a/Source/Rive/Public/Slate/SRiveWidget.h b/Source/Rive/Public/Slate/SRiveWidget.h index 0d339201..0e15f362 100644 --- a/Source/Rive/Public/Slate/SRiveWidget.h +++ b/Source/Rive/Public/Slate/SRiveWidget.h @@ -27,6 +27,7 @@ class RIVE_API SRiveWidget : public SCompoundWidget #endif SLATE_END_ARGS() + ~SRiveWidget() override; /** * Implementation(s) */ @@ -48,4 +49,6 @@ class RIVE_API SRiveWidget : public SCompoundWidget /** Reference to Avalanche View */ TSharedPtr RiveWidgetView; + URiveFile* RiveFile = nullptr; + FDelegateHandle OnArtboardChangedHandle; }; diff --git a/Source/RiveEditor/Private/RiveFile_AssetDefinitionDefault.cpp b/Source/RiveEditor/Private/RiveFile_AssetDefinitionDefault.cpp index 29336e39..e70e92be 100644 --- a/Source/RiveEditor/Private/RiveFile_AssetDefinitionDefault.cpp +++ b/Source/RiveEditor/Private/RiveFile_AssetDefinitionDefault.cpp @@ -6,6 +6,7 @@ #include "IAssetTools.h" #include "RiveAssetToolkit.h" #include "Factories/RiveFileInstanceFactory.h" +#include "Factories/RiveWidgetFactory.h" #include "Logs/RiveEditorLog.h" #include "Rive/RiveFile.h" @@ -28,6 +29,19 @@ namespace MenuExtension_RiveFile }); } + void ExecuteCreateWidget(const FToolMenuContext& InContext) + { + const UContentBrowserAssetContextMenuContext* CBContext = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext); + + TArray RiveFiles = CBContext->LoadSelectedObjects(); + for (URiveFile* RiveFile : RiveFiles) + { + if (IsValid(RiveFile)) + { + FRiveWidgetFactory(RiveFile).Create(); + } + } + } static FDelayedAutoRegisterHelper DelayedAutoRegister(EDelayedRegisterRunPhase::EndOfEngineInit, []{ UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateLambda([]() @@ -47,6 +61,13 @@ namespace MenuExtension_RiveFile const FToolMenuExecuteAction UIAction = FToolMenuExecuteAction::CreateStatic(&ExecuteCreateInstance); InSection.AddMenuEntry("RiveFile_CreateInstance", Label, ToolTip, Icon, UIAction); } + { + const TAttribute Label = LOCTEXT("RiveFile_CreateWidget", "Create Rive Widget"); + const TAttribute ToolTip = LOCTEXT("RiveFile_CreateWidgetTooltip", "Creates a new Rive Widget asset using this file."); + const FSlateIcon Icon = FSlateIcon(FAppStyle::GetAppStyleSetName(), "ClassIcon.WidgetBlueprint"); + const FToolMenuExecuteAction UIAction = FToolMenuExecuteAction::CreateStatic(&ExecuteCreateWidget); + InSection.AddMenuEntry("RiveFile_CreateWidget", Label, ToolTip, Icon, UIAction); + } } })); })); diff --git a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp index 6da77710..1f7327c0 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp +++ b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.cpp @@ -3,6 +3,11 @@ #include "RiveRenderTargetD3D11.h" #if PLATFORM_WINDOWS +#include "CommonRenderResources.h" +#include "RenderGraphBuilder.h" +#include "ScreenRendering.h" +#include "Engine/Texture2DDynamic.h" + #include "RiveRendererD3D11.h" #include "ID3D11DynamicRHI.h" #include "Logs/RiveRendererLog.h" @@ -63,23 +68,24 @@ void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::CacheTextureTarget_Ren } } -rive::rcp UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::GetRenderTarget() const -{ - return CachedPLSRenderTargetD3D; -} - -#if WITH_RIVE -void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::EndFrame() const +void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::Render_RenderThread(FRHICommandListImmediate& RHICmdList, const TArray& RiveRenderCommands) { - FRiveRenderTarget::EndFrame(); - ResetBlendState(); + // First, we transition the texture to a RenderTextureView + FTextureRHIRef TargetTexture = RenderTarget->GetResource()->TextureRHI; + RHICmdList.Transition(FRHITransitionInfo(TargetTexture, ERHIAccess::Unknown, ERHIAccess::RTV)); + // Then we render Rive, ensuring the DX11 states are reset before and after the call + RHICmdList.EnqueueLambda([this, RiveRenderCommands](FRHICommandListImmediate& RHICmdList) + { + RiveRendererD3D11->ResetDXState(); + FRiveRenderTarget::Render_Internal(RiveRenderCommands); + RiveRendererD3D11->ResetDXState(); + }); + // Finally we transition the texture to a UAV Graphics + RHICmdList.Transition(FRHITransitionInfo(TargetTexture, ERHIAccess::RTV, ERHIAccess::UAVGraphics)); } -void UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::ResetBlendState() const +rive::rcp UE::Rive::Renderer::Private::FRiveRenderTargetD3D11::GetRenderTarget() const { - check(IsInRenderingThread()); - RiveRendererD3D11->ResetBlendState(); + return CachedPLSRenderTargetD3D; } - -#endif // WITH_RIVE #endif // PLATFORM_WINDOWS diff --git a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.h b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.h index a3f4ed72..4808a71d 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.h +++ b/Source/RiveRenderer/Private/Platform/RiveRenderTargetD3D11.h @@ -32,36 +32,26 @@ namespace UE::Rive::Renderer::Private FRiveRenderTargetD3D11(const TSharedRef& InRiveRenderer, const FName& InRiveName, UTexture2DDynamic* InRenderTarget); virtual ~FRiveRenderTargetD3D11() override; + //~ BEGIN : IRiveRenderTarget Interface - public: virtual void CacheTextureTarget_RenderThread(FRHICommandListImmediate& RHICmdList, const FTexture2DRHIRef& InRHIResource) override; - -#if WITH_RIVE - //~ END : IRiveRenderTarget Interface - + +#if WITH_RIVE //~ BEGIN : FRiveRenderTarget Interface - protected: // It Might need to be on rendering thread, render QUEUE is required + virtual void Render_RenderThread(FRHICommandListImmediate& RHICmdList, const TArray& RiveRenderCommands) override; virtual rive::rcp GetRenderTarget() const override; - virtual void EndFrame() const override; - //~ END : FRiveRenderTarget Interface /** * Attribute(s) */ - - private: - void ResetBlendState() const; - private: TSharedRef RiveRendererD3D11; - rive::rcp CachedPLSRenderTargetD3D; - #endif // WITH_RIVE }; } diff --git a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.cpp index 7f522b3a..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" @@ -28,84 +29,28 @@ void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::Initialize(rive: D3D11DeviceContext = nullptr; D3D11DevicePtr->GetImmediateContext(&D3D11DeviceContext); - if (SUCCEEDED(D3D11DevicePtr->QueryInterface(__uuidof(IDXGIDevice), (void**)&DXGIDevice))) + if (SUCCEEDED(D3D11DevicePtr->QueryInterface(__uuidof(IDXGIDevice), (void**)DXGIDevice.GetInitReference()))) { - IDXGIAdapter* DXGIAdapter; - if (SUCCEEDED(DXGIDevice->GetAdapter(&DXGIAdapter))) + TRefCountPtr DXGIAdapter; + if (SUCCEEDED(DXGIDevice->GetAdapter(DXGIAdapter.GetInitReference()))) { DXGI_ADAPTER_DESC AdapterDesc; DXGIAdapter->GetDesc(&AdapterDesc); OutContextOptions.isIntel = AdapterDesc.VendorId == 0x163C || AdapterDesc.VendorId == 0x8086 || AdapterDesc.VendorId == 0x8087; - - DXGIAdapter->Release(); } } - - // Init Blend State to fix the issue with Slate UI rendering - InitBlendState(); } #endif // WITH_RIVE -void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::ResetBlendState() -{ - if (!D3D11DeviceContext) - { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DeviceContext is nullptr while resetting of blend state")); - return; - } - - // Reference is here FSlateD3D11RenderingPolicy::DrawElements(), set the blend state back to whatever Unreal expects after Rive renderers - D3D11DeviceContext->OMSetBlendState( AlphaBlendState, nullptr, 0xFFFFFFFF ); - - // Reset the Raster state when finished, there are places that are making assumptions about the raster state - // that need to be fixed. - D3D11DeviceContext->RSSetState(NormalRasterState); -} - -void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::InitBlendState() +void UE::Rive::Renderer::Private::FRiveRendererD3D11GPUAdapter::ResetDXState() { - check(IsInRenderingThread()); - check(D3D11DevicePtr); - - D3D11_BLEND_DESC BlendDesc; - BlendDesc.AlphaToCoverageEnable = false; - BlendDesc.IndependentBlendEnable = false; - BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; - BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - - // dest.a = 1-(1-dest.a)*src.a + dest.a - BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA; - BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; - BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - - BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - BlendDesc.RenderTarget[0].BlendEnable = true; - - HRESULT Hr = D3D11DevicePtr->CreateBlendState( &BlendDesc, AlphaBlendState.GetInitReference() ); - if (FAILED(Hr)) + // Clear the internal state kept by UE and reset DX + FD3D11DynamicRHI* DynRHI = static_cast(D3D11RHI); + if (ensure(DynRHI)) { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DevicePtr->CreateBlendState( &BlendDesc, AlphaBlendState.GetInitReference() ) Failed")); - return; - } - - D3D11_RASTERIZER_DESC RasterDesc; - RasterDesc.CullMode = D3D11_CULL_NONE; - RasterDesc.FillMode = D3D11_FILL_SOLID; - RasterDesc.FrontCounterClockwise = true; - RasterDesc.DepthBias = 0; - RasterDesc.DepthBiasClamp = 0; - RasterDesc.SlopeScaledDepthBias = 0; - RasterDesc.ScissorEnable = false; - RasterDesc.MultisampleEnable = false; - RasterDesc.AntialiasedLineEnable = false; - - Hr = D3D11DevicePtr->CreateRasterizerState( &RasterDesc, NormalRasterState.GetInitReference() ); - if (FAILED(Hr)) - { - UE_LOG(LogRiveRenderer, Warning, TEXT("D3D11DevicePtr->CreateRasterizerState( &RasterDesc, NormalRasterState.GetInitReference() ) Failed")); + DynRHI->ClearState(); } } @@ -152,14 +97,13 @@ void UE::Rive::Renderer::Private::FRiveRendererD3D11::CreatePLSRenderer_RenderTh RIVE_DEBUG_FUNCTION_INDENT; } -void UE::Rive::Renderer::Private::FRiveRendererD3D11::ResetBlendState() const +void UE::Rive::Renderer::Private::FRiveRendererD3D11::ResetDXState() const { check(IsInRenderingThread()); check(D3D11GPUAdapter.IsValid()); FScopeLock Lock(&ThreadDataCS); - - D3D11GPUAdapter->ResetBlendState(); + D3D11GPUAdapter->ResetDXState(); } #endif // PLATFORM_WINDOWS diff --git a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h index 7b85d039..154c5473 100644 --- a/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h +++ b/Source/RiveRenderer/Private/Platform/RiveRendererD3D11.h @@ -35,23 +35,18 @@ namespace UE::Rive::Renderer::Private #if WITH_RIVE void Initialize(rive::pls::PLSRenderContextD3DImpl::ContextOptions& OutContextOptions); #endif // WITH_RIVE - void ResetBlendState(); + 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; - IDXGIDevice* DXGIDevice = nullptr; - - TRefCountPtr AlphaBlendState; - TRefCountPtr NormalRasterState; + TRefCountPtr DXGIDevice = nullptr; }; class RIVERENDERER_API FRiveRendererD3D11 : public FRiveRenderer @@ -59,21 +54,14 @@ 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 ResetBlendState() const; + + void ResetDXState() const; private: TUniquePtr D3D11GPUAdapter; diff --git a/Source/RiveRenderer/Private/RiveRenderTarget.cpp b/Source/RiveRenderer/Private/RiveRenderTarget.cpp index 2617e83e..79951b02 100644 --- a/Source/RiveRenderer/Private/RiveRenderTarget.cpp +++ b/Source/RiveRenderer/Private/RiveRenderTarget.cpp @@ -214,7 +214,7 @@ void UE::Rive::Renderer::Private::FRiveRenderTarget::Render_RenderThread(FRHICom { SCOPED_GPU_STAT(RHICmdList, Render); check(IsInRenderingThread()); - + Render_Internal(RiveRenderCommands); } 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)) {