You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
542 lines
19 KiB
C++
542 lines
19 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
Renderer.cpp: Renderer module implementation.
|
|
=============================================================================*/
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Misc/CoreMisc.h"
|
|
#include "Stats/Stats.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Async/TaskGraphInterfaces.h"
|
|
#include "EngineDefines.h"
|
|
#include "EngineGlobals.h"
|
|
#include "RenderingThread.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "SceneView.h"
|
|
#include "RenderTargetPool.h"
|
|
#include "PostProcess/SceneRenderTargets.h"
|
|
#include "VisualizeTexture.h"
|
|
#include "SceneCore.h"
|
|
#include "SceneHitProxyRendering.h"
|
|
#include "SceneRendering.h"
|
|
#include "BasePassRendering.h"
|
|
#include "MobileBasePassRendering.h"
|
|
#include "TranslucentRendering.h"
|
|
#include "RendererModule.h"
|
|
#include "GPUBenchmark.h"
|
|
#include "SystemSettings.h"
|
|
#include "VisualizeTexturePresent.h"
|
|
#include "MeshPassProcessor.inl"
|
|
#include "DebugViewModeRendering.h"
|
|
#include "EditorPrimitivesRendering.h"
|
|
#include "VisualizeTexturePresent.h"
|
|
#include "ScreenSpaceDenoise.h"
|
|
#include "VT/VirtualTextureSystem.h"
|
|
#include "PostProcess/TemporalAA.h"
|
|
#include "CanvasRender.h"
|
|
#include "RendererOnScreenNotification.h"
|
|
#include "Lumen/Lumen.h"
|
|
|
|
DEFINE_LOG_CATEGORY(LogRenderer);
|
|
|
|
IMPLEMENT_MODULE(FRendererModule, Renderer);
|
|
|
|
#if !IS_MONOLITHIC
|
|
// visual studio cannot find cross dll data for visualizers
|
|
// thus as a workaround for now, copy and paste this into every module
|
|
// where we need to visualize SystemSettings
|
|
FSystemSettings* GSystemSettingsForVisualizers = &GSystemSettings;
|
|
#endif
|
|
|
|
static int32 bFlushRenderTargetsOnWorldCleanup = 1;
|
|
FAutoConsoleVariableRef CVarFlushRenderTargetsOnWorldCleanup(TEXT("r.bFlushRenderTargetsOnWorldCleanup"), bFlushRenderTargetsOnWorldCleanup, TEXT(""));
|
|
|
|
|
|
|
|
void FRendererModule::StartupModule()
|
|
{
|
|
GScreenSpaceDenoiser = IScreenSpaceDenoiser::GetDefaultDenoiser();
|
|
|
|
FRendererOnScreenNotification::Get();
|
|
FVirtualTextureSystem::Initialize();
|
|
|
|
StopRenderingThreadDelegate = RegisterStopRenderingThreadDelegate(FStopRenderingThreadDelegate::CreateLambda([this]
|
|
{
|
|
ENQUEUE_RENDER_COMMAND(FSceneRendererCleanUp)(
|
|
[](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
FSceneRenderer::CleanUp(RHICmdList);
|
|
});
|
|
}));
|
|
}
|
|
|
|
void FRendererModule::ShutdownModule()
|
|
{
|
|
UnregisterStopRenderingThreadDelegate(StopRenderingThreadDelegate);
|
|
|
|
FVirtualTextureSystem::Shutdown();
|
|
FRendererOnScreenNotification::TearDown();
|
|
|
|
// Free up the memory of the default denoiser. Responsibility of the plugin to free up theirs.
|
|
delete IScreenSpaceDenoiser::GetDefaultDenoiser();
|
|
|
|
// Free up global resources in Lumen
|
|
Lumen::Shutdown();
|
|
|
|
void CleanupOcclusionSubmittedFence();
|
|
CleanupOcclusionSubmittedFence();
|
|
}
|
|
|
|
void FRendererModule::OnWorldCleanup(UWorld* World, bool bSessionEnded, bool bCleanupResources, bool bWorldChanged)
|
|
{
|
|
FSceneInterface* Scene = World->Scene;
|
|
ENQUEUE_RENDER_COMMAND(OnWorldCleanup)(
|
|
[Scene, bWorldChanged](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if(bFlushRenderTargetsOnWorldCleanup > 0)
|
|
{
|
|
GRenderTargetPool.FreeUnusedResources();
|
|
}
|
|
if(bWorldChanged && Scene)
|
|
{
|
|
Scene->OnWorldCleanup();
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
void FRendererModule::InitializeSystemTextures(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
GSystemTextures.InitializeTextures(RHICmdList, GMaxRHIFeatureLevel);
|
|
}
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FDrawTileMeshPassParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FInstanceCullingGlobalUniforms, InstanceCulling)
|
|
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCapture)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FDebugViewModePassUniformParameters, DebugViewMode)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FTranslucentBasePassUniformParameters, TranslucentBasePass)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FOpaqueBasePassUniformParameters, OpaqueBasePass)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FMobileBasePassUniformParameters, MobileBasePass)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
void FRendererModule::DrawTileMesh(FCanvasRenderContext& RenderContext, FMeshPassProcessorRenderState& DrawRenderState, const FSceneView& SceneView, FMeshBatch& Mesh, bool bIsHitTesting, const FHitProxyId& HitProxyId, bool bUse128bitRT)
|
|
{
|
|
if (!GUsingNullRHI)
|
|
{
|
|
// Create an FViewInfo so we can initialize its RHI resources
|
|
//@todo - reuse this view for multiple tiles, this is going to be slow for each tile
|
|
FViewInfo& View = *RenderContext.Alloc<FViewInfo>(&SceneView);
|
|
View.ViewRect = View.UnscaledViewRect;
|
|
|
|
const auto FeatureLevel = View.GetFeatureLevel();
|
|
const EShadingPath ShadingPath = FSceneInterface::GetShadingPath(FeatureLevel);
|
|
const FSceneViewFamily* ViewFamily = View.Family;
|
|
FScene* Scene = nullptr;
|
|
|
|
if (ViewFamily->Scene)
|
|
{
|
|
Scene = ViewFamily->Scene->GetRenderScene();
|
|
}
|
|
|
|
Mesh.MaterialRenderProxy->UpdateUniformExpressionCacheIfNeeded(FeatureLevel);
|
|
FMaterialRenderProxy::UpdateDeferredCachedUniformExpressions();
|
|
|
|
FSinglePrimitiveStructured& SinglePrimitiveStructured = GTilePrimitiveBuffer;
|
|
|
|
if (Mesh.VertexFactory->GetPrimitiveIdStreamIndex(FeatureLevel, EVertexInputStreamType::PositionOnly) >= 0)
|
|
{
|
|
FMeshBatchElement& MeshElement = Mesh.Elements[0];
|
|
|
|
checkf(Mesh.Elements.Num() == 1, TEXT("Only 1 batch element currently supported by DrawTileMesh"));
|
|
checkf(MeshElement.PrimitiveUniformBuffer == nullptr, TEXT("DrawTileMesh does not currently support an explicit primitive uniform buffer on vertex factories which manually fetch primitive data. Use PrimitiveUniformBufferResource instead."));
|
|
|
|
if (MeshElement.PrimitiveUniformBufferResource)
|
|
{
|
|
checkf(MeshElement.NumInstances == 1, TEXT("DrawTileMesh does not currently support instancing"));
|
|
// Force PrimitiveId to be 0 in the shader
|
|
MeshElement.PrimitiveIdMode = PrimID_ForceZero;
|
|
|
|
// Set the LightmapID to 0, since that's where our light map data resides for this primitive
|
|
FPrimitiveUniformShaderParameters PrimitiveParams = *(const FPrimitiveUniformShaderParameters*)MeshElement.PrimitiveUniformBufferResource->GetContents();
|
|
PrimitiveParams.LightmapDataIndex = 0;
|
|
PrimitiveParams.LightmapUVIndex = 0;
|
|
|
|
// Set up reference to the single-instance
|
|
PrimitiveParams.InstanceSceneDataOffset = 0;
|
|
PrimitiveParams.NumInstanceSceneDataEntries = 1;
|
|
PrimitiveParams.InstancePayloadDataOffset = INDEX_NONE;
|
|
PrimitiveParams.InstancePayloadDataStride = 0;
|
|
|
|
// Now we just need to fill out the first entry of primitive data in a buffer and bind it
|
|
SinglePrimitiveStructured.PrimitiveSceneData = FPrimitiveSceneShaderData(PrimitiveParams);
|
|
SinglePrimitiveStructured.ShaderPlatform = View.GetShaderPlatform();
|
|
|
|
// Also fill out correct single-primitive instance data, derived from the primitive.
|
|
SinglePrimitiveStructured.InstanceSceneData.BuildInternal
|
|
(
|
|
0 /* Primitive Id */,
|
|
0 /* Relative Instance Id */,
|
|
0 /* Payload Data Flags */,
|
|
INVALID_LAST_UPDATE_FRAME,
|
|
0 /* Custom Data Count */,
|
|
0.0f /* Random ID */,
|
|
PrimitiveParams.LocalToRelativeWorld,
|
|
PrimitiveParams.PreviousLocalToRelativeWorld
|
|
);
|
|
|
|
// TODO: Payload dummy?
|
|
|
|
// Set up the parameters for the LightmapSceneData from the given LCI data
|
|
FPrecomputedLightingUniformParameters LightmapParams;
|
|
GetPrecomputedLightingParameters(FeatureLevel, LightmapParams, Mesh.LCI);
|
|
SinglePrimitiveStructured.LightmapSceneData = FLightmapSceneShaderData(LightmapParams);
|
|
|
|
SinglePrimitiveStructured.UploadToGPU();
|
|
|
|
View.PrimitiveSceneDataOverrideSRV = SinglePrimitiveStructured.PrimitiveSceneDataBufferSRV;
|
|
View.InstanceSceneDataOverrideSRV = SinglePrimitiveStructured.InstanceSceneDataBufferSRV;
|
|
View.InstancePayloadDataOverrideSRV = SinglePrimitiveStructured.InstancePayloadDataBufferSRV;
|
|
View.LightmapSceneDataOverrideSRV = SinglePrimitiveStructured.LightmapSceneDataBufferSRV;
|
|
}
|
|
}
|
|
|
|
FRDGBuilder& GraphBuilder = RenderContext.GraphBuilder;
|
|
|
|
if (!FRDGSystemTextures::IsValid(GraphBuilder))
|
|
{
|
|
FRDGSystemTextures::Create(GraphBuilder);
|
|
}
|
|
|
|
View.InitRHIResources();
|
|
View.ForwardLightingResources.SetUniformBuffer(CreateDummyForwardLightUniformBuffer(GraphBuilder));
|
|
|
|
TUniformBufferRef<FReflectionCaptureShaderData> EmptyReflectionCaptureUniformBuffer;
|
|
|
|
{
|
|
FReflectionCaptureShaderData EmptyData;
|
|
EmptyReflectionCaptureUniformBuffer = TUniformBufferRef<FReflectionCaptureShaderData>::CreateUniformBufferImmediate(EmptyData, UniformBuffer_SingleFrame);
|
|
}
|
|
|
|
//get the blend mode of the material
|
|
const FMaterial& MeshMaterial = Mesh.MaterialRenderProxy->GetIncompleteMaterialWithFallback(FeatureLevel);
|
|
const EBlendMode MaterialBlendMode = MeshMaterial.GetBlendMode();
|
|
|
|
const bool bUseVirtualTexturing = UseVirtualTexturing(FeatureLevel);
|
|
// Materials sampling VTs need FVirtualTextureSystem to be updated before being rendered :
|
|
if (bUseVirtualTexturing && !MeshMaterial.GetUniformVirtualTextureExpressions().IsEmpty())
|
|
{
|
|
RDG_GPU_STAT_SCOPE(GraphBuilder, VirtualTextureUpdate);
|
|
FVirtualTextureSystem::Get().AllocateResources(GraphBuilder, FeatureLevel);
|
|
FVirtualTextureSystem::Get().CallPendingCallbacks();
|
|
FVirtualTextureSystem::Get().Update(GraphBuilder, FeatureLevel, Scene);
|
|
}
|
|
|
|
RDG_EVENT_SCOPE(GraphBuilder, "DrawTileMesh");
|
|
|
|
auto* PassParameters = GraphBuilder.AllocParameters<FDrawTileMeshPassParameters>();
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(RenderContext.GetRenderTarget(), ERenderTargetLoadAction::ELoad);
|
|
PassParameters->View = View.GetShaderParameters();
|
|
PassParameters->ReflectionCapture = EmptyReflectionCaptureUniformBuffer;
|
|
PassParameters->InstanceCulling = FInstanceCullingContext::CreateDummyInstanceCullingUniformBuffer(GraphBuilder);
|
|
|
|
// handle translucent material blend modes, not relevant in MaterialTexCoordScalesAnalysis since it outputs the scales.
|
|
if (ViewFamily->GetDebugViewShaderMode() == DVSM_OutputMaterialTextureScales)
|
|
{
|
|
#if WITH_DEBUG_VIEW_MODES
|
|
// make sure we are doing opaque drawing
|
|
DrawRenderState.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
// is this path used on mobile?
|
|
if (ShadingPath == EShadingPath::Deferred)
|
|
{
|
|
PassParameters->DebugViewMode = CreateDebugViewModePassUniformBuffer(GraphBuilder, View, nullptr);
|
|
|
|
RenderContext.AddPass(RDG_EVENT_NAME("OutputMaterialTextureScales"), PassParameters,
|
|
[Scene, &View, &Mesh](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList, [&](FMeshPassDrawListContext* InDrawListContext)
|
|
{
|
|
FDebugViewModeMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
View.GetFeatureLevel(),
|
|
&View,
|
|
false,
|
|
InDrawListContext);
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
}
|
|
#endif // WITH_DEBUG_VIEW_MODES
|
|
}
|
|
else if (IsTranslucentBlendMode(MaterialBlendMode))
|
|
{
|
|
if (ShadingPath == EShadingPath::Deferred)
|
|
{
|
|
PassParameters->TranslucentBasePass = CreateTranslucentBasePassUniformBuffer(GraphBuilder, Scene, View);
|
|
|
|
RenderContext.AddPass(RDG_EVENT_NAME("TranslucentDeferred"), PassParameters,
|
|
[Scene, &View, &Mesh, DrawRenderState, bUse128bitRT](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
|
|
{
|
|
FBasePassMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
View.GetFeatureLevel(),
|
|
&View,
|
|
DrawRenderState,
|
|
DynamicMeshPassContext,
|
|
bUse128bitRT ? FBasePassMeshProcessor::EFlags::bRequires128bitRT : FBasePassMeshProcessor::EFlags::None,
|
|
ETranslucencyPass::TPT_AllTranslucency);
|
|
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
}
|
|
else // Mobile
|
|
{
|
|
PassParameters->MobileBasePass = CreateMobileBasePassUniformBuffer(GraphBuilder, View, EMobileBasePass::Translucent, EMobileSceneTextureSetupMode::None);
|
|
|
|
RenderContext.AddPass(RDG_EVENT_NAME("TranslucentMobile"), PassParameters,
|
|
[Scene, &View, DrawRenderState, &Mesh](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
|
|
{
|
|
FMobileBasePassMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
View.GetFeatureLevel(),
|
|
&View,
|
|
DrawRenderState,
|
|
DynamicMeshPassContext,
|
|
FMobileBasePassMeshProcessor::EFlags::None,
|
|
ETranslucencyPass::TPT_AllTranslucency);
|
|
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
// handle opaque materials
|
|
else
|
|
{
|
|
// make sure we are doing opaque drawing
|
|
DrawRenderState.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
// draw the mesh
|
|
if (bIsHitTesting)
|
|
{
|
|
ensureMsgf(HitProxyId == Mesh.BatchHitProxyId, TEXT("Only Mesh.BatchHitProxyId is used for hit testing."));
|
|
|
|
#if WITH_EDITOR
|
|
RenderContext.AddPass(RDG_EVENT_NAME("HitTesting"), PassParameters,
|
|
[Scene, &View, DrawRenderState, &Mesh](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
|
|
{
|
|
FHitProxyMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
&View,
|
|
false,
|
|
DrawRenderState,
|
|
DynamicMeshPassContext);
|
|
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (ShadingPath == EShadingPath::Deferred)
|
|
{
|
|
PassParameters->OpaqueBasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View);
|
|
|
|
RenderContext.AddPass(RDG_EVENT_NAME("OpaqueDeferred"), PassParameters,
|
|
[Scene, &View, DrawRenderState, &Mesh, bUse128bitRT](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList,
|
|
[&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
|
|
{
|
|
FBasePassMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
View.GetFeatureLevel(),
|
|
&View,
|
|
DrawRenderState,
|
|
DynamicMeshPassContext,
|
|
bUse128bitRT ? FBasePassMeshProcessor::EFlags::bRequires128bitRT : FBasePassMeshProcessor::EFlags::None);
|
|
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
}
|
|
else // Mobile
|
|
{
|
|
PassParameters->MobileBasePass = CreateMobileBasePassUniformBuffer(GraphBuilder, View, EMobileBasePass::Opaque, EMobileSceneTextureSetupMode::None);
|
|
|
|
RenderContext.AddPass(RDG_EVENT_NAME("OpaqueMobile"), PassParameters,
|
|
[Scene, &View, DrawRenderState, &Mesh](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
DrawDynamicMeshPass(View, RHICmdList, [&](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
|
|
{
|
|
FMobileBasePassMeshProcessor PassMeshProcessor(
|
|
Scene,
|
|
View.GetFeatureLevel(),
|
|
&View,
|
|
DrawRenderState,
|
|
DynamicMeshPassContext,
|
|
FMobileBasePassMeshProcessor::EFlags::CanReceiveCSM);
|
|
|
|
const uint64 DefaultBatchElementMask = ~0ull;
|
|
PassMeshProcessor.AddMeshBatch(Mesh, DefaultBatchElementMask, nullptr);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FRendererModule::DebugLogOnCrash()
|
|
{
|
|
GVisualizeTexture.DebugLogOnCrash();
|
|
|
|
GEngine->Exec(NULL, TEXT("rhi.DumpMemory"), *GLog);
|
|
|
|
// execute on main thread
|
|
{
|
|
struct FTest
|
|
{
|
|
void Thread()
|
|
{
|
|
GEngine->Exec(NULL, TEXT("Mem FromReport"), *GLog);
|
|
}
|
|
} Test;
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.DumpDataAfterCrash"),
|
|
STAT_FSimpleDelegateGraphTask_DumpDataAfterCrash,
|
|
STATGROUP_TaskGraphTasks);
|
|
|
|
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
|
|
FSimpleDelegateGraphTask::FDelegate::CreateRaw(&Test, &FTest::Thread),
|
|
GET_STATID(STAT_FSimpleDelegateGraphTask_DumpDataAfterCrash), nullptr, ENamedThreads::GameThread
|
|
);
|
|
}
|
|
}
|
|
|
|
void FRendererModule::GPUBenchmark(FSynthBenchmarkResults& InOut, float WorkScale)
|
|
{
|
|
check(IsInGameThread());
|
|
|
|
FSceneViewInitOptions ViewInitOptions;
|
|
FIntRect ViewRect(0, 0, 1, 1);
|
|
|
|
FBox LevelBox(FVector(-WORLD_MAX), FVector(+WORLD_MAX));
|
|
ViewInitOptions.SetViewRectangle(ViewRect);
|
|
|
|
// Initialize Projection Matrix and ViewMatrix since FSceneView initialization is doing some math on them.
|
|
// Otherwise it trips NaN checks.
|
|
const FVector ViewPoint = LevelBox.GetCenter();
|
|
ViewInitOptions.ViewOrigin = FVector(ViewPoint.X, ViewPoint.Y, 0.0f);
|
|
ViewInitOptions.ViewRotationMatrix = FMatrix(
|
|
FPlane(1, 0, 0, 0),
|
|
FPlane(0, -1, 0, 0),
|
|
FPlane(0, 0, -1, 0),
|
|
FPlane(0, 0, 0, 1));
|
|
|
|
const float ZOffset = WORLD_MAX;
|
|
ViewInitOptions.ProjectionMatrix = FReversedZOrthoMatrix(
|
|
LevelBox.GetSize().X / 2.f,
|
|
LevelBox.GetSize().Y / 2.f,
|
|
0.5f / ZOffset,
|
|
ZOffset
|
|
);
|
|
|
|
FSceneView DummyView(ViewInitOptions);
|
|
FlushRenderingCommands();
|
|
FSynthBenchmarkResults* InOutPtr = &InOut;
|
|
ENQUEUE_RENDER_COMMAND(RendererGPUBenchmarkCommand)(
|
|
[DummyView, WorkScale, InOutPtr](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
RendererGPUBenchmark(RHICmdList, *InOutPtr, DummyView, WorkScale);
|
|
});
|
|
FlushRenderingCommands();
|
|
}
|
|
|
|
static void VisualizeTextureExec( const TCHAR* Cmd, FOutputDevice &Ar )
|
|
{
|
|
check(IsInGameThread());
|
|
FlushRenderingCommands();
|
|
GVisualizeTexture.ParseCommands(Cmd, Ar);
|
|
}
|
|
|
|
extern void NaniteStatsFilterExec(const TCHAR* Cmd, FOutputDevice& Ar);
|
|
|
|
static bool RendererExec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
|
|
{
|
|
#if SUPPORTS_VISUALIZE_TEXTURE
|
|
if (FParse::Command(&Cmd, TEXT("VisualizeTexture")) || FParse::Command(&Cmd, TEXT("Vis")))
|
|
{
|
|
VisualizeTextureExec(Cmd, Ar);
|
|
return true;
|
|
}
|
|
#endif //SUPPORTS_VISUALIZE_TEXTURE
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
if (FParse::Command(&Cmd, TEXT("DumpUnbuiltLightInteractions")))
|
|
{
|
|
InWorld->Scene->DumpUnbuiltLightInteractions(Ar);
|
|
return true;
|
|
}
|
|
else if (FParse::Command(&Cmd, TEXT("NaniteStats")))
|
|
{
|
|
NaniteStatsFilterExec(Cmd, Ar);
|
|
return true;
|
|
}
|
|
else if(FParse::Command(&Cmd, TEXT("r.RHI.Name")))
|
|
{
|
|
Ar.Logf( TEXT( "Running on the %s RHI" ), GDynamicRHI
|
|
? (GDynamicRHI->GetName() ? GDynamicRHI->GetName() : TEXT("<NULL Name>"))
|
|
: TEXT("<NULL DynamicRHI>"));
|
|
return true;
|
|
}
|
|
else if (FParse::Command(&Cmd, TEXT("r.ResetRenderTargetsExtent")))
|
|
{
|
|
ResetSceneTextureExtentHistory();
|
|
Ar.Logf(TEXT("Scene texture extent history reset. Next scene render will reallocate textures at the requested size."));
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
ICustomCulling* GCustomCullingImpl = nullptr;
|
|
|
|
void FRendererModule::RegisterCustomCullingImpl(ICustomCulling* impl)
|
|
{
|
|
check(GCustomCullingImpl == nullptr);
|
|
GCustomCullingImpl = impl;
|
|
}
|
|
|
|
void FRendererModule::UnregisterCustomCullingImpl(ICustomCulling* impl)
|
|
{
|
|
check(GCustomCullingImpl == impl);
|
|
GCustomCullingImpl = nullptr;
|
|
}
|
|
|
|
FStaticSelfRegisteringExec RendererExecRegistration(RendererExec);
|
|
|
|
void FRendererModule::ExecVisualizeTextureCmd( const FString& Cmd )
|
|
{
|
|
// @todo: Find a nicer way to call this
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
VisualizeTextureExec(*Cmd, *GLog);
|
|
#endif
|
|
}
|