本文整理汇总了C++中TMap::ValueSort方法的典型用法代码示例。如果您正苦于以下问题:C++ TMap::ValueSort方法的具体用法?C++ TMap::ValueSort怎么用?C++ TMap::ValueSort使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TMap
的用法示例。
在下文中一共展示了TMap::ValueSort方法的8个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: CreateTextures
void FSlateRHIResourceManager::CreateTextures( const TArray< const FSlateBrush* >& Resources )
{
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Loading Slate Textures"), STAT_Slate, STATGROUP_LoadTime);
TMap<FName,FNewTextureInfo> TextureInfoMap;
const uint32 Stride = GPixelFormats[PF_R8G8B8A8].BlockBytes;
for( int32 ResourceIndex = 0; ResourceIndex < Resources.Num(); ++ResourceIndex )
{
const FSlateBrush& Brush = *Resources[ResourceIndex];
const FName TextureName = Brush.GetResourceName();
if( TextureName != NAME_None && !Brush.HasUObject() && !Brush.IsDynamicallyLoaded() && !ResourceMap.Contains(TextureName) )
{
// Find the texture or add it if it doesnt exist (only load the texture once)
FNewTextureInfo& Info = TextureInfoMap.FindOrAdd( TextureName );
Info.bSrgb = (Brush.ImageType != ESlateBrushImageType::Linear);
// Only atlas the texture if none of the brushes that use it tile it and the image is srgb
Info.bShouldAtlas &= ( Brush.Tiling == ESlateBrushTileType::NoTile && Info.bSrgb && AtlasSize > 0 );
// Texture has been loaded if the texture data is valid
if( !Info.TextureData.IsValid() )
{
uint32 Width = 0;
uint32 Height = 0;
TArray<uint8> RawData;
bool bSucceeded = LoadTexture( Brush, Width, Height, RawData );
Info.TextureData = MakeShareable( new FSlateTextureData( Width, Height, Stride, RawData ) );
const bool bTooLargeForAtlas = (Width >= 256 || Height >= 256 || Width >= AtlasSize || Height >= AtlasSize );
Info.bShouldAtlas &= !bTooLargeForAtlas;
if( !bSucceeded || !ensureMsgf( Info.TextureData->GetRawBytes().Num() > 0, TEXT("Slate resource: (%s) contains no data"), *TextureName.ToString() ) )
{
TextureInfoMap.Remove( TextureName );
}
}
}
}
// Sort textures by size. The largest textures are atlased first which creates a more compact atlas
TextureInfoMap.ValueSort( FCompareFNewTextureInfoByTextureSize() );
for( TMap<FName,FNewTextureInfo>::TConstIterator It(TextureInfoMap); It; ++It )
{
const FNewTextureInfo& Info = It.Value();
FName TextureName = It.Key();
FString NameStr = TextureName.ToString();
checkSlow( TextureName != NAME_None );
FSlateShaderResourceProxy* NewTexture = GenerateTextureResource( Info );
ResourceMap.Add( TextureName, NewTexture );
}
}
示例2: LoadTexture
void FSlateD3DTextureManager::CreateTextures( const TArray< const FSlateBrush* >& Resources )
{
TMap<FName,FNewTextureInfo> TextureInfoMap;
for( int32 ResourceIndex = 0; ResourceIndex < Resources.Num(); ++ResourceIndex )
{
const FSlateBrush& Brush = *Resources[ResourceIndex];
const FName TextureName = Brush.GetResourceName();
if( TextureName != NAME_None && !ResourceMap.Contains(TextureName) )
{
// Find the texture or add it if it doesn't exist (only load the texture once)
FNewTextureInfo& Info = TextureInfoMap.FindOrAdd( TextureName );
Info.bSrgb = (Brush.ImageType != ESlateBrushImageType::Linear);
// Only atlas the texture if none of the brushes that use it tile it
Info.bShouldAtlas &= (Brush.Tiling == ESlateBrushTileType::NoTile && Info.bSrgb );
if( !Info.TextureData.IsValid())
{
uint32 Width = 0;
uint32 Height = 0;
TArray<uint8> RawData;
bool bSucceeded = LoadTexture( Brush, Width, Height, RawData );
const uint32 Stride = 4; // RGBA
Info.TextureData = MakeShareable( new FSlateTextureData( Width, Height, Stride, RawData ) );
const bool bTooLargeForAtlas = (Width >= 256 || Height >= 256);
Info.bShouldAtlas &= !bTooLargeForAtlas;
if( !bSucceeded )
{
TextureInfoMap.Remove( TextureName );
}
}
}
}
TextureInfoMap.ValueSort( FCompareFNewTextureInfoByTextureSize() );
for( TMap<FName,FNewTextureInfo>::TConstIterator It(TextureInfoMap); It; ++It )
{
const FNewTextureInfo& Info = It.Value();
FName TextureName = It.Key();
FString NameStr = TextureName.ToString();
FSlateShaderResourceProxy* NewTexture = GenerateTextureResource( Info );
ResourceMap.Add( TextureName, NewTexture );
}
}
示例3: DumpSharedMemoryUsage
void FPhysxSharedData::DumpSharedMemoryUsage(FOutputDevice* Ar)
{
struct FSharedResourceEntry
{
uint64 MemorySize;
uint64 Count;
};
struct FSortBySize
{
FORCEINLINE bool operator()( const FSharedResourceEntry& A, const FSharedResourceEntry& B ) const
{
// Sort descending
return B.MemorySize < A.MemorySize;
}
};
TMap<FString, FSharedResourceEntry> AllocationsByType;
uint64 OverallSize = 0;
int32 OverallCount = 0;
TMap<FString, TArray<PxBase*> > ObjectsByType;
for (int32 i=0; i < (int32)SharedObjects->getNbObjects(); ++i)
{
PxBase& Obj = SharedObjects->getObject(i);
FString TypeName = ANSI_TO_TCHAR(Obj.getConcreteTypeName());
TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName);
if (ObjectsArray == NULL)
{
ObjectsByType.Add(TypeName, TArray<PxBase*>());
ObjectsArray = ObjectsByType.Find(TypeName);
}
check(ObjectsArray);
ObjectsArray->Add(&Obj);
}
TArray<FString> TypeNames;
ObjectsByType.GetKeys(TypeNames);
for (int32 TypeIdx=0; TypeIdx < TypeNames.Num(); ++TypeIdx)
{
const FString& TypeName = TypeNames[TypeIdx];
TArray<PxBase*>* ObjectsArray = ObjectsByType.Find(TypeName);
check(ObjectsArray);
PxSerializationRegistry* Sr = PxSerialization::createSerializationRegistry(*GPhysXSDK);
PxCollection* Collection = PxCreateCollection();
for (int32 i=0; i < ObjectsArray->Num(); ++i)
{
Collection->add(*((*ObjectsArray)[i]));;
}
PxSerialization::complete(*Collection, *Sr); // chase all other stuff (shared shaps, materials, etc) needed to serialize this collection
FPhysXCountMemoryStream Out;
PxSerialization::serializeCollectionToBinary(Out, *Collection, *Sr);
Collection->release();
Sr->release();
OverallSize += Out.UsedMemory;
OverallCount += ObjectsArray->Num();
FSharedResourceEntry NewEntry;
NewEntry.Count = ObjectsArray->Num();
NewEntry.MemorySize = Out.UsedMemory;
AllocationsByType.Add(TypeName, NewEntry);
}
Ar->Logf(TEXT(""));
Ar->Logf(TEXT("Shared Resources:"));
Ar->Logf(TEXT(""));
AllocationsByType.ValueSort(FSortBySize());
Ar->Logf(TEXT("%-10d %s (%d)"), OverallSize, TEXT("Overall"), OverallCount );
for( auto It=AllocationsByType.CreateConstIterator(); It; ++It )
{
Ar->Logf(TEXT("%-10d %s (%d)"), It.Value().MemorySize, *It.Key(), It.Value().Count );
}
}
示例4: ReassignStationaryLightChannels
void ULightComponent::ReassignStationaryLightChannels(UWorld* TargetWorld, bool bAssignForLightingBuild)
{
TMap<FLightAndChannel*, TArray<FLightAndChannel*> > LightToOverlapMap;
// Build an array of all static shadowing lights that need to be assigned
for(TObjectIterator<ULightComponent> LightIt(RF_ClassDefaultObject|RF_PendingKill); LightIt; ++LightIt)
{
ULightComponent* const LightComponent = *LightIt;
const bool bLightIsInWorld = LightComponent->GetOwner() && TargetWorld->ContainsActor(LightComponent->GetOwner()) && !LightComponent->GetOwner()->IsPendingKill();
if (bLightIsInWorld
// Only operate on stationary light components (static shadowing only)
&& LightComponent->HasStaticShadowing()
&& !LightComponent->HasStaticLighting())
{
if (LightComponent->bAffectsWorld
&& LightComponent->CastShadows
&& LightComponent->CastStaticShadows)
{
LightToOverlapMap.Add(new FLightAndChannel(LightComponent), TArray<FLightAndChannel*>());
}
else
{
// Reset the preview channel of stationary light components that shouldn't get a channel
// This is necessary to handle a light being newly disabled
LightComponent->PreviewShadowMapChannel = INDEX_NONE;
#if WITH_EDITOR
LightComponent->UpdateLightSpriteTexture();
#endif
}
}
}
// Build an array of overlapping lights
for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It)
{
ULightComponent* CurrentLight = It.Key()->Light;
TArray<FLightAndChannel*>& OverlappingLights = It.Value();
if (bAssignForLightingBuild)
{
// This should have happened during lighting invalidation at the beginning of the build anyway
CurrentLight->ShadowMapChannel = INDEX_NONE;
}
for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator OtherIt(LightToOverlapMap); OtherIt; ++OtherIt)
{
ULightComponent* OtherLight = OtherIt.Key()->Light;
if (CurrentLight != OtherLight
// Testing both directions because the spotlight <-> spotlight test is just cone vs bounding sphere
//@todo - more accurate spotlight <-> spotlight intersection
&& CurrentLight->AffectsBounds(FBoxSphereBounds(OtherLight->GetBoundingSphere()))
&& OtherLight->AffectsBounds(FBoxSphereBounds(CurrentLight->GetBoundingSphere())))
{
OverlappingLights.Add(OtherIt.Key());
}
}
}
// Sort lights with the most overlapping lights first
LightToOverlapMap.ValueSort(FCompareLightsByArrayCount());
TMap<FLightAndChannel*, TArray<FLightAndChannel*> > SortedLightToOverlapMap;
// Add directional lights to the beginning so they always get channels
for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It)
{
FLightAndChannel* CurrentLight = It.Key();
if (CurrentLight->Light->GetLightType() == LightType_Directional)
{
SortedLightToOverlapMap.Add(It.Key(), It.Value());
}
}
// Add everything else, which has been sorted by descending overlaps
for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(LightToOverlapMap); It; ++It)
{
FLightAndChannel* CurrentLight = It.Key();
if (CurrentLight->Light->GetLightType() != LightType_Directional)
{
SortedLightToOverlapMap.Add(It.Key(), It.Value());
}
}
// Go through lights and assign shadowmap channels
//@todo - retry with different ordering heuristics when it fails
for (TMap<FLightAndChannel*, TArray<FLightAndChannel*> >::TIterator It(SortedLightToOverlapMap); It; ++It)
{
bool bChannelUsed[4] = {0};
FLightAndChannel* CurrentLight = It.Key();
const TArray<FLightAndChannel*>& OverlappingLights = It.Value();
// Mark which channels have already been assigned to overlapping lights
for (int32 OverlappingIndex = 0; OverlappingIndex < OverlappingLights.Num(); OverlappingIndex++)
{
//.........这里部分代码省略.........
示例5: ProcessingUObjectAllocations
void FStatsMemoryDumpCommand::ProcessingUObjectAllocations( const TMap<uint64, FAllocationInfo>& AllocationMap )
{
// This code is not optimized.
FScopeLogTime SLT( TEXT( "ProcessingUObjectAllocations" ), nullptr, FScopeLogTime::ScopeLog_Seconds );
UE_LOG( LogStats, Warning, TEXT( "Processing UObject allocations" ) );
FDiagnosticTableViewer MemoryReport( *FDiagnosticTableViewer::GetUniqueTemporaryFilePath( TEXT( "MemoryReport-UObject" ) ) );
// Write a row of headings for the table's columns.
MemoryReport.AddColumn( TEXT( "Size (bytes)" ) );
MemoryReport.AddColumn( TEXT( "Size (MB)" ) );
MemoryReport.AddColumn( TEXT( "Count" ) );
MemoryReport.AddColumn( TEXT( "UObject class" ) );
MemoryReport.CycleRow();
TMap<FName, FSizeAndCount> UObjectAllocations;
// To minimize number of calls to expensive DecodeCallstack.
TMap<FName,FName> UObjectCallstackToClassMapping;
uint64 NumAllocations = 0;
uint64 TotalAllocatedMemory = 0;
for( const auto& It : AllocationMap )
{
const FAllocationInfo& Alloc = It.Value;
FName UObjectClass = UObjectCallstackToClassMapping.FindRef( Alloc.EncodedCallstack );
if( UObjectClass == NAME_None )
{
TArray<FString> DecodedCallstack;
DecodeCallstack( Alloc.EncodedCallstack, DecodedCallstack );
for( int32 Index = DecodedCallstack.Num() - 1; Index >= 0; --Index )
{
NAME_INDEX NameIndex = 0;
TTypeFromString<NAME_INDEX>::FromString( NameIndex, *DecodedCallstack[Index] );
const FName LongName = FName( NameIndex, NameIndex, 0 );
const bool bValid = UObjectNames.Contains( LongName );
if( bValid )
{
const FString ObjectName = FStatNameAndInfo::GetShortNameFrom( LongName ).GetPlainNameString();
UObjectClass = *ObjectName.Left( ObjectName.Find( TEXT( "//" ) ) );;
UObjectCallstackToClassMapping.Add( Alloc.EncodedCallstack, UObjectClass );
break;
}
}
}
if( UObjectClass != NAME_None )
{
FSizeAndCount& SizeAndCount = UObjectAllocations.FindOrAdd( UObjectClass );
SizeAndCount.Size += Alloc.Size;
SizeAndCount.Count += 1;
TotalAllocatedMemory += Alloc.Size;
NumAllocations++;
}
}
// Dump memory to the log.
UObjectAllocations.ValueSort( FSizeAndCountGreater() );
const float MaxPctDisplayed = 0.90f;
int32 CurrentIndex = 0;
uint64 DisplayedSoFar = 0;
UE_LOG( LogStats, Warning, TEXT( "Index, Size (Size MB), Count, UObject class" ) );
for( const auto& It : UObjectAllocations )
{
const FSizeAndCount& SizeAndCount = It.Value;
const FName& UObjectClass = It.Key;
UE_LOG( LogStats, Log, TEXT( "%2i, %llu (%.2f MB), %llu, %s" ),
CurrentIndex,
SizeAndCount.Size,
SizeAndCount.Size / 1024.0f / 1024.0f,
SizeAndCount.Count,
*UObjectClass.GetPlainNameString() );
// Dump stats
MemoryReport.AddColumn( TEXT( "%llu" ), SizeAndCount.Size );
MemoryReport.AddColumn( TEXT( "%.2f MB" ), SizeAndCount.Size / 1024.0f / 1024.0f );
MemoryReport.AddColumn( TEXT( "%llu" ), SizeAndCount.Count );
MemoryReport.AddColumn( *UObjectClass.GetPlainNameString() );
MemoryReport.CycleRow();
CurrentIndex++;
DisplayedSoFar += SizeAndCount.Size;
const float CurrentPct = (float)DisplayedSoFar / (float)TotalAllocatedMemory;
if( CurrentPct > MaxPctDisplayed )
{
break;
}
}
UE_LOG( LogStats, Warning, TEXT( "Allocated memory: %llu bytes (%.2f MB)" ), TotalAllocatedMemory, TotalAllocatedMemory / 1024.0f / 1024.0f );
// Add a total row.
MemoryReport.CycleRow();
MemoryReport.CycleRow();
//.........这里部分代码省略.........
示例6: ProcessingScopedAllocations
void FStatsMemoryDumpCommand::ProcessingScopedAllocations( const TMap<uint64, FAllocationInfo>& AllocationMap )
{
// This code is not optimized.
FScopeLogTime SLT( TEXT( "ProcessingScopedAllocations" ), nullptr, FScopeLogTime::ScopeLog_Seconds );
UE_LOG( LogStats, Warning, TEXT( "Processing scoped allocations" ) );
FDiagnosticTableViewer MemoryReport( *FDiagnosticTableViewer::GetUniqueTemporaryFilePath( TEXT( "MemoryReport-Scoped" ) ) );
// Write a row of headings for the table's columns.
MemoryReport.AddColumn( TEXT( "Size (bytes)" ) );
MemoryReport.AddColumn( TEXT( "Size (MB)" ) );
MemoryReport.AddColumn( TEXT( "Count" ) );
MemoryReport.AddColumn( TEXT( "Callstack" ) );
MemoryReport.CycleRow();
TMap<FName, FSizeAndCount> ScopedAllocations;
uint64 NumAllocations = 0;
uint64 TotalAllocatedMemory = 0;
for( const auto& It : AllocationMap )
{
const FAllocationInfo& Alloc = It.Value;
FSizeAndCount& SizeAndCount = ScopedAllocations.FindOrAdd( Alloc.EncodedCallstack );
SizeAndCount.Size += Alloc.Size;
SizeAndCount.Count += 1;
TotalAllocatedMemory += Alloc.Size;
NumAllocations++;
}
// Dump memory to the log.
ScopedAllocations.ValueSort( FSizeAndCountGreater() );
const float MaxPctDisplayed = 0.90f;
int32 CurrentIndex = 0;
uint64 DisplayedSoFar = 0;
UE_LOG( LogStats, Warning, TEXT( "Index, Size (Size MB), Count, Stat desc" ) );
for( const auto& It : ScopedAllocations )
{
const FSizeAndCount& SizeAndCount = It.Value;
const FName& EncodedCallstack = It.Key;
const FString AllocCallstack = GetCallstack( EncodedCallstack );
UE_LOG( LogStats, Log, TEXT( "%2i, %llu (%.2f MB), %llu, %s" ),
CurrentIndex,
SizeAndCount.Size,
SizeAndCount.Size / 1024.0f / 1024.0f,
SizeAndCount.Count,
*AllocCallstack );
// Dump stats
MemoryReport.AddColumn( TEXT( "%llu" ), SizeAndCount.Size );
MemoryReport.AddColumn( TEXT( "%.2f MB" ), SizeAndCount.Size / 1024.0f / 1024.0f );
MemoryReport.AddColumn( TEXT( "%llu" ), SizeAndCount.Count );
MemoryReport.AddColumn( *AllocCallstack );
MemoryReport.CycleRow();
CurrentIndex++;
DisplayedSoFar += SizeAndCount.Size;
const float CurrentPct = (float)DisplayedSoFar / (float)TotalAllocatedMemory;
if( CurrentPct > MaxPctDisplayed )
{
break;
}
}
UE_LOG( LogStats, Warning, TEXT( "Allocated memory: %llu bytes (%.2f MB)" ), TotalAllocatedMemory, TotalAllocatedMemory / 1024.0f / 1024.0f );
// Add a total row.
MemoryReport.CycleRow();
MemoryReport.CycleRow();
MemoryReport.CycleRow();
MemoryReport.AddColumn( TEXT( "%llu" ), TotalAllocatedMemory );
MemoryReport.AddColumn( TEXT( "%.2f MB" ), TotalAllocatedMemory / 1024.0f / 1024.0f );
MemoryReport.AddColumn( TEXT( "%llu" ), NumAllocations );
MemoryReport.AddColumn( TEXT( "TOTAL" ) );
MemoryReport.CycleRow();
}
示例7: QueryCustomDetailLayout
void SDetailsViewBase::QueryCustomDetailLayout(FDetailLayoutBuilderImpl& CustomDetailLayout)
{
FPropertyEditorModule& ParentPlugin = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
// Get the registered classes that customize details
FCustomDetailLayoutNameMap& GlobalCustomLayoutNameMap = ParentPlugin.ClassNameToDetailLayoutNameMap;
UStruct* BaseStruct = GetBaseStruct();
// All the current customization instances need to be deleted when it is safe
CustomizationClassInstancesPendingDelete = CustomizationClassInstances;
CustomizationClassInstances.Empty();
//Ask for generic details not specific to an object being viewed
if (GenericLayoutDelegate.IsBound())
{
// Create a new instance of the custom detail layout for the current class
TSharedRef<IDetailCustomization> CustomizationInstance = GenericLayoutDelegate.Execute();
// Ask for details immediately
CustomizationInstance->CustomizeDetails(CustomDetailLayout);
// Save the instance from destruction until we refresh
CustomizationClassInstances.Add(CustomizationInstance);
}
// Sort them by query order. @todo not good enough
struct FCompareFDetailLayoutCallback
{
FORCEINLINE bool operator()(const FDetailLayoutCallback& A, const FDetailLayoutCallback& B) const
{
return A.Order < B.Order;
}
};
TMap< TWeakObjectPtr<UStruct>, FDetailLayoutCallback*> FinalCallbackMap;
for (auto ClassIt = ClassesWithProperties.CreateConstIterator(); ClassIt; ++ClassIt)
{
// Check the instanced map first
FDetailLayoutCallback* Callback = InstancedClassToDetailLayoutMap.Find(*ClassIt);
if (!Callback)
{
// callback wasn't found in the per instance map, try the global instances instead
Callback = GlobalCustomLayoutNameMap.Find((*ClassIt)->GetFName());
}
if (Callback)
{
FinalCallbackMap.Add(*ClassIt, Callback);
}
}
FinalCallbackMap.ValueSort(FCompareFDetailLayoutCallback());
TSet<UStruct*> QueriedClasses;
if (FinalCallbackMap.Num() > 0)
{
// Ask each class that we have properties for to customize its layout
for (auto LayoutIt(FinalCallbackMap.CreateConstIterator()); LayoutIt; ++LayoutIt)
{
const TWeakObjectPtr<UStruct> WeakClass = LayoutIt.Key();
if (WeakClass.IsValid())
{
UStruct* Class = WeakClass.Get();
FClassInstanceToPropertyMap& InstancedPropertyMap = ClassToPropertyMap.FindChecked(Class->GetFName());
for (FClassInstanceToPropertyMap::TIterator InstanceIt(InstancedPropertyMap); InstanceIt; ++InstanceIt)
{
FName Key = InstanceIt.Key();
CustomDetailLayout.SetCurrentCustomizationClass(CastChecked<UClass>(Class), Key);
const FOnGetDetailCustomizationInstance& DetailDelegate = LayoutIt.Value()->DetailLayoutDelegate;
if (DetailDelegate.IsBound())
{
QueriedClasses.Add(Class);
// Create a new instance of the custom detail layout for the current class
TSharedRef<IDetailCustomization> CustomizationInstance = DetailDelegate.Execute();
// Ask for details immediately
CustomizationInstance->CustomizeDetails(CustomDetailLayout);
// Save the instance from destruction until we refresh
CustomizationClassInstances.Add(CustomizationInstance);
}
}
}
}
}
// Ensure that the base class and its parents are always queried
TSet<UStruct*> ParentClassesToQuery;
//.........这里部分代码省略.........
示例8: DumpEventTree
void FGPUProfilerEventNodeFrame::DumpEventTree()
{
if (EventTree.Num() > 0)
{
float RootResult = GetRootTimingResults();
//extern ENGINE_API float GUnit_GPUFrameTime;
//UE_LOG(LogRHI, Warning, TEXT("Perf marker hierarchy, total GPU time %.2fms (%.2fms smoothed)"), RootResult * 1000.0f, GUnit_GPUFrameTime);
UE_LOG(LogRHI, Warning, TEXT("Perf marker hierarchy, total GPU time %.2fms"), RootResult * 1000.0f);
LogDisjointQuery();
TMap<FString, FGPUProfilerEventNodeStats> EventHistogram;
for (int32 BaseNodeIndex = 0; BaseNodeIndex < EventTree.Num(); BaseNodeIndex++)
{
GatherStatsEventNode(EventTree[BaseNodeIndex], 0, EventHistogram);
}
int32 NumNodes = 0;
int32 NumDraws = 0;
for (int32 BaseNodeIndex = 0; BaseNodeIndex < EventTree.Num(); BaseNodeIndex++)
{
DumpStatsEventNode(EventTree[BaseNodeIndex], RootResult, 0, NumNodes, NumDraws);
}
//@todo - calculate overhead instead of hardcoding
// This .012ms of overhead is based on what Nsight shows as the minimum draw call duration on a 580 GTX,
// Which is apparently how long it takes to issue two timing events.
UE_LOG(LogRHI, Warning, TEXT("Total Nodes %u Draws %u approx overhead %.2fms"), NumNodes, NumDraws, .012f * NumNodes);
UE_LOG(LogRHI, Warning, TEXT(""));
UE_LOG(LogRHI, Warning, TEXT(""));
// Sort descending based on node duration
EventHistogram.ValueSort( FNodeStatsCompare() );
// Log stats about the node histogram
UE_LOG(LogRHI, Warning, TEXT("Node histogram %u buckets"), EventHistogram.Num());
int32 NumNotShown = 0;
for (TMap<FString, FGPUProfilerEventNodeStats>::TIterator It(EventHistogram); It; ++It)
{
const FGPUProfilerEventNodeStats& NodeStats = It.Value();
if (NodeStats.TimingResult > RootResult * 1000.0f * .005f)
{
UE_LOG(LogRHI, Warning, TEXT(" %.2fms %s Events %u Draws %u"), NodeStats.TimingResult, *It.Key(), NodeStats.NumEvents, NodeStats.NumDraws);
}
else
{
NumNotShown++;
}
}
UE_LOG(LogRHI, Warning, TEXT(" %u buckets not shown"), NumNotShown);
#if !UE_BUILD_SHIPPING
// Create and display profile visualizer data
if (RHIConfig::ShouldShowProfilerAfterProfilingGPU())
{
// execute on main thread
{
struct FDisplayProfilerVisualizer
{
void Thread( TSharedPtr<FVisualizerEvent> InVisualizerData )
{
static FName TaskGraphModule(TEXT("TaskGraph"));
if (FModuleManager::Get().IsModuleLoaded(TaskGraphModule))
{
IProfileVisualizerModule* ProfileVisualizer = (IProfileVisualizerModule*)&FModuleManager::Get().GetModuleInterface(TaskGraphModule);
ProfileVisualizer->DisplayProfileVisualizer( InVisualizerData, TEXT("GPU") );
}
}
} DisplayProfilerVisualizer;
TSharedPtr<FVisualizerEvent> VisualizerData = CreateVisualizerData( EventTree );
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady
(
FSimpleDelegateGraphTask::FDelegate::CreateRaw(&DisplayProfilerVisualizer, &FDisplayProfilerVisualizer::Thread, VisualizerData )
, TEXT("DisplayProfilerVisualizer")
, nullptr, ENamedThreads::GameThread
);
}
}
#endif
}
}