You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3055495 on 2016/07/19 by Marc.Olano Allow Noise material node on mobile No reason to exclude mobile, except for Fast Gradient Noise, which uses 3D textures. Allow this node on ES2 for all of the other noise functions. #jira UE-33345 Change 3055602 on 2016/07/19 by Luke.Thatcher Fix crash bug in D3D11 RHI when selecting adapters. - Array of adapter descriptors will get out of sync with the adapter index if any adapter is skipped (e.g. the Microsoft Basic Render Device). #jira UE-33236 Change 3055890 on 2016/07/19 by Daniel.Wright Improved the assert in LoadModuleChecked so we won't have to check the log to see which module it was Change 3055891 on 2016/07/19 by Daniel.Wright Fixed Global Distance Field not dirtying previous object position on UpdateTransform - left behind a phantom shadow on teleports * This will effectively double partial distiance field update costs until clipping of the update regions is implemented Change 3055892 on 2016/07/19 by Daniel.Wright Higher poly light source shapes drawn into reflection captures Change 3055893 on 2016/07/19 by Daniel.Wright More info to 'Incompatible surface format' GNM assert Change 3055904 on 2016/07/19 by Daniel.Wright Reflection environment normalization improvements * Indirect specular from reflection captures is now mixed with indirect diffuse from lightmaps based on roughness, such that a mirror surface will have no mixing. Reflection captures now match other reflection methods like SSR and planar reflections much more closely. * When a stationary skylight is present, Reflection captures are now normalized as if the initial skylight will always be present, giving consistent results with static skylight reflections. The skylight and reflection captures with sky removed used to be normalized separately, compacting the relative brightness between the sky and scene. * Added r.ReflectionEnvironmentLightmapMixing for debugging lightmap mixing issues. This toggle was previously not possible due to prenormalizing the capture data. * The standard deferred reflection path (r.DoTiledReflections 0) can no longer match the results of the compute path or base pass reflections, as it would require MRT to accumulate the average brightness * Removed unused r.DiffuseFromCaptures * Cost of reflection environment on PS4 increased from 1.52ms -> 1.75ms with this change, but decreased back to 1.58ms by reducing tile size to 8x8 Change 3055905 on 2016/07/19 by Daniel.Wright Workaround for RTDF shadows not working on PS4 - manual clear of ObjectIndirectArguments instead of RHICmdList.ClearUAV Change 3059486 on 2016/07/21 by Nick.Penwarden Testing #uecritical Change 3060558 on 2016/07/21 by Daniel.Wright Fixed skylight with specified cubemap being black Change 3061999 on 2016/07/22 by Marcus.Wassmer Disable old AMD driver hacks for DX11. QA has already tested with them off and given thumbs up. Change 3062241 on 2016/07/22 by Daniel.Wright Fixed bug in RHISupportsSeparateMSAAAndResolveTextures that was preventing MSAA for any non-Vulkan platforms Change 3062244 on 2016/07/22 by Daniel.Wright Discard old prenormalized reflection environment data on load Change 3062283 on 2016/07/22 by Daniel.Wright MSAA support for the forward renderer * AntiAliasing method is chosen in Rendering project settings, DefaultSettings category * Deferred passes like shadow projection, fogging and decals are only computed per-pixel and can introduce aliasing * Added Rendering project setting VertexFoggingForOpaque, which makes height fog cheaper and work properly with MSAA * The AntiAliasing method in PostProcessSettings has been removed, this may affect existing content * Added r.MSAACount which defaults to 4 * Integrated wide custom resolve filter from Oculus renderer, controlled by r.WideCustomResolve * GBuffer targets are no longer allocated when using the forward renderer * Decal blend modes that write to the GBuffer fall back to SceneColor emissive only Change 3062666 on 2016/07/23 by Uriel.Doyon Added legend to streaming accuracy viewmodes Added a new helper class FRenderTargetTemp to be reused in different canvas rendering. Exposed the pass through pixel shader so that it can be reused. #review-3058986 @marcus.wassmer Change 3063023 on 2016/07/25 by Luke.Thatcher Fix "RecompileShaders Changed" when using Cook On The Fly. #jira UE-33573 Change 3063078 on 2016/07/25 by Ben.Woodhouse Add -emitdrawevents command line option to emit draw events by default. This is useful when capturing with Renderdoc Change 3063315 on 2016/07/25 by Ben.Woodhouse Fix div 0 in motion blur. This caused artifacts in some fairly common cases #jira UE-32331 Change 3063897 on 2016/07/25 by Uriel.Doyon Fixed missing qualifier on interpolants Change 3064559 on 2016/07/26 by Ben.Woodhouse Fix for cooker crash with BC6H textures (XB1, but may affect other platforms). Also fixes corruption issue with texture slices not being a multiple of 4 pixels (expanding as necessary), courtesy of Stu McKenna at the Coalition Tested fix on xbox, PC and PS4, using QAGame #jira UE-28592 Change 3064896 on 2016/07/26 by Ben.Woodhouse Fix compile errors on PS4 (the variable "sample" was conflicting with a keyword, causing compile errors). Also making encoding consistent on new shaders (ansi rather than UTF16) Change 3064913 on 2016/07/26 by Ben.Marsh Fix spelling of "Editor, Tools, Monolithics & DDC" node in Dev-Rendering build settings. Change 3065326 on 2016/07/26 by Uriel.Doyon Fixed UnbuiltInstanceBoundsList not being reset correctly, creating broken rendered primitives. #jira UE-32585 Change 3065541 on 2016/07/26 by Daniel.Wright Materials with a GBuffer SceneTexture lookup will fail to compile with forward shading Change 3065543 on 2016/07/26 by Daniel.Wright Restored DetailMode changes causing a FGlobalComponentRecreateRenderStateContext - accidental removal from cl 2969413 Change 3065545 on 2016/07/26 by Daniel.Wright Added material property bNormalCurvatureToRoughness, which can slightly reduce aliasing. Tweakable impact with r.NormalCurvatureToRoughnessScale. Fixed reflection capture feedback with base pass reflections Change 3066783 on 2016/07/27 by Daniel.Wright Moved PreShadowCacheDepthZ out of FSceneRenderTargets and into FScene, which fixes issues with cached preshadows and multiple scenes, including HighResScreenShot Disabled GMinScreenRadiusForShadowCaster on per-object shadows, which fixes popping when trying to increase shadow resolution from the defaults (r.Shadow.TexelsPerPixel 3) Change 3066794 on 2016/07/27 by Daniel.Wright Fixed crash rendering planar reflections due to NULL PostProcessSettings Change 3067412 on 2016/07/27 by Daniel.Wright Fix for OpenGL4 with uint interpolator Change 3068470 on 2016/07/28 by Daniel.Wright Fixed crash rendering translucency with translucent shadows which were determined to be invisible Change 3069046 on 2016/07/28 by Daniel.Wright Handle null Family in SetupAntiAliasingMethod Change 3069059 on 2016/07/28 by Daniel.Wright Added r.ReflectionEnvironmentBeginMixingRoughness (.1) and r.ReflectionEnvironmentEndMixingRoughness (.3), which can be used to tweak the lightmap mixing heuristc, or revert to previous behavior (mixing even on a mirror surface) Change 3069391 on 2016/07/28 by Daniel.Wright Fixed AverageBrightness being applied to reflections in gamma space in the mobile base pass, causing ES2 reflections to be overbright Change 3070369 on 2016/07/29 by Daniel.Wright r.ReflectionEnvironmentBeginMixingRoughness and r.ReflectionEnvironmentEndMixingRoughness set to 0 can be used to achieve old non-roughness based lightmap mixing Change 3070370 on 2016/07/29 by Daniel.Wright Bumped reflection capture DDC version to get rid of legacy prenormalized data Change 3070680 on 2016/07/29 by Marcus.Wassmer Fix slate ensure that is most likely a timing issue exposed by rendering. #ue-33902 Change 3070811 on 2016/07/29 by Marcus.Wassmer Fix ProjectLauncher errors when loading old versions #ue-33939 Change 3070971 on 2016/07/29 by Uriel.Doyon Updated ListTextures outputs to fix cooked VS non cooked differences and also to put enphasis on disk VS memory Change 3071452 on 2016/07/31 by Uriel.Doyon Updated the legend description for the (texture streaming) primitive distance accuracy view mode [CL 3072803 by Marcus Wassmer in Main branch]
1209 lines
49 KiB
C++
1209 lines
49 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DistanceFieldSurfaceCacheLighting.cpp
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "UniformBuffer.h"
|
|
#include "ShaderParameters.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
#include "DistanceFieldSurfaceCacheLighting.h"
|
|
#include "DistanceFieldGlobalIllumination.h"
|
|
#include "RHICommandList.h"
|
|
#include "SceneUtils.h"
|
|
|
|
float GAOMaxObjectBoundingRadius = 50000;
|
|
FAutoConsoleVariableRef CVarAOMaxObjectBoundingRadius(
|
|
TEXT("r.AOMaxObjectBoundingRadius"),
|
|
GAOMaxObjectBoundingRadius,
|
|
TEXT("Objects larger than this will not contribute to AO calculations, to improve performance."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GAOLogObjectBufferReallocation = 0;
|
|
FAutoConsoleVariableRef CVarAOLogObjectBufferReallocation(
|
|
TEXT("r.AOLogObjectBufferReallocation"),
|
|
GAOLogObjectBufferReallocation,
|
|
TEXT(""),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
// Must match equivalent shader defines
|
|
int32 FDistanceFieldObjectBuffers::ObjectDataStride = 16;
|
|
int32 FDistanceFieldCulledObjectBuffers::ObjectDataStride = 16;
|
|
int32 FDistanceFieldCulledObjectBuffers::ObjectBoxBoundsStride = 5;
|
|
|
|
// In float4's. Must match corresponding usf definition
|
|
int32 UploadObjectDataStride = 1 + FDistanceFieldObjectBuffers::ObjectDataStride;
|
|
|
|
class FDistanceFieldUploadDataResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer UploadData;
|
|
|
|
FDistanceFieldUploadDataResource()
|
|
{
|
|
UploadData.Format = PF_A32B32G32R32F;
|
|
UploadData.Stride = UploadObjectDataStride;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
UploadData.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
UploadData.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FDistanceFieldUploadDataResource> GDistanceFieldUploadData;
|
|
|
|
class FDistanceFieldUploadIndicesResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer UploadIndices;
|
|
|
|
FDistanceFieldUploadIndicesResource()
|
|
{
|
|
UploadIndices.Format = PF_R32_UINT;
|
|
UploadIndices.Stride = 1;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
UploadIndices.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
UploadIndices.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FDistanceFieldUploadIndicesResource> GDistanceFieldUploadIndices;
|
|
|
|
class FDistanceFieldRemoveIndicesResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer RemoveIndices;
|
|
|
|
FDistanceFieldRemoveIndicesResource()
|
|
{
|
|
RemoveIndices.Format = PF_R32G32B32A32_UINT;
|
|
RemoveIndices.Stride = 1;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
RemoveIndices.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
RemoveIndices.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FDistanceFieldRemoveIndicesResource> GDistanceFieldRemoveIndices;
|
|
|
|
const uint32 UpdateObjectsGroupSize = 64;
|
|
|
|
class FUploadObjectsToBufferCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FUploadObjectsToBufferCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
}
|
|
|
|
FUploadObjectsToBufferCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
NumUploadOperations.Bind(Initializer.ParameterMap, TEXT("NumUploadOperations"));
|
|
UploadOperationIndices.Bind(Initializer.ParameterMap, TEXT("UploadOperationIndices"));
|
|
UploadOperationData.Bind(Initializer.ParameterMap, TEXT("UploadOperationData"));
|
|
ObjectBufferParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
FUploadObjectsToBufferCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FScene* Scene, uint32 NumUploadOperationsValue, FShaderResourceViewRHIParamRef InUploadOperationIndices, FShaderResourceViewRHIParamRef InUploadOperationData)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumUploadOperations, NumUploadOperationsValue);
|
|
|
|
SetSRVParameter(RHICmdList, ShaderRHI, UploadOperationIndices, InUploadOperationIndices);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, UploadOperationData, InUploadOperationData);
|
|
|
|
|
|
ObjectBufferParameters.Set(RHICmdList, ShaderRHI, *(Scene->DistanceFieldSceneData.ObjectBuffers), Scene->DistanceFieldSceneData.NumObjectsInBuffer, true);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, const FScene* Scene)
|
|
{
|
|
ObjectBufferParameters.UnsetParameters(RHICmdList, GetComputeShader(), *(Scene->DistanceFieldSceneData.ObjectBuffers), true);
|
|
|
|
const FDistanceFieldObjectBuffers& ObjectBuffers = *(Scene->DistanceFieldSceneData.ObjectBuffers);
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = ObjectBuffers.Bounds.UAV;
|
|
OutUAVs[1] = ObjectBuffers.Data.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << NumUploadOperations;
|
|
Ar << UploadOperationIndices;
|
|
Ar << UploadOperationData;
|
|
Ar << ObjectBufferParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FShaderParameter NumUploadOperations;
|
|
FShaderResourceParameter UploadOperationIndices;
|
|
FShaderResourceParameter UploadOperationData;
|
|
FDistanceFieldObjectBufferParameters ObjectBufferParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FUploadObjectsToBufferCS,TEXT("DistanceFieldSurfaceCacheLightingCompute"),TEXT("UploadObjectsToBufferCS"),SF_Compute);
|
|
|
|
class FCopyObjectBufferCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopyObjectBufferCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
}
|
|
|
|
FCopyObjectBufferCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
CopyObjectBounds.Bind(Initializer.ParameterMap, TEXT("CopyObjectBounds"));
|
|
CopyObjectData.Bind(Initializer.ParameterMap, TEXT("CopyObjectData"));
|
|
ObjectBufferParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
FCopyObjectBufferCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, FDistanceFieldObjectBuffers& ObjectBuffersSource, FDistanceFieldObjectBuffers& ObjectBuffersDest, int32 NumObjectsValue)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = ObjectBuffersDest.Bounds.UAV;
|
|
OutUAVs[1] = ObjectBuffersDest.Data.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
|
|
CopyObjectBounds.SetBuffer(RHICmdList, ShaderRHI, ObjectBuffersDest.Bounds);
|
|
CopyObjectData.SetBuffer(RHICmdList, ShaderRHI, ObjectBuffersDest.Data);
|
|
|
|
ObjectBufferParameters.Set(RHICmdList, ShaderRHI, ObjectBuffersSource, NumObjectsValue);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, FDistanceFieldObjectBuffers& ObjectBuffersDest)
|
|
{
|
|
ObjectBufferParameters.UnsetParameters(RHICmdList, GetComputeShader(), ObjectBuffersDest);
|
|
CopyObjectBounds.UnsetUAV(RHICmdList, GetComputeShader());
|
|
CopyObjectData.UnsetUAV(RHICmdList, GetComputeShader());
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = ObjectBuffersDest.Bounds.UAV;
|
|
OutUAVs[1] = ObjectBuffersDest.Data.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << CopyObjectBounds;
|
|
Ar << CopyObjectData;
|
|
Ar << ObjectBufferParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FRWShaderParameter CopyObjectBounds;
|
|
FRWShaderParameter CopyObjectData;
|
|
FDistanceFieldObjectBufferParameters ObjectBufferParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCopyObjectBufferCS,TEXT("DistanceFieldSurfaceCacheLightingCompute"),TEXT("CopyObjectBufferCS"),SF_Compute);
|
|
|
|
class FCopySurfelBufferCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopySurfelBufferCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
}
|
|
|
|
FCopySurfelBufferCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
CopyInterpolatedVertexData.Bind(Initializer.ParameterMap, TEXT("CopyInterpolatedVertexData"));
|
|
CopySurfelData.Bind(Initializer.ParameterMap, TEXT("CopySurfelData"));
|
|
SurfelBufferParameters.Bind(Initializer.ParameterMap);
|
|
NumSurfels.Bind(Initializer.ParameterMap, TEXT("NumSurfels"));
|
|
}
|
|
|
|
FCopySurfelBufferCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSurfelBuffers& SurfelBuffersSource, const FInstancedSurfelBuffers& InstancedSurfelBuffersSource, FSurfelBuffers& SurfelBuffersDest, int32 NumSurfelsValue)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = SurfelBuffersDest.InterpolatedVertexData.UAV;
|
|
OutUAVs[1] = SurfelBuffersDest.Surfels.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
|
|
CopyInterpolatedVertexData.SetBuffer(RHICmdList, ShaderRHI, SurfelBuffersDest.InterpolatedVertexData);
|
|
CopySurfelData.SetBuffer(RHICmdList, ShaderRHI, SurfelBuffersDest.Surfels);
|
|
SurfelBufferParameters.Set(RHICmdList, ShaderRHI, SurfelBuffersSource, InstancedSurfelBuffersSource);
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumSurfels, NumSurfelsValue);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, FSurfelBuffers& SurfelBuffersDest)
|
|
{
|
|
SurfelBufferParameters.UnsetParameters(RHICmdList, GetComputeShader());
|
|
CopyInterpolatedVertexData.UnsetUAV(RHICmdList, GetComputeShader());
|
|
CopySurfelData.UnsetUAV(RHICmdList, GetComputeShader());
|
|
|
|
FUnorderedAccessViewRHIParamRef OutUAVs[2];
|
|
OutUAVs[0] = SurfelBuffersDest.InterpolatedVertexData.UAV;
|
|
OutUAVs[1] = SurfelBuffersDest.Surfels.UAV;
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, OutUAVs, ARRAY_COUNT(OutUAVs));
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << CopyInterpolatedVertexData;
|
|
Ar << CopySurfelData;
|
|
Ar << SurfelBufferParameters;
|
|
Ar << NumSurfels;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FRWShaderParameter CopyInterpolatedVertexData;
|
|
FRWShaderParameter CopySurfelData;
|
|
FSurfelBufferParameters SurfelBufferParameters;
|
|
FShaderParameter NumSurfels;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCopySurfelBufferCS,TEXT("SurfelTree"),TEXT("CopySurfelBufferCS"),SF_Compute);
|
|
|
|
|
|
class FCopyVPLFluxBufferCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopyVPLFluxBufferCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
}
|
|
|
|
FCopyVPLFluxBufferCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
CopyVPLFlux.Bind(Initializer.ParameterMap, TEXT("CopyVPLFlux"));
|
|
SurfelBufferParameters.Bind(Initializer.ParameterMap);
|
|
NumSurfels.Bind(Initializer.ParameterMap, TEXT("NumSurfels"));
|
|
}
|
|
|
|
FCopyVPLFluxBufferCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSurfelBuffers& SurfelBuffersSource, const FInstancedSurfelBuffers& InstancedSurfelBuffersSource, FInstancedSurfelBuffers& InstancedSurfelBuffersDest, int32 NumSurfelsValue)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EComputeToCompute, InstancedSurfelBuffersDest.VPLFlux.UAV);
|
|
CopyVPLFlux.SetBuffer(RHICmdList, ShaderRHI, InstancedSurfelBuffersDest.VPLFlux);
|
|
SurfelBufferParameters.Set(RHICmdList, ShaderRHI, SurfelBuffersSource, InstancedSurfelBuffersSource);
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumSurfels, NumSurfelsValue);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, FInstancedSurfelBuffers& InstancedSurfelBuffersDest)
|
|
{
|
|
SurfelBufferParameters.UnsetParameters(RHICmdList, GetComputeShader());
|
|
CopyVPLFlux.UnsetUAV(RHICmdList, GetComputeShader());
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToCompute, InstancedSurfelBuffersDest.VPLFlux.UAV);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << CopyVPLFlux;
|
|
Ar << SurfelBufferParameters;
|
|
Ar << NumSurfels;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FRWShaderParameter CopyVPLFlux;
|
|
FSurfelBufferParameters SurfelBufferParameters;
|
|
FShaderParameter NumSurfels;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCopyVPLFluxBufferCS,TEXT("SurfelTree"),TEXT("CopyVPLFluxBufferCS"),SF_Compute);
|
|
|
|
template<bool bRemoveFromSameBuffer>
|
|
class TRemoveObjectsFromBufferCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(TRemoveObjectsFromBufferCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldAO(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("UPDATEOBJECTS_THREADGROUP_SIZE"), UpdateObjectsGroupSize);
|
|
OutEnvironment.SetDefine(TEXT("REMOVE_FROM_SAME_BUFFER"), bRemoveFromSameBuffer);
|
|
}
|
|
|
|
TRemoveObjectsFromBufferCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
NumRemoveOperations.Bind(Initializer.ParameterMap, TEXT("NumRemoveOperations"));
|
|
RemoveOperationIndices.Bind(Initializer.ParameterMap, TEXT("RemoveOperationIndices"));
|
|
ObjectBufferParameters.Bind(Initializer.ParameterMap);
|
|
ObjectBounds2.Bind(Initializer.ParameterMap, TEXT("ObjectBounds2"));
|
|
ObjectData2.Bind(Initializer.ParameterMap, TEXT("ObjectData2"));
|
|
}
|
|
|
|
TRemoveObjectsFromBufferCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FScene* Scene,
|
|
uint32 NumRemoveOperationsValue,
|
|
FShaderResourceViewRHIParamRef InRemoveOperationIndices,
|
|
FShaderResourceViewRHIParamRef InObjectBounds2,
|
|
FShaderResourceViewRHIParamRef InObjectData2)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumRemoveOperations, NumRemoveOperationsValue);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, RemoveOperationIndices, InRemoveOperationIndices);
|
|
ObjectBufferParameters.Set(RHICmdList, ShaderRHI, *(Scene->DistanceFieldSceneData.ObjectBuffers), Scene->DistanceFieldSceneData.NumObjectsInBuffer, true);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ObjectBounds2, InObjectBounds2);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ObjectData2, InObjectData2);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList, const FScene* Scene)
|
|
{
|
|
ObjectBufferParameters.UnsetParameters(RHICmdList, GetComputeShader(), *(Scene->DistanceFieldSceneData.ObjectBuffers), true);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << NumRemoveOperations;
|
|
Ar << RemoveOperationIndices;
|
|
Ar << ObjectBufferParameters;
|
|
Ar << ObjectBounds2;
|
|
Ar << ObjectData2;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FShaderParameter NumRemoveOperations;
|
|
FShaderResourceParameter RemoveOperationIndices;
|
|
FDistanceFieldObjectBufferParameters ObjectBufferParameters;
|
|
FShaderResourceParameter ObjectBounds2;
|
|
FShaderResourceParameter ObjectData2;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(template<>,TRemoveObjectsFromBufferCS<true>,TEXT("DistanceFieldSurfaceCacheLightingCompute"),TEXT("RemoveObjectsFromBufferCS"),SF_Compute);
|
|
IMPLEMENT_SHADER_TYPE(template<>,TRemoveObjectsFromBufferCS<false>,TEXT("DistanceFieldSurfaceCacheLightingCompute"),TEXT("RemoveObjectsFromBufferCS"),SF_Compute);
|
|
|
|
void FSurfelBufferAllocator::RemovePrimitive(const FPrimitiveSceneInfo* Primitive)
|
|
{
|
|
FPrimitiveSurfelAllocation Allocation;
|
|
|
|
if (Allocations.RemoveAndCopyValue(Primitive, Allocation))
|
|
{
|
|
bool bMergedWithExisting = false;
|
|
|
|
FPrimitiveSurfelFreeEntry FreeEntry(Allocation.Offset, Allocation.GetTotalNumSurfels());
|
|
|
|
// Note: only does one merge
|
|
//@todo - keep free list sorted then can binary search
|
|
for (int32 FreeIndex = 0; FreeIndex < FreeList.Num(); FreeIndex++)
|
|
{
|
|
if (FreeList[FreeIndex].Offset == FreeEntry.Offset + FreeEntry.NumSurfels)
|
|
{
|
|
FreeList[FreeIndex].Offset = FreeEntry.Offset;
|
|
FreeList[FreeIndex].NumSurfels += FreeEntry.NumSurfels;
|
|
bMergedWithExisting = true;
|
|
break;
|
|
}
|
|
else if (FreeList[FreeIndex].Offset + FreeList[FreeIndex].NumSurfels == FreeEntry.Offset)
|
|
{
|
|
FreeList[FreeIndex].NumSurfels += FreeEntry.NumSurfels;
|
|
bMergedWithExisting = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bMergedWithExisting)
|
|
{
|
|
FreeList.Add(FreeEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSurfelBufferAllocator::AddPrimitive(const FPrimitiveSceneInfo* PrimitiveSceneInfo, int32 PrimitiveLOD0Surfels, int32 PrimitiveNumSurfels, int32 NumInstances)
|
|
{
|
|
int32 BestFreeAllocationIndex = -1;
|
|
|
|
for (int32 FreeIndex = 0; FreeIndex < FreeList.Num(); FreeIndex++)
|
|
{
|
|
const FPrimitiveSurfelFreeEntry& CurrentFreeEntry = FreeList[FreeIndex];
|
|
|
|
if (CurrentFreeEntry.NumSurfels >= PrimitiveNumSurfels * NumInstances
|
|
&& (BestFreeAllocationIndex == -1
|
|
|| CurrentFreeEntry.NumSurfels < FreeList[BestFreeAllocationIndex].NumSurfels))
|
|
{
|
|
BestFreeAllocationIndex = FreeIndex;
|
|
}
|
|
}
|
|
|
|
if (BestFreeAllocationIndex != -1)
|
|
{
|
|
FPrimitiveSurfelFreeEntry FreeEntry = FreeList[BestFreeAllocationIndex];
|
|
|
|
if (FreeEntry.NumSurfels == PrimitiveNumSurfels * NumInstances)
|
|
{
|
|
// Existing allocation matches exactly, remove it from the free list
|
|
FreeList.RemoveAtSwap(BestFreeAllocationIndex);
|
|
}
|
|
else
|
|
{
|
|
// Replace with the remaining free range
|
|
FreeList[BestFreeAllocationIndex] = FPrimitiveSurfelFreeEntry(FreeEntry.Offset + PrimitiveNumSurfels * NumInstances, FreeEntry.NumSurfels - PrimitiveNumSurfels * NumInstances);
|
|
}
|
|
|
|
Allocations.Add(PrimitiveSceneInfo, FPrimitiveSurfelAllocation(FreeEntry.Offset, PrimitiveLOD0Surfels, PrimitiveNumSurfels, NumInstances));
|
|
}
|
|
else
|
|
{
|
|
// Add a new allocation to the end of the buffer
|
|
Allocations.Add(PrimitiveSceneInfo, FPrimitiveSurfelAllocation(NumSurfelsInBuffer, PrimitiveLOD0Surfels, PrimitiveNumSurfels, NumInstances));
|
|
NumSurfelsInBuffer += PrimitiveNumSurfels * NumInstances;
|
|
}
|
|
}
|
|
|
|
void UpdateGlobalDistanceFieldObjectRemoves(FRHICommandListImmediate& RHICmdList, FScene* Scene)
|
|
{
|
|
FDistanceFieldSceneData& DistanceFieldSceneData = Scene->DistanceFieldSceneData;
|
|
|
|
TArray<FIntRect> RemoveObjectIndices;
|
|
FDistanceFieldObjectBuffers* TemporaryCopySourceBuffers = NULL;
|
|
|
|
if (DistanceFieldSceneData.PendingRemoveOperations.Num() > 0)
|
|
{
|
|
TArray<int32, SceneRenderingAllocator> PendingRemoveOperations;
|
|
|
|
for (int32 RemoveIndex = 0; RemoveIndex < DistanceFieldSceneData.PendingRemoveOperations.Num(); RemoveIndex++)
|
|
{
|
|
// Can't dereference the primitive here, it has already been deleted
|
|
const FPrimitiveSceneInfo* Primitive = DistanceFieldSceneData.PendingRemoveOperations[RemoveIndex].Primitive;
|
|
DistanceFieldSceneData.SurfelAllocations.RemovePrimitive(Primitive);
|
|
DistanceFieldSceneData.InstancedSurfelAllocations.RemovePrimitive(Primitive);
|
|
const TArray<int32, TInlineAllocator<1>>& DistanceFieldInstanceIndices = DistanceFieldSceneData.PendingRemoveOperations[RemoveIndex].DistanceFieldInstanceIndices;
|
|
|
|
for (int32 RemoveInstanceIndex = 0; RemoveInstanceIndex < DistanceFieldInstanceIndices.Num(); RemoveInstanceIndex++)
|
|
{
|
|
const int32 InstanceIndex = DistanceFieldInstanceIndices[RemoveInstanceIndex];
|
|
|
|
// InstanceIndex will be -1 with zero scale meshes
|
|
if (InstanceIndex >= 0)
|
|
{
|
|
DistanceFieldSceneData.PrimitiveModifiedBounds.Add(DistanceFieldSceneData.PrimitiveInstanceMapping[InstanceIndex].BoundingSphere);
|
|
PendingRemoveOperations.Add(InstanceIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
DistanceFieldSceneData.PendingRemoveOperations.Reset();
|
|
|
|
if (PendingRemoveOperations.Num() > 0)
|
|
{
|
|
check(DistanceFieldSceneData.NumObjectsInBuffer >= PendingRemoveOperations.Num());
|
|
|
|
// Sort from smallest to largest
|
|
PendingRemoveOperations.Sort();
|
|
|
|
// We have multiple remove requests enqueued in PendingRemoveOperations, can only use the RemoveAtSwap version when there won't be collisions
|
|
const bool bUseRemoveAtSwap = PendingRemoveOperations.Last() < DistanceFieldSceneData.NumObjectsInBuffer - PendingRemoveOperations.Num();
|
|
|
|
if (bUseRemoveAtSwap)
|
|
{
|
|
// Remove everything in parallel in the same buffer with a RemoveAtSwap algorithm
|
|
for (int32 RemovePrimitiveIndex = 0; RemovePrimitiveIndex < PendingRemoveOperations.Num(); RemovePrimitiveIndex++)
|
|
{
|
|
DistanceFieldSceneData.NumObjectsInBuffer--;
|
|
const int32 RemoveIndex = PendingRemoveOperations[RemovePrimitiveIndex];
|
|
const int32 MoveFromIndex = DistanceFieldSceneData.NumObjectsInBuffer;
|
|
|
|
check(RemoveIndex != MoveFromIndex);
|
|
// Queue a compute shader move
|
|
RemoveObjectIndices.Add(FIntRect(RemoveIndex, MoveFromIndex, 0, 0));
|
|
|
|
// Fixup indices of the primitive that is being moved
|
|
FPrimitiveAndInstance& PrimitiveAndInstanceBeingMoved = DistanceFieldSceneData.PrimitiveInstanceMapping[MoveFromIndex];
|
|
check(PrimitiveAndInstanceBeingMoved.Primitive && PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices.Num() > 0);
|
|
PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices[PrimitiveAndInstanceBeingMoved.InstanceIndex] = RemoveIndex;
|
|
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping.RemoveAtSwap(RemoveIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const double StartTime = FPlatformTime::Seconds();
|
|
|
|
// Have to copy the object data to allow parallel removing
|
|
TemporaryCopySourceBuffers = DistanceFieldSceneData.ObjectBuffers;
|
|
DistanceFieldSceneData.ObjectBuffers = new FDistanceFieldObjectBuffers();
|
|
DistanceFieldSceneData.ObjectBuffers->MaxObjects = TemporaryCopySourceBuffers->MaxObjects;
|
|
DistanceFieldSceneData.ObjectBuffers->Initialize();
|
|
|
|
TArray<FPrimitiveAndInstance> OriginalPrimitiveInstanceMapping = DistanceFieldSceneData.PrimitiveInstanceMapping;
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping.Reset();
|
|
|
|
const int32 NumDestObjects = DistanceFieldSceneData.NumObjectsInBuffer - PendingRemoveOperations.Num();
|
|
int32 SourceIndex = 0;
|
|
int32 NextPendingRemoveIndex = 0;
|
|
|
|
for (int32 DestinationIndex = 0; DestinationIndex < NumDestObjects; DestinationIndex++)
|
|
{
|
|
while (NextPendingRemoveIndex < PendingRemoveOperations.Num()
|
|
&& PendingRemoveOperations[NextPendingRemoveIndex] == SourceIndex)
|
|
{
|
|
NextPendingRemoveIndex++;
|
|
SourceIndex++;
|
|
}
|
|
|
|
// Queue a compute shader move
|
|
RemoveObjectIndices.Add(FIntRect(DestinationIndex, SourceIndex, 0, 0));
|
|
|
|
// Fixup indices of the primitive that is being moved
|
|
FPrimitiveAndInstance& PrimitiveAndInstanceBeingMoved = OriginalPrimitiveInstanceMapping[SourceIndex];
|
|
check(PrimitiveAndInstanceBeingMoved.Primitive && PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices.Num() > 0);
|
|
PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices[PrimitiveAndInstanceBeingMoved.InstanceIndex] = DestinationIndex;
|
|
|
|
check(DistanceFieldSceneData.PrimitiveInstanceMapping.Num() == DestinationIndex);
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping.Add(PrimitiveAndInstanceBeingMoved);
|
|
|
|
SourceIndex++;
|
|
}
|
|
|
|
DistanceFieldSceneData.NumObjectsInBuffer = NumDestObjects;
|
|
|
|
if (GAOLogObjectBufferReallocation)
|
|
{
|
|
const float ElapsedTime = (float)(FPlatformTime::Seconds() - StartTime);
|
|
UE_LOG(LogDistanceField,Warning,TEXT("Global object buffer realloc %.3fs"), ElapsedTime);
|
|
}
|
|
|
|
/*
|
|
// Have to remove one at a time while any entries to remove are at the end of the buffer
|
|
DistanceFieldSceneData.NumObjectsInBuffer--;
|
|
const int32 RemoveIndex = DistanceFieldSceneData.PendingRemoveOperations[ParallelConflictIndex];
|
|
const int32 MoveFromIndex = DistanceFieldSceneData.NumObjectsInBuffer;
|
|
|
|
if (RemoveIndex != MoveFromIndex)
|
|
{
|
|
// Queue a compute shader move
|
|
RemoveObjectIndices.Add(FIntRect(RemoveIndex, MoveFromIndex, 0, 0));
|
|
|
|
// Fixup indices of the primitive that is being moved
|
|
FPrimitiveAndInstance& PrimitiveAndInstanceBeingMoved = DistanceFieldSceneData.PrimitiveInstanceMapping[MoveFromIndex];
|
|
check(PrimitiveAndInstanceBeingMoved.Primitive && PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices.Num() > 0);
|
|
PrimitiveAndInstanceBeingMoved.Primitive->DistanceFieldInstanceIndices[PrimitiveAndInstanceBeingMoved.InstanceIndex] = RemoveIndex;
|
|
}
|
|
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping.RemoveAtSwap(RemoveIndex);
|
|
DistanceFieldSceneData.PendingRemoveOperations.RemoveAtSwap(ParallelConflictIndex);
|
|
*/
|
|
}
|
|
|
|
PendingRemoveOperations.Reset();
|
|
|
|
if (RemoveObjectIndices.Num() > 0)
|
|
{
|
|
if (RemoveObjectIndices.Num() > GDistanceFieldRemoveIndices.RemoveIndices.MaxElements)
|
|
{
|
|
GDistanceFieldRemoveIndices.RemoveIndices.MaxElements = RemoveObjectIndices.Num() * 5 / 4;
|
|
GDistanceFieldRemoveIndices.RemoveIndices.Release();
|
|
GDistanceFieldRemoveIndices.RemoveIndices.Initialize();
|
|
}
|
|
|
|
void* LockedBuffer = RHILockVertexBuffer(GDistanceFieldRemoveIndices.RemoveIndices.Buffer, 0, GDistanceFieldRemoveIndices.RemoveIndices.Buffer->GetSize(), RLM_WriteOnly);
|
|
const uint32 MemcpySize = RemoveObjectIndices.GetTypeSize() * RemoveObjectIndices.Num();
|
|
check(GDistanceFieldRemoveIndices.RemoveIndices.Buffer->GetSize() >= MemcpySize);
|
|
FPlatformMemory::Memcpy(LockedBuffer, RemoveObjectIndices.GetData(), MemcpySize);
|
|
RHIUnlockVertexBuffer(GDistanceFieldRemoveIndices.RemoveIndices.Buffer);
|
|
|
|
if (bUseRemoveAtSwap)
|
|
{
|
|
check(!TemporaryCopySourceBuffers);
|
|
TShaderMapRef<TRemoveObjectsFromBufferCS<true> > ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, Scene, RemoveObjectIndices.Num(), GDistanceFieldRemoveIndices.RemoveIndices.BufferSRV, NULL, NULL);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(RemoveObjectIndices.Num(), UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, Scene);
|
|
}
|
|
else
|
|
{
|
|
check(TemporaryCopySourceBuffers);
|
|
TShaderMapRef<TRemoveObjectsFromBufferCS<false> > ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, Scene, RemoveObjectIndices.Num(), GDistanceFieldRemoveIndices.RemoveIndices.BufferSRV, TemporaryCopySourceBuffers->Bounds.SRV, TemporaryCopySourceBuffers->Data.SRV);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(RemoveObjectIndices.Num(), UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, Scene);
|
|
|
|
TemporaryCopySourceBuffers->Release();
|
|
delete TemporaryCopySourceBuffers;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Gathers the information needed to represent a single object's distance field and appends it to the upload buffers. */
|
|
void ProcessPrimitiveUpdate(
|
|
bool bIsAddOperation,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
FSceneRenderer& SceneRenderer,
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo,
|
|
int32 OriginalNumObjects,
|
|
FVector InvTextureDim,
|
|
bool bPrepareForDistanceFieldGI,
|
|
TArray<FMatrix>& ObjectLocalToWorldTransforms,
|
|
TArray<uint32>& UploadObjectIndices,
|
|
TArray<FVector4>& UploadObjectData)
|
|
{
|
|
FScene* Scene = SceneRenderer.Scene;
|
|
FDistanceFieldSceneData& DistanceFieldSceneData = Scene->DistanceFieldSceneData;
|
|
|
|
ObjectLocalToWorldTransforms.Reset();
|
|
|
|
FBox LocalVolumeBounds;
|
|
FIntVector BlockMin;
|
|
FIntVector BlockSize;
|
|
bool bBuiltAsIfTwoSided;
|
|
bool bMeshWasPlane;
|
|
PrimitiveSceneInfo->Proxy->GetDistancefieldAtlasData(LocalVolumeBounds, BlockMin, BlockSize, bBuiltAsIfTwoSided, bMeshWasPlane, ObjectLocalToWorldTransforms);
|
|
|
|
if (BlockMin.X >= 0
|
|
&& BlockMin.Y >= 0
|
|
&& BlockMin.Z >= 0
|
|
&& ObjectLocalToWorldTransforms.Num() > 0)
|
|
{
|
|
const float BoundingRadius = PrimitiveSceneInfo->Proxy->GetBounds().SphereRadius;
|
|
|
|
// Proxy bounds are only useful if single instance
|
|
if (ObjectLocalToWorldTransforms.Num() > 1 || BoundingRadius < GAOMaxObjectBoundingRadius)
|
|
{
|
|
FPrimitiveSurfelAllocation Allocation;
|
|
FPrimitiveSurfelAllocation InstancedAllocation;
|
|
|
|
if (bPrepareForDistanceFieldGI)
|
|
{
|
|
const FPrimitiveSurfelAllocation* AllocationPtr = Scene->DistanceFieldSceneData.SurfelAllocations.FindAllocation(PrimitiveSceneInfo);
|
|
const FPrimitiveSurfelAllocation* InstancedAllocationPtr = Scene->DistanceFieldSceneData.InstancedSurfelAllocations.FindAllocation(PrimitiveSceneInfo);
|
|
|
|
if (AllocationPtr)
|
|
{
|
|
checkSlow(InstancedAllocationPtr && InstancedAllocationPtr->NumInstances == ObjectLocalToWorldTransforms.Num());
|
|
Allocation = *AllocationPtr;
|
|
InstancedAllocation = *InstancedAllocationPtr;
|
|
|
|
extern void GenerateSurfelRepresentation(FRHICommandListImmediate& RHICmdList, FSceneRenderer& Renderer, FViewInfo& View, FPrimitiveSceneInfo* PrimitiveSceneInfo, const FMatrix& Instance0Transform, FPrimitiveSurfelAllocation& Allocation);
|
|
// @todo - support surfel generation without a view
|
|
GenerateSurfelRepresentation(RHICmdList, SceneRenderer, SceneRenderer.Views[0], PrimitiveSceneInfo, ObjectLocalToWorldTransforms[0], Allocation);
|
|
|
|
if (Allocation.NumSurfels == 0)
|
|
{
|
|
InstancedAllocation.NumSurfels = 0;
|
|
InstancedAllocation.NumInstances = 0;
|
|
InstancedAllocation.NumLOD0 = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bIsAddOperation)
|
|
{
|
|
PrimitiveSceneInfo->DistanceFieldInstanceIndices.Empty(ObjectLocalToWorldTransforms.Num());
|
|
PrimitiveSceneInfo->DistanceFieldInstanceIndices.AddZeroed(ObjectLocalToWorldTransforms.Num());
|
|
}
|
|
|
|
for (int32 TransformIndex = 0; TransformIndex < ObjectLocalToWorldTransforms.Num(); TransformIndex++)
|
|
{
|
|
FMatrix LocalToWorld = ObjectLocalToWorldTransforms[TransformIndex];
|
|
const float MaxScale = LocalToWorld.GetMaximumAxisScale();
|
|
|
|
// Skip degenerate primitives
|
|
if (MaxScale > 0)
|
|
{
|
|
uint32 UploadIndex;
|
|
|
|
if (bIsAddOperation)
|
|
{
|
|
UploadIndex = OriginalNumObjects + UploadObjectIndices.Num();
|
|
DistanceFieldSceneData.NumObjectsInBuffer++;
|
|
}
|
|
else
|
|
{
|
|
UploadIndex = PrimitiveSceneInfo->DistanceFieldInstanceIndices[TransformIndex];
|
|
}
|
|
|
|
UploadObjectIndices.Add(UploadIndex);
|
|
|
|
if (bMeshWasPlane)
|
|
{
|
|
FVector LocalScales = LocalToWorld.GetScaleVector();
|
|
FVector AbsLocalScales(FMath::Abs(LocalScales.X), FMath::Abs(LocalScales.Y), FMath::Abs(LocalScales.Z));
|
|
float MidScale = FMath::Min(AbsLocalScales.X, AbsLocalScales.Y);
|
|
float ScaleAdjust = FMath::Sign(LocalScales.Z) * MidScale / AbsLocalScales.Z;
|
|
// The mesh was determined to be a plane flat in Z during the build process, so we can change the Z scale
|
|
// Helps in cases with modular ground pieces with scales of (10, 10, 1) and some triangles just above Z=0
|
|
LocalToWorld.SetAxis(2, LocalToWorld.GetScaledAxis(EAxis::Z) * ScaleAdjust);
|
|
}
|
|
|
|
const FMatrix VolumeToWorld = FScaleMatrix(LocalVolumeBounds.GetExtent())
|
|
* FTranslationMatrix(LocalVolumeBounds.GetCenter())
|
|
* LocalToWorld;
|
|
|
|
const FVector4 ObjectBoundingSphere(VolumeToWorld.GetOrigin(), VolumeToWorld.GetScaleVector().Size());
|
|
|
|
UploadObjectData.Add(ObjectBoundingSphere);
|
|
|
|
const float MaxExtent = LocalVolumeBounds.GetExtent().GetMax();
|
|
|
|
const FMatrix UniformScaleVolumeToWorld = FScaleMatrix(MaxExtent)
|
|
* FTranslationMatrix(LocalVolumeBounds.GetCenter())
|
|
* LocalToWorld;
|
|
|
|
const FVector InvBlockSize(1.0f / BlockSize.X, 1.0f / BlockSize.Y, 1.0f / BlockSize.Z);
|
|
|
|
//float3 VolumeUV = (VolumePosition / LocalPositionExtent * .5f * UVScale + .5f * UVScale + UVAdd;
|
|
const FVector LocalPositionExtent = LocalVolumeBounds.GetExtent() / FVector(MaxExtent);
|
|
const FVector UVScale = FVector(BlockSize) * InvTextureDim;
|
|
const float VolumeScale = UniformScaleVolumeToWorld.GetMaximumAxisScale();
|
|
|
|
const FMatrix WorldToVolume = UniformScaleVolumeToWorld.Inverse();
|
|
// WorldToVolume
|
|
UploadObjectData.Add(*(FVector4*)&WorldToVolume.M[0]);
|
|
UploadObjectData.Add(*(FVector4*)&WorldToVolume.M[1]);
|
|
UploadObjectData.Add(*(FVector4*)&WorldToVolume.M[2]);
|
|
UploadObjectData.Add(*(FVector4*)&WorldToVolume.M[3]);
|
|
|
|
// Clamp to texel center by subtracting a half texel in the [-1,1] position space
|
|
// LocalPositionExtent
|
|
UploadObjectData.Add(FVector4(LocalPositionExtent - InvBlockSize, LocalVolumeBounds.Min.X));
|
|
|
|
// UVScale, VolumeScale and sign gives bGeneratedAsTwoSided
|
|
const float WSign = bBuiltAsIfTwoSided ? -1 : 1;
|
|
UploadObjectData.Add(FVector4(FVector(BlockSize) * InvTextureDim * .5f / LocalPositionExtent, WSign * VolumeScale));
|
|
|
|
// UVAdd
|
|
UploadObjectData.Add(FVector4(FVector(BlockMin) * InvTextureDim + .5f * UVScale, LocalVolumeBounds.Min.Y));
|
|
|
|
// Box bounds
|
|
UploadObjectData.Add(FVector4(LocalVolumeBounds.Max, LocalVolumeBounds.Min.Z));
|
|
|
|
UploadObjectData.Add(*(FVector4*)&UniformScaleVolumeToWorld.M[0]);
|
|
UploadObjectData.Add(*(FVector4*)&UniformScaleVolumeToWorld.M[1]);
|
|
UploadObjectData.Add(*(FVector4*)&UniformScaleVolumeToWorld.M[2]);
|
|
|
|
UploadObjectData.Add(*(FVector4*)&LocalToWorld.M[0]);
|
|
UploadObjectData.Add(*(FVector4*)&LocalToWorld.M[1]);
|
|
UploadObjectData.Add(*(FVector4*)&LocalToWorld.M[2]);
|
|
UploadObjectData.Add(*(FVector4*)&LocalToWorld.M[3]);
|
|
|
|
UploadObjectData.Add(FVector4(Allocation.Offset, Allocation.NumLOD0, Allocation.NumSurfels, InstancedAllocation.Offset + InstancedAllocation.NumSurfels * TransformIndex));
|
|
|
|
checkSlow(UploadObjectData.Num() % UploadObjectDataStride == 0);
|
|
|
|
if (bIsAddOperation)
|
|
{
|
|
const int32 AddIndex = UploadIndex;
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping.Add(FPrimitiveAndInstance(ObjectBoundingSphere, PrimitiveSceneInfo, TransformIndex));
|
|
PrimitiveSceneInfo->DistanceFieldInstanceIndices[TransformIndex] = AddIndex;
|
|
}
|
|
else
|
|
{
|
|
// InstanceIndex will be -1 with zero scale meshes
|
|
const int32 InstanceIndex = PrimitiveSceneInfo->DistanceFieldInstanceIndices[TransformIndex];
|
|
if (InstanceIndex >= 0)
|
|
{
|
|
// For an update transform we have to dirty the previous bounds and the new bounds, in case of large movement (teleport)
|
|
DistanceFieldSceneData.PrimitiveModifiedBounds.Add(DistanceFieldSceneData.PrimitiveInstanceMapping[InstanceIndex].BoundingSphere);
|
|
DistanceFieldSceneData.PrimitiveInstanceMapping[InstanceIndex].BoundingSphere = ObjectBoundingSphere;
|
|
}
|
|
}
|
|
|
|
DistanceFieldSceneData.PrimitiveModifiedBounds.Add(ObjectBoundingSphere);
|
|
|
|
extern int32 GAOLogGlobalDistanceFieldModifiedPrimitives;
|
|
|
|
if (GAOLogGlobalDistanceFieldModifiedPrimitives)
|
|
{
|
|
UE_LOG(LogDistanceField,Warning,TEXT("Global Distance Field primitive %s %s %s bounding radius %.1f"), (bIsAddOperation ? TEXT("add") : TEXT("update")), *PrimitiveSceneInfo->Proxy->GetOwnerName().ToString(), *PrimitiveSceneInfo->Proxy->GetResourceName().ToString(), BoundingRadius);
|
|
}
|
|
}
|
|
else if (bIsAddOperation)
|
|
{
|
|
// Set to -1 for zero scale meshes
|
|
PrimitiveSceneInfo->DistanceFieldInstanceIndices[TransformIndex] = -1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogDistanceField,Log,TEXT("Primitive %s %s excluded due to bounding radius %f"), *PrimitiveSceneInfo->Proxy->GetOwnerName().ToString(), *PrimitiveSceneInfo->Proxy->GetResourceName().ToString(), BoundingRadius);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::UpdateGlobalDistanceFieldObjectBuffers(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
FDistanceFieldSceneData& DistanceFieldSceneData = Scene->DistanceFieldSceneData;
|
|
|
|
if (GDistanceFieldVolumeTextureAtlas.VolumeTextureRHI
|
|
&& (DistanceFieldSceneData.HasPendingOperations() || DistanceFieldSceneData.AtlasGeneration != GDistanceFieldVolumeTextureAtlas.GetGeneration()))
|
|
{
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_UpdateObjectData);
|
|
SCOPED_DRAW_EVENT(RHICmdList, UpdateSceneObjectData);
|
|
|
|
if (!DistanceFieldSceneData.ObjectBuffers)
|
|
{
|
|
DistanceFieldSceneData.ObjectBuffers = new FDistanceFieldObjectBuffers();
|
|
}
|
|
|
|
if (!DistanceFieldSceneData.SurfelBuffers)
|
|
{
|
|
DistanceFieldSceneData.SurfelBuffers = new FSurfelBuffers();
|
|
}
|
|
|
|
if (!DistanceFieldSceneData.InstancedSurfelBuffers)
|
|
{
|
|
DistanceFieldSceneData.InstancedSurfelBuffers = new FInstancedSurfelBuffers();
|
|
}
|
|
|
|
if (DistanceFieldSceneData.AtlasGeneration != GDistanceFieldVolumeTextureAtlas.GetGeneration())
|
|
{
|
|
DistanceFieldSceneData.AtlasGeneration = GDistanceFieldVolumeTextureAtlas.GetGeneration();
|
|
|
|
for (int32 PrimitiveInstanceIndex = 0; PrimitiveInstanceIndex < DistanceFieldSceneData.PrimitiveInstanceMapping.Num(); PrimitiveInstanceIndex++)
|
|
{
|
|
FPrimitiveAndInstance& PrimitiveInstance = DistanceFieldSceneData.PrimitiveInstanceMapping[PrimitiveInstanceIndex];
|
|
|
|
// Queue an update of all primitives, since the atlas layout has changed
|
|
if (PrimitiveInstance.InstanceIndex == 0
|
|
&& !DistanceFieldSceneData.HasPendingRemovePrimitive(PrimitiveInstance.Primitive)
|
|
&& !DistanceFieldSceneData.PendingAddOperations.Contains(PrimitiveInstance.Primitive)
|
|
&& !DistanceFieldSceneData.PendingUpdateOperations.Contains(PrimitiveInstance.Primitive))
|
|
{
|
|
DistanceFieldSceneData.PendingUpdateOperations.Add(PrimitiveInstance.Primitive);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process removes before adds, as the adds will overwrite primitive allocation info in DistanceFieldSceneData.SurfelAllocations
|
|
UpdateGlobalDistanceFieldObjectRemoves(RHICmdList, Scene);
|
|
|
|
extern int32 GVPLMeshGlobalIllumination;
|
|
TArray<uint32> UploadObjectIndices;
|
|
TArray<FVector4> UploadObjectData;
|
|
const bool bPrepareForDistanceFieldGI = GVPLMeshGlobalIllumination && SupportsDistanceFieldGI(Scene->GetFeatureLevel(), Scene->GetShaderPlatform());
|
|
|
|
if (DistanceFieldSceneData.PendingAddOperations.Num() > 0 || DistanceFieldSceneData.PendingUpdateOperations.Num() > 0)
|
|
{
|
|
TArray<FMatrix> ObjectLocalToWorldTransforms;
|
|
|
|
const int32 NumUploadOperations = DistanceFieldSceneData.PendingAddOperations.Num() + DistanceFieldSceneData.PendingUpdateOperations.Num();
|
|
UploadObjectData.Empty(NumUploadOperations * UploadObjectDataStride);
|
|
UploadObjectIndices.Empty(NumUploadOperations);
|
|
|
|
const int32 NumTexelsOneDimX = GDistanceFieldVolumeTextureAtlas.GetSizeX();
|
|
const int32 NumTexelsOneDimY = GDistanceFieldVolumeTextureAtlas.GetSizeY();
|
|
const int32 NumTexelsOneDimZ = GDistanceFieldVolumeTextureAtlas.GetSizeZ();
|
|
const FVector InvTextureDim(1.0f / NumTexelsOneDimX, 1.0f / NumTexelsOneDimY, 1.0f / NumTexelsOneDimZ);
|
|
|
|
int32 OriginalNumObjects = DistanceFieldSceneData.NumObjectsInBuffer;
|
|
int32 OriginalNumSurfels = DistanceFieldSceneData.SurfelAllocations.GetNumSurfelsInBuffer();
|
|
int32 OriginalNumInstancedSurfels = DistanceFieldSceneData.InstancedSurfelAllocations.GetNumSurfelsInBuffer();
|
|
|
|
if (bPrepareForDistanceFieldGI)
|
|
{
|
|
for (int32 UploadPrimitiveIndex = 0; UploadPrimitiveIndex < DistanceFieldSceneData.PendingAddOperations.Num(); UploadPrimitiveIndex++)
|
|
{
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = DistanceFieldSceneData.PendingAddOperations[UploadPrimitiveIndex];
|
|
|
|
int32 NumInstances = 0;
|
|
float BoundsSurfaceArea = 0;
|
|
PrimitiveSceneInfo->Proxy->GetDistanceFieldInstanceInfo(NumInstances, BoundsSurfaceArea);
|
|
|
|
extern void ComputeNumSurfels(float BoundsSurfaceArea, int32& PrimitiveNumSurfels, int32& PrimitiveLOD0Surfels);
|
|
int32 PrimitiveNumSurfels;
|
|
int32 PrimitiveLOD0Surfels;
|
|
ComputeNumSurfels(BoundsSurfaceArea, PrimitiveNumSurfels, PrimitiveLOD0Surfels);
|
|
|
|
if (PrimitiveNumSurfels > 0 && NumInstances > 0)
|
|
{
|
|
const int32 PrimitiveTotalNumSurfels = PrimitiveNumSurfels * NumInstances;
|
|
|
|
if (PrimitiveNumSurfels > 5000)
|
|
{
|
|
UE_LOG(LogDistanceField,Warning,TEXT("Primitive %s %s used %u Surfels"), *PrimitiveSceneInfo->Proxy->GetOwnerName().ToString(), *PrimitiveSceneInfo->Proxy->GetResourceName().ToString(), PrimitiveNumSurfels);
|
|
}
|
|
|
|
DistanceFieldSceneData.SurfelAllocations.AddPrimitive(PrimitiveSceneInfo, PrimitiveLOD0Surfels, PrimitiveNumSurfels, 1);
|
|
DistanceFieldSceneData.InstancedSurfelAllocations.AddPrimitive(PrimitiveSceneInfo, PrimitiveLOD0Surfels, PrimitiveNumSurfels, NumInstances);
|
|
}
|
|
}
|
|
|
|
if (DistanceFieldSceneData.SurfelBuffers->MaxSurfels < DistanceFieldSceneData.SurfelAllocations.GetNumSurfelsInBuffer())
|
|
{
|
|
if (DistanceFieldSceneData.SurfelBuffers->MaxSurfels > 0)
|
|
{
|
|
// Realloc
|
|
FSurfelBuffers* NewSurfelBuffers = new FSurfelBuffers();
|
|
NewSurfelBuffers->MaxSurfels = DistanceFieldSceneData.SurfelAllocations.GetNumSurfelsInBuffer() * 5 / 4;
|
|
NewSurfelBuffers->Initialize();
|
|
|
|
{
|
|
TShaderMapRef<FCopySurfelBufferCS> ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, *(DistanceFieldSceneData.SurfelBuffers), *(DistanceFieldSceneData.InstancedSurfelBuffers), *NewSurfelBuffers, OriginalNumSurfels);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(OriginalNumSurfels, UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, *NewSurfelBuffers);
|
|
}
|
|
|
|
DistanceFieldSceneData.SurfelBuffers->Release();
|
|
delete DistanceFieldSceneData.SurfelBuffers;
|
|
DistanceFieldSceneData.SurfelBuffers = NewSurfelBuffers;
|
|
}
|
|
else
|
|
{
|
|
// First time allocate
|
|
DistanceFieldSceneData.SurfelBuffers->MaxSurfels = DistanceFieldSceneData.SurfelAllocations.GetNumSurfelsInBuffer() * 5 / 4;
|
|
DistanceFieldSceneData.SurfelBuffers->Initialize();
|
|
}
|
|
}
|
|
|
|
if (DistanceFieldSceneData.InstancedSurfelBuffers->MaxSurfels < DistanceFieldSceneData.InstancedSurfelAllocations.GetNumSurfelsInBuffer())
|
|
{
|
|
if (DistanceFieldSceneData.InstancedSurfelBuffers->MaxSurfels > 0)
|
|
{
|
|
// Realloc
|
|
FInstancedSurfelBuffers* NewInstancedSurfelBuffers = new FInstancedSurfelBuffers();
|
|
NewInstancedSurfelBuffers->MaxSurfels = DistanceFieldSceneData.InstancedSurfelAllocations.GetNumSurfelsInBuffer() * 5 / 4;
|
|
NewInstancedSurfelBuffers->Initialize();
|
|
|
|
{
|
|
TShaderMapRef<FCopyVPLFluxBufferCS> ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, *(DistanceFieldSceneData.SurfelBuffers), *(DistanceFieldSceneData.InstancedSurfelBuffers), *NewInstancedSurfelBuffers, OriginalNumInstancedSurfels);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(OriginalNumInstancedSurfels, UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, *NewInstancedSurfelBuffers);
|
|
}
|
|
|
|
DistanceFieldSceneData.InstancedSurfelBuffers->Release();
|
|
delete DistanceFieldSceneData.InstancedSurfelBuffers;
|
|
DistanceFieldSceneData.InstancedSurfelBuffers = NewInstancedSurfelBuffers;
|
|
}
|
|
else
|
|
{
|
|
// First time allocate
|
|
DistanceFieldSceneData.InstancedSurfelBuffers->MaxSurfels = DistanceFieldSceneData.InstancedSurfelAllocations.GetNumSurfelsInBuffer() * 5 / 4;
|
|
DistanceFieldSceneData.InstancedSurfelBuffers->Initialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int32 UploadPrimitiveIndex = 0; UploadPrimitiveIndex < DistanceFieldSceneData.PendingAddOperations.Num(); UploadPrimitiveIndex++)
|
|
{
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = DistanceFieldSceneData.PendingAddOperations[UploadPrimitiveIndex];
|
|
|
|
ProcessPrimitiveUpdate(
|
|
true,
|
|
RHICmdList,
|
|
*this,
|
|
PrimitiveSceneInfo,
|
|
OriginalNumObjects,
|
|
InvTextureDim,
|
|
bPrepareForDistanceFieldGI,
|
|
ObjectLocalToWorldTransforms,
|
|
UploadObjectIndices,
|
|
UploadObjectData);
|
|
}
|
|
|
|
for (TSet<FPrimitiveSceneInfo*>::TIterator It(DistanceFieldSceneData.PendingUpdateOperations); It; ++It)
|
|
{
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = *It;
|
|
|
|
ProcessPrimitiveUpdate(
|
|
false,
|
|
RHICmdList,
|
|
*this,
|
|
PrimitiveSceneInfo,
|
|
OriginalNumObjects,
|
|
InvTextureDim,
|
|
bPrepareForDistanceFieldGI,
|
|
ObjectLocalToWorldTransforms,
|
|
UploadObjectIndices,
|
|
UploadObjectData);
|
|
}
|
|
|
|
DistanceFieldSceneData.PendingAddOperations.Reset();
|
|
DistanceFieldSceneData.PendingUpdateOperations.Empty();
|
|
|
|
if (DistanceFieldSceneData.ObjectBuffers->MaxObjects < DistanceFieldSceneData.NumObjectsInBuffer)
|
|
{
|
|
if (DistanceFieldSceneData.ObjectBuffers->MaxObjects > 0)
|
|
{
|
|
// Realloc
|
|
FDistanceFieldObjectBuffers* NewObjectBuffers = new FDistanceFieldObjectBuffers();
|
|
NewObjectBuffers->MaxObjects = DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4;
|
|
NewObjectBuffers->Initialize();
|
|
|
|
{
|
|
TShaderMapRef<FCopyObjectBufferCS> ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, *(DistanceFieldSceneData.ObjectBuffers), *NewObjectBuffers, OriginalNumObjects);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(OriginalNumObjects, UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, *NewObjectBuffers);
|
|
}
|
|
|
|
DistanceFieldSceneData.ObjectBuffers->Release();
|
|
delete DistanceFieldSceneData.ObjectBuffers;
|
|
DistanceFieldSceneData.ObjectBuffers = NewObjectBuffers;
|
|
}
|
|
else
|
|
{
|
|
// First time allocate
|
|
DistanceFieldSceneData.ObjectBuffers->MaxObjects = DistanceFieldSceneData.NumObjectsInBuffer * 5 / 4;
|
|
DistanceFieldSceneData.ObjectBuffers->Initialize();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (UploadObjectIndices.Num() > 0)
|
|
{
|
|
if (UploadObjectIndices.Num() > GDistanceFieldUploadIndices.UploadIndices.MaxElements)
|
|
{
|
|
GDistanceFieldUploadIndices.UploadIndices.MaxElements = UploadObjectIndices.Num() * 5 / 4;
|
|
GDistanceFieldUploadIndices.UploadIndices.Release();
|
|
GDistanceFieldUploadIndices.UploadIndices.Initialize();
|
|
|
|
GDistanceFieldUploadData.UploadData.MaxElements = UploadObjectIndices.Num() * 5 / 4;
|
|
GDistanceFieldUploadData.UploadData.Release();
|
|
GDistanceFieldUploadData.UploadData.Initialize();
|
|
}
|
|
|
|
void* LockedBuffer = RHILockVertexBuffer(GDistanceFieldUploadIndices.UploadIndices.Buffer, 0, GDistanceFieldUploadIndices.UploadIndices.Buffer->GetSize(), RLM_WriteOnly);
|
|
const uint32 MemcpySize = UploadObjectIndices.GetTypeSize() * UploadObjectIndices.Num();
|
|
check(GDistanceFieldUploadIndices.UploadIndices.Buffer->GetSize() >= MemcpySize);
|
|
FPlatformMemory::Memcpy(LockedBuffer, UploadObjectIndices.GetData(), MemcpySize);
|
|
RHIUnlockVertexBuffer(GDistanceFieldUploadIndices.UploadIndices.Buffer);
|
|
|
|
LockedBuffer = RHILockVertexBuffer(GDistanceFieldUploadData.UploadData.Buffer, 0, GDistanceFieldUploadData.UploadData.Buffer->GetSize(), RLM_WriteOnly);
|
|
const uint32 MemcpySize2 = UploadObjectData.GetTypeSize() * UploadObjectData.Num();
|
|
check(GDistanceFieldUploadData.UploadData.Buffer->GetSize() >= MemcpySize2);
|
|
FPlatformMemory::Memcpy(LockedBuffer, UploadObjectData.GetData(), MemcpySize2);
|
|
RHIUnlockVertexBuffer(GDistanceFieldUploadData.UploadData.Buffer);
|
|
|
|
{
|
|
TShaderMapRef<FUploadObjectsToBufferCS> ComputeShader(GetGlobalShaderMap(Scene->GetFeatureLevel()));
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, Scene, UploadObjectIndices.Num(), GDistanceFieldUploadIndices.UploadIndices.BufferSRV, GDistanceFieldUploadData.UploadData.BufferSRV);
|
|
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, FMath::DivideAndRoundUp<uint32>(UploadObjectIndices.Num(), UpdateObjectsGroupSize), 1, 1);
|
|
ComputeShader->UnsetParameters(RHICmdList, Scene);
|
|
}
|
|
}
|
|
|
|
check(DistanceFieldSceneData.NumObjectsInBuffer == DistanceFieldSceneData.PrimitiveInstanceMapping.Num());
|
|
|
|
DistanceFieldSceneData.VerifyIntegrity();
|
|
}
|
|
}
|
|
|
|
FString GetObjectBufferMemoryString()
|
|
{
|
|
return FString::Printf(TEXT("Temp object buffers %.3fMb"),
|
|
(GDistanceFieldUploadIndices.UploadIndices.GetSizeBytes() + GDistanceFieldUploadData.UploadData.GetSizeBytes() + GDistanceFieldRemoveIndices.RemoveIndices.GetSizeBytes()) / 1024.0f / 1024.0f);
|
|
}
|