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 ========================== MAJOR FEATURES + CHANGES ========================== Change 2806454 on 2015/12/16 by Bob.Tellez #UE4 Getting crash reporting working again on linux servers. Since -Unattended is now being passed BEFORE the target folder, the cmd line parsing code was failing so now it parses tokens and switches in a more general way. Also, diagnostics.txt had the incorrect case, since the d is supposed to be capitolized and the crash report processor is case sensitive. #rb Ben.Zeigler #codereview Dmitry.Rekman Change 2805502 on 2015/12/16 by Ben.Zeigler #UE4 Move ValidateEnumProperties into ValidateGeneratedClass, it was happening too early in the generation process so was being called at an invalid time. As a result of this ValidateEnumProperties will not be called correctly for compile on load blueprints, that issue is covered in UE-24569 #codereview mike.beach, bob.tellez Change 2805288 on 2015/12/16 by David.Nikdel #HTTP #HttpRetry - Add new Failed_ConnectionError code to EHttpRequestStatus to distinguish between connection errors and protocol errors. - Changed HTTP retry logic a little bit * If a response was received, retry on service-specific explicit HTTP codes (defaults to empty) * If a response was not received and we did not send a full request, automatically retry * If a response was not received and a request may have been sent, retry if the verb is GET or HEAD (should be idempotent) - Adjusted Curl/IOS/Mac/PS4/WinInet to try and distinguish Failed_ConnectionError where possible * Other systems will default to Failed which is ok (ConnectionError is an opportunistic categorization) * Opened a PS4 ticket to try to improve detection, but unfortunately there's no way (currently) to distinguish between send timeout, connection timeout, and receive timeout, the latter being the problematic case. - Removed the concept of global/default HTTP retry status codes. No system has enough knowledge to set those globally. * Individual requests still specify explicit "retryable" codes and McpServiceBase sets that on each request on a per-service basis #RB: Sam.Zamani #CodeReview: Sam.Zamani, Josh.Markiewicz, Alex.Fennell, Dmitry.Rekman, Sam.Spiro #Fixes: FORT-17804 Change 2803864 on 2015/12/15 by Bob.Tellez #UE4 Changed usage of !UE_SERVER to !IsRunningDedicatedServer in cases where we are preventing load attempts on UFonts. This is so running an editor build with -server works the same as running a cooked server. #rb Dmitry.Rekman #codereview Nick.Darnell Change 2803677 on 2015/12/15 by Billy.Bramer - Expose equality and inequality operators for gameplay attributes #rb Todd.Eckert Change 2802881 on 2015/12/14 by Bob.Tellez #UE4 InheritableComponentHandler no longer keeps records for components that we are no longer inheriting. #rb Phillip.Kavan, Maciej.Mroz #codereview Phillip.Kavan, Maciej.Mroz Change 2801636 on 2015/12/14 by Bob.Tellez #UE4 Returning package insert order for non-imports back to being after those of matching priorities unconditionally since this is what you want even when you are not using the asset registry to preload packages. #codereview Graeme.Thornton Change 2800400 on 2015/12/11 by Jonathan.Lindquist Submitting a new Pivot Painter Edition - now renders to textures - improved workflow - greater capabilities Change 2799579 on 2015/12/11 by John.Abercrombie [AUTOMERGE] Fixed EQS BP query wrappers getting GCed before wrapped query finishes #UE4 Fixes FORT-18649 - Patrols don't spawn consistently - The patrol blueprint was waiting (endlessly) for an EQS query to finish but because the wrapper could be GC-ed while the EQS query was running the delegate would never fire #rb me (this code was written by MieszkoZ) (removed code review for integration of Mieszko.Zielinski, Phil.Cole, Dominic.Barile) -------- Integrated using branch UE4-Fortnite-To-UE4-FortniteReleases/0.10 (reversed) of change#2799575 by John.Abercrombie on 2015/12/11 09:55:11. Change 2799018 on 2015/12/10 by Bob.Tellez #UE4 The asset registry tags stripped from cooked builds is now a blacklist by default that includes only the FiB tag. You can opt-in to using the whitelist by flipping the bUseAssetRegistryTagsWhitelistInsteadOfBlacklist flag. #rb Fred.Kimberley #codereview Peter.Knepley Change 2798926 on 2015/12/10 by Bob.Tellez #UE4 Removed some showflags from the list of "Fixed" showflags since they were actually in use at runtime in Fortnite in a scene capture. #jira FORT-18514 #codereview Martin.Mittring Change 2797758 on 2015/12/10 by Mark.Satterthwaite Defer calls to AUGraphUpdate into FCoreAudioDevice::UpdateHardware - this call will synchronise the calling thread with the CoreAudio thread/run-loop so that the CoreAudio graph is safe to modify and this may incur a significant stall. This means it is far more efficient to amortise the cost of all changes to the graph with a single call. To ensure correctness the audio format conversion components are cached and disposed of after the call to AUGraphUpdate so that any existing operations on the CoreAudio thread are completed prior to disposal. Change 2781204 on 2015/11/25 by Dmitry.Rekman Linux: use jemalloc by default if available. - Alleviates one of the reasons for player disconnect (FORT-18048), which was machines running OOM. #rb Bob.Tellez #codereview Bob.Tellez, Ben.Zeigler Change 2779398 on 2015/11/24 by Mark.Satterthwaite Switch the default graphics API on Mac back to OpenGL, but allow Metal to run with -metal (or -metalsm5 for experimental SM5 support).
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_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GAOLogObjectBufferReallocation = 0;
|
|
FAutoConsoleVariableRef CVarAOLogObjectBufferReallocation(
|
|
TEXT("r.AOLogObjectBufferReallocation"),
|
|
GAOLogObjectBufferReallocation,
|
|
TEXT(""),
|
|
ECVF_Cheat | 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 ? TEXT("1") : TEXT("0"));
|
|
}
|
|
|
|
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)
|
|
{
|
|
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;
|
|
|
|
DistanceFieldSceneData.PrimitiveModifiedBounds.Reset();
|
|
|
|
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);
|
|
}
|