Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Private/RenderGraphResources.cpp

215 lines
7.3 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
#include "RenderGraphResources.h"
#include "RenderGraphPrivate.h"
inline bool SkipUAVBarrier(const FRDGSubresourceState& Previous, const FRDGSubresourceState& Next)
{
return SkipUAVBarrier(Previous.NoUAVBarrierFilter.GetUniqueHandle(), Next.NoUAVBarrierFilter.GetUniqueHandle());
}
FRDGTexture::FRDGTexture(const TCHAR* InName, const FRDGTextureDesc& InDesc, ERDGTextureFlags InFlags)
: FRDGViewableResource(InName, ERDGViewableResourceType::Texture, EnumHasAnyFlags(InFlags, ERDGTextureFlags::SkipTracking), !EnumHasAnyFlags(InFlags, ERDGTextureFlags::ForceImmediateFirstBarrier) && !EnumHasAnyFlags(InDesc.Flags, ETextureCreateFlags::Presentable))
, Desc(InDesc)
, Flags(InFlags)
, Layout(InDesc)
, WholeRange(Layout)
, SubresourceCount(Layout.GetSubresourceCount())
{
if (EnumHasAnyFlags(Desc.Flags, ETextureCreateFlags::Foveation))
{
EpilogueAccess = ERHIAccess::ShadingRateSource;
}
State.SetNum(SubresourceCount);
FirstState.SetNum(SubresourceCount);
MergeState.SetNum(SubresourceCount);
LastProducers.SetNum(SubresourceCount);
}
FRDGBuffer::FRDGBuffer(const TCHAR* InName, const FRDGBufferDesc& InDesc, ERDGBufferFlags InFlags)
: FRDGViewableResource(InName, ERDGViewableResourceType::Buffer, EnumHasAnyFlags(InFlags, ERDGBufferFlags::SkipTracking), !EnumHasAnyFlags(InFlags, ERDGBufferFlags::ForceImmediateFirstBarrier))
, Desc(InDesc)
, Flags(InFlags)
{}
FRDGViewableResource::FRDGViewableResource(const TCHAR* InName, const ERDGViewableResourceType InType, bool bSkipTracking, bool bInSplitFirstTransition)
: FRDGResource(InName)
, Type(InType)
, bExternal(0)
, bExtracted(0)
, bProduced(0)
, bTransient(0)
, bForceNonTransient(0)
, bSkipLastTransition(0)
, bSplitFirstTransition(bInSplitFirstTransition)
, bQueuedForUpload(0)
, bCollectForAllocate(1)
[Re-submit Backout attempt take 2 -- original horde failure didn't repro on preflight, so maybe it was a spurious issue?] Post Process Material: Support for "UserSceneTextures" -- transient intermediate render targets that can be written and read by name in post process materials. The post process section of materials has a UserSceneTexture output name, and a new UserSceneTexture node type has been added to read back those outputs as inputs. Shader features: * A resolution divisor can be specified on the output to allow things like half resolution targets. If the same name is used with multiple resolutions, the most recently written resolution is used as an input. * A UV clamping option was added to solve out of bounds interpolation issues when bilinear sampling lower resolution targets from a higher resolution pass. * A human readable define based on the user specified name is added to HLSL (with prefix "PPIUser_"), allowing Custom HLSL nodes to refer to UserSceneTexture inputs by name. Necessary because input slots are dynamically allocated. Useful for things like blur kernels that use Custom HLSL to sample a range of inputs. * All 5 Post Process Input slots are potentially available to UserSceneTextures -- built-in SceneTexture slots for a given location (like SceneColor, SeparateTranslucency, or SceneVelocity) are used for UserSceneTextures if not referenced in the shader. * Supports translucent blending. If the first write to a UserSceneTexture includes blending, it will be primed with the current input for the given location. * Missing inputs are replaced with black. * Simplified syntax for accessing SceneTextures / UserSceneTextures in Custom HLSL (see "SceneTextureFetch" macro). Editing / debug features: * Material editor preview window automatically includes other edited materials that feed inputs into the current material, allowing multi-pass effects to be interactively edited. * Debug display of post process passes with UserSceneTexture inputs or output via r.PostProcessing.UserSceneTextureDebug. Allows seeing order, location, and priority of passes, plus names of material, inputs, and output, and whether an output is written with blending. * Debug display pops up automatically on error conditions (missing input, unused output), improving discoverability. Suppressed by DisableAllScreenMessages (or setting CVar itself to zero). * FRDGViewableResource can now be given dynamically generated heap allocated debug names (indicated by setting a flag immediately after construction), instead of only supporting static const strings. Allows UserSceneTexture names to be displayed in debug displays, VisualizeTexture, GPU captures, and GPU dumps, instead of every resource getting the same name. Mobile doesn't support post process domain materials at all, so the feature is not relevant there. Tested on scene captures, split screen, and both legacy and new material translate code paths. An existing bug was fixed where rendering post process materials with blending before bloom would crash, due to the output not being allocated with the render target flag set. #rb eric.renaudhoude, Ruslan.Idrisov [CL 34055494 by jason hoerner in ue5-main branch]
2024-06-01 13:02:37 -04:00
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
, bHeapAllocatedDebugName(0)
#endif
, TransientExtractionHint(ETransientExtractionHint::None)
, ReferenceCount(IsImmediateMode() ? 1 : 0)
{
if (bSkipTracking)
{
SetExternalAccessMode(ERHIAccess::Mask, ERHIPipeline::All);
AccessModeState.bLocked = 1;
AccessModeState.ActiveMode = AccessModeState.Mode;
}
}
Added RHI tracked access API to remove Unknown transitions. - New RHI command list SetTrackedAccess method for the user to supply a current whole-resource state. - New RHI command context GetTrackedAccess method for querying the tracked access in RHIBeginTransitions / RHIEndTransitions on the RHI thread. - Hooked RHICmdList.Transition and FRHICommandListExecutor::Transition to assign tracked state automatically. - Refactored RDG and resource pools to use new RHI tracking. - FRDGPooledBuffer / FRDGPooledTexture no longer contain tracked state. RDG temp-allocates state through the graph allocator instead. - All prologue transitions are 'Unknown', and all epilogue transitions coalesce into a whole resource state. - Implemented platform support for patching the 'before' state with the tracked state. - Implemented various RHI validation checks: - Asserts that the user assigned tracked state matches RHI validation tracked state, for all subresources. - Asserts that tracked state is not assigned or queried from a parallel translation context. - Added FRHIViewableResource and FRHIView base classes to RHI. FRHIView contains a pointer to an FRHIViewableResource. This is currently a raw pointer, but should be extended to a full reference in a later CL. NOTE on RHI thread constraint: Transition evaluation is now restricted to the RHI thread (i.e. no parallel translation contexts). Transitions aren't performed in parallel translate contexts anyway, so this is not a problem. If, however, we decide to refactor parallel translation to be more general, this implementation could be extended to track the state per context and update from the 'dispatch' thread. #preflight 6233b4396666d7e753a16aaf #rb kenzo.terelst [CL 19513316 by zach bethel in ue5-main branch]
2022-03-25 11:19:10 -04:00
bool FRDGSubresourceState::IsMergeAllowed(ERDGViewableResourceType ResourceType, const FRDGSubresourceState& Previous, const FRDGSubresourceState& Next)
{
/** State merging occurs during compilation and before resource transitions are collected. It serves to remove the bulk
* of unnecessary transitions by looking ahead in the resource usage chain. A resource transition cannot occur within
* a merged state, so a merge is not allowed to proceed if a barrier might be required. Merging is also where multi-pipe
* transitions are determined, if supported by the platform.
*/
const ERHIAccess AccessUnion = Previous.Access | Next.Access;
const ERHIAccess DSVMask = ERHIAccess::DSVRead | ERHIAccess::DSVWrite;
// If we have the same access between the two states, we don't need to check for invalid access combinations.
if (Previous.Access != Next.Access)
{
// Not allowed to merge read-only and writable states.
if (EnumHasAnyFlags(Previous.Access, ERHIAccess::ReadOnlyExclusiveMask) && EnumHasAnyFlags(Next.Access, ERHIAccess::WritableMask))
{
return false;
}
// Not allowed to merge write-only and readable states.
if (EnumHasAnyFlags(Previous.Access, ERHIAccess::WriteOnlyExclusiveMask) && EnumHasAnyFlags(Next.Access, ERHIAccess::ReadableMask))
{
return false;
}
// UAVs will filter through the above checks because they are both read and write. UAV can only merge it itself.
if (EnumHasAnyFlags(AccessUnion, ERHIAccess::UAVMask) && EnumHasAnyFlags(AccessUnion, ~ERHIAccess::UAVMask))
{
return false;
}
// Depth Read / Write should never merge with anything other than itself.
if (EnumHasAllFlags(AccessUnion, DSVMask) && EnumHasAnyFlags(AccessUnion, ~DSVMask))
{
return false;
}
// Filter out platform-specific unsupported mergeable states.
if (EnumHasAnyFlags(AccessUnion, ~GRHIMergeableAccessMask))
{
return false;
}
}
// Not allowed if the resource is being used as a UAV and needs a barrier.
if (EnumHasAnyFlags(Next.Access, ERHIAccess::UAVMask) && !SkipUAVBarrier(Previous, Next))
{
return false;
}
// Filter out unsupported platform-specific multi-pipeline merged accesses.
if (EnumHasAnyFlags(AccessUnion, ~GRHIMultiPipelineMergeableAccessMask) && Previous.GetPipelines() != Next.GetPipelines())
{
return false;
}
// Not allowed to merge differing flags.
if (Previous.Flags != Next.Flags)
{
return false;
}
return true;
}
bool FRDGSubresourceState::IsTransitionRequired(const FRDGSubresourceState& Previous, const FRDGSubresourceState& Next)
{
// This function only needs to filter out identical states and handle UAV barriers.
check(Next.Access != ERHIAccess::Unknown);
if (Previous.Access != Next.Access || Previous.GetPipelines() != Next.GetPipelines() || Previous.Flags != Next.Flags)
{
return true;
}
// UAV is a special case as a barrier may still be required even if the states match.
if (EnumHasAnyFlags(Next.Access, ERHIAccess::UAVMask) && !SkipUAVBarrier(Previous, Next))
{
return true;
}
return false;
}
FRDGPooledBuffer::FRDGPooledBuffer(TRefCountPtr<FRHIBuffer> InBuffer, const FRDGBufferDesc& InDesc, uint32 InNumAllocatedElements, const TCHAR* InName)
: FRDGPooledBuffer(FRHICommandListImmediate::Get(), MoveTemp(InBuffer), InDesc, InNumAllocatedElements, InName)
{}
void FRDGPooledBuffer::SetDebugLabelName(FRHICommandListBase& RHICmdList, const TCHAR* InName)
{
#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
Name = InName;
#else
// For performance, avoid updating name if it happens to be the same (true 80% of the time in testing)
bool bNameUpdated = false;
if (!InName || FCString::Strcmp(Name, InName))
{
// Name changed, need to update it
Name = InName;
RHICmdList.BindDebugLabelName(GetRHI(), InName);
bNameUpdated = true;
}
// Propagate the debug name to ViewCache if the name was updated, or if any items were added to ViewCache since the debug name was set
int32 ViewCacheNum = ViewCache.NumItems();
if (bNameUpdated || NameUpdatedViewCacheNum != ViewCacheNum)
{
NameUpdatedViewCacheNum = ViewCacheNum;
ViewCache.SetDebugName(RHICmdList, InName);
}
#endif
}
FRDGUniformBuffer::~FRDGUniformBuffer() = default;
void FRDGUniformBuffer::InitRHI()
{
check(!HasRHI());
const EUniformBufferValidation Validation =
#if RDG_ENABLE_DEBUG
EUniformBufferValidation::ValidateResources;
#else
EUniformBufferValidation::None;
#endif
const FRDGParameterStruct& PassParameters = GetParameters();
UniformBufferRHI = RHICreateUniformBuffer(PassParameters.GetContents(), PassParameters.GetLayoutPtr(), UniformBuffer_SingleFrame, Validation);
ResourceRHI = UniformBufferRHI;
}
FRDGTextureSubresourceRange FRDGTexture::GetSubresourceRangeSRV() const
{
FRDGTextureSubresourceRange Range = GetSubresourceRange();
// When binding a whole texture for shader read (SRV), we only use the first plane.
// Other planes like stencil require a separate view to access for read in the shader.
Range.PlaneSlice = FRHITransitionInfo::kDepthPlaneSlice;
Range.NumPlaneSlices = 1;
return Range;
}
void FRDGBuffer::FinalizeDesc()
{
if (NumElementsCallback)
{
Desc.NumElements = FMath::Max(NumElementsCallback(), 1u);
NumElementsCallback = {};
}
}