2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-12-03 22:25:23 -05:00
# include "VisualizeTexturePresent.h"
# include "VisualizeTexture.h"
2020-09-24 00:43:27 -04:00
# include "ScreenPass.h"
2018-12-03 22:25:23 -05:00
# include "UnrealEngine.h"
2020-09-24 00:43:27 -04:00
# include "Engine/Canvas.h"
# include "Engine/Engine.h"
2018-12-03 22:25:23 -05:00
# include "RenderTargetPool.h"
// draw a single pixel sized rectangle using 4 sub elements
static void DrawBorder ( FCanvas & Canvas , const FIntRect Rect , FLinearColor Color )
{
// top
Canvas . DrawTile ( Rect . Min . X , Rect . Min . Y , Rect . Max . X - Rect . Min . X , 1 , 0 , 0 , 1 , 1 , Color ) ;
// bottom
Canvas . DrawTile ( Rect . Min . X , Rect . Max . Y - 1 , Rect . Max . X - Rect . Min . X , 1 , 0 , 0 , 1 , 1 , Color ) ;
// left
Canvas . DrawTile ( Rect . Min . X , Rect . Min . Y + 1 , 1 , Rect . Max . Y - Rect . Min . Y - 2 , 0 , 0 , 1 , 1 , Color ) ;
// right
Canvas . DrawTile ( Rect . Max . X - 1 , Rect . Min . Y + 1 , 1 , Rect . Max . Y - Rect . Min . Y - 2 , 0 , 0 , 1 , 1 , Color ) ;
}
// helper class to get a consistent layout in multiple functions
// MaxX and Y are the output value that can be requested during or after iteration
// Examples usages:
// FRenderTargetPoolEventIterator It(RenderTargetPoolEvents, OptionalStartIndex);
// while(FRenderTargetPoolEvent* Event = It.Iterate()) {}
struct FRenderTargetPoolEventIterator
{
int32 Index ;
TArray < FRenderTargetPoolEvent > & RenderTargetPoolEvents ;
bool bLineContent ;
uint32 TotalWidth ;
int32 Y ;
// constructor
FRenderTargetPoolEventIterator ( TArray < FRenderTargetPoolEvent > & InRenderTargetPoolEvents , int32 InIndex = 0 )
: Index ( InIndex )
, RenderTargetPoolEvents ( InRenderTargetPoolEvents )
, bLineContent ( false )
, TotalWidth ( 1 )
, Y ( 0 )
{
Touch ( ) ;
}
FRenderTargetPoolEvent * operator * ( )
{
if ( Index < RenderTargetPoolEvents . Num ( ) )
{
return & RenderTargetPoolEvents [ Index ] ;
}
return 0 ;
}
// @return 0 if end was reached
FRenderTargetPoolEventIterator & operator + + ( )
{
if ( Index < RenderTargetPoolEvents . Num ( ) )
{
+ + Index ;
}
Touch ( ) ;
return * this ;
}
int32 FindClosingEventY ( ) const
{
FRenderTargetPoolEventIterator It = * this ;
const ERenderTargetPoolEventType StartType = ( * It ) - > GetEventType ( ) ;
if ( StartType = = ERTPE_Alloc )
{
int32 PoolEntryId = RenderTargetPoolEvents [ Index ] . GetPoolEntryId ( ) ;
+ + It ;
// search for next Dealloc of the same PoolEntryId
for ( ; * It ; + + It )
{
FRenderTargetPoolEvent * Event = * It ;
if ( Event - > GetEventType ( ) = = ERTPE_Dealloc & & Event - > GetPoolEntryId ( ) = = PoolEntryId )
{
break ;
}
}
}
else if ( StartType = = ERTPE_Phase )
{
+ + It ;
// search for next Phase
for ( ; * It ; + + It )
{
FRenderTargetPoolEvent * Event = * It ;
if ( Event - > GetEventType ( ) = = ERTPE_Phase )
{
break ;
}
}
}
else
{
check ( 0 ) ;
}
return It . Y ;
}
private :
void Touch ( )
{
if ( Index < RenderTargetPoolEvents . Num ( ) )
{
const FRenderTargetPoolEvent & Event = RenderTargetPoolEvents [ Index ] ;
const ERenderTargetPoolEventType Type = Event . GetEventType ( ) ;
if ( Type = = ERTPE_Alloc )
{
// for now they are all equal width
TotalWidth = FMath : : Max ( TotalWidth , Event . GetColumnX ( ) + Event . GetColumnSize ( ) ) ;
}
Y = Event . GetTimeStep ( ) ;
}
}
} ;
uint32 FVisualizeTexturePresent : : ComputeEventDisplayHeight ( )
{
FRenderTargetPoolEventIterator It ( GRenderTargetPool . RenderTargetPoolEvents ) ;
2020-09-24 00:43:27 -04:00
while ( * It )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
+ + It ;
2018-12-03 22:25:23 -05:00
}
return It . Y ;
}
void FVisualizeTexturePresent : : OnStartRender ( const FViewInfo & View )
{
2020-07-06 18:58:26 -04:00
# if SUPPORTS_VISUALIZE_TEXTURE
2020-09-24 00:43:27 -04:00
GVisualizeTexture . FeatureLevel = View . GetFeatureLevel ( ) ;
GVisualizeTexture . Captured = { } ;
GVisualizeTexture . VersionCountMap . Empty ( ) ;
# endif
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
void FVisualizeTexturePresent : : PresentContent ( FRDGBuilder & GraphBuilder , const FViewInfo & View , FScreenPassRenderTarget Output )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
check ( Output . IsValid ( ) ) ;
2018-12-03 22:25:23 -05:00
if ( GRenderTargetPool . RenderTargetPoolEvents . Num ( ) )
{
FIntPoint DisplayLeftTop ( 20 , 50 ) ;
// on the right we leave more space to make the mouse tooltip readable
FIntPoint DisplayExtent ( View . ViewRect . Width ( ) - DisplayLeftTop . X * 2 - 140 , View . ViewRect . Height ( ) - DisplayLeftTop . Y * 2 ) ;
// if the area is not too small
if ( DisplayExtent . X > 50 & & DisplayExtent . Y > 50 )
{
2020-09-24 00:43:27 -04:00
AddDrawCanvasPass ( GraphBuilder , RDG_EVENT_NAME ( " RenderTargetPool " ) , View , Output , [ & View , DisplayLeftTop , DisplayExtent ] ( FCanvas & Canvas )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
FRenderTargetPool : : SMemoryStats MemoryStats = GRenderTargetPool . ComputeView ( ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
// TinyFont property
const int32 FontHeight = 12 ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
FIntPoint MousePos = View . CursorPos ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
FLinearColor BackgroundColor = FLinearColor ( 0.0f , 0.0f , 0.0f , 0.7f ) ;
FLinearColor PhaseColor = FLinearColor ( 0.2f , 0.1f , 0.05f , 0.8f ) ;
FLinearColor ElementColor = FLinearColor ( 0.3f , 0.3f , 0.3f , 0.9f ) ;
FLinearColor ElementColorVRam = FLinearColor ( 0.4f , 0.25f , 0.25f , 0.9f ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
UTexture2D * GradientTexture = UCanvas : : StaticClass ( ) - > GetDefaultObject < UCanvas > ( ) - > GradientTexture0 ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
// background rectangle
Canvas . DrawTile ( DisplayLeftTop . X , DisplayLeftTop . Y - 1 * FontHeight - 1 , DisplayExtent . X , DisplayExtent . Y + FontHeight , 0 , 0 , 1 , 1 , BackgroundColor ) ;
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
uint32 MB = 1024 * 1024 ;
uint32 MBm1 = MB - 1 ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
FString Headline = * FString : : Printf ( TEXT ( " RenderTargetPool elements(x) over time(y) >= %dKB, Displayed/Total:%d/%dMB " ) ,
GRenderTargetPool . EventRecordingSizeThreshold ,
( uint32 ) ( ( MemoryStats . DisplayedUsageInBytes + MBm1 ) / MB ) ,
( uint32 ) ( ( MemoryStats . TotalUsageInBytes + MBm1 ) / MB ) ) ;
Canvas . DrawShadowedString ( DisplayLeftTop . X , DisplayLeftTop . Y - 1 * FontHeight - 1 , * Headline , GEngine - > GetTinyFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
uint32 EventDisplayHeight = FVisualizeTexturePresent : : ComputeEventDisplayHeight ( ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
float ScaleX = DisplayExtent . X / ( float ) MemoryStats . TotalColumnSize ;
float ScaleY = DisplayExtent . Y / ( float ) EventDisplayHeight ;
// 0 if none
FRenderTargetPoolEvent * HighlightedEvent = 0 ;
FIntRect HighlightedRect ;
// Phase events
for ( FRenderTargetPoolEventIterator It ( GRenderTargetPool . RenderTargetPoolEvents ) ; * It ; + + It )
{
FRenderTargetPoolEvent * Event = * It ;
if ( Event - > GetEventType ( ) = = ERTPE_Phase )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
int32 Y0 = It . Y ;
int32 Y1 = It . FindClosingEventY ( ) ;
FIntPoint PixelLeftTop ( ( int32 ) ( DisplayLeftTop . X ) , ( int32 ) ( DisplayLeftTop . Y + ScaleY * Y0 ) ) ;
FIntPoint PixelRightBottom ( ( int32 ) ( DisplayLeftTop . X + DisplayExtent . X ) , ( int32 ) ( DisplayLeftTop . Y + ScaleY * Y1 ) ) ;
bool bHighlight = MousePos . X > = PixelLeftTop . X & & MousePos . X < PixelRightBottom . X & & MousePos . Y > = PixelLeftTop . Y & & MousePos . Y < = PixelRightBottom . Y ;
if ( bHighlight )
{
HighlightedEvent = Event ;
HighlightedRect = FIntRect ( PixelLeftTop , PixelRightBottom ) ;
}
// UMax is 0.9f to avoid getting some wrap texture leaking in at the bottom
2021-05-14 07:17:32 -04:00
Canvas . DrawTile ( PixelLeftTop . X , PixelLeftTop . Y , PixelRightBottom . X - PixelLeftTop . X , PixelRightBottom . Y - PixelLeftTop . Y , 0 , 0 , 1 , 0.9f , PhaseColor , GradientTexture - > GetResource ( ) ) ;
2018-12-03 22:25:23 -05:00
}
}
2020-09-24 00:43:27 -04:00
// Alloc / Dealloc events
for ( FRenderTargetPoolEventIterator It ( GRenderTargetPool . RenderTargetPoolEvents ) ; * It ; + + It )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
FRenderTargetPoolEvent * Event = * It ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
if ( Event - > GetEventType ( ) = = ERTPE_Alloc & & Event - > GetColumnSize ( ) )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
int32 Y0 = It . Y ;
int32 Y1 = It . FindClosingEventY ( ) ;
int32 X0 = Event - > GetColumnX ( ) ;
// for now they are all equal width
int32 X1 = X0 + Event - > GetColumnSize ( ) ;
FIntPoint PixelLeftTop ( ( int32 ) ( DisplayLeftTop . X + ScaleX * X0 ) , ( int32 ) ( DisplayLeftTop . Y + ScaleY * Y0 ) ) ;
FIntPoint PixelRightBottom ( ( int32 ) ( DisplayLeftTop . X + ScaleX * X1 ) , ( int32 ) ( DisplayLeftTop . Y + ScaleY * Y1 ) ) ;
bool bHighlight = MousePos . X > = PixelLeftTop . X & & MousePos . X < PixelRightBottom . X & & MousePos . Y > = PixelLeftTop . Y & & MousePos . Y < = PixelRightBottom . Y ;
if ( bHighlight )
{
HighlightedEvent = Event ;
HighlightedRect = FIntRect ( PixelLeftTop , PixelRightBottom ) ;
}
FLinearColor Color = ElementColor ;
// Highlight EDRAM/FastVRAM usage
2021-05-24 14:25:19 -04:00
if ( EnumHasAnyFlags ( Event - > GetDesc ( ) . Flags , TexCreate_FastVRAM ) )
2020-09-24 00:43:27 -04:00
{
Color = ElementColorVRam ;
}
Canvas . DrawTile (
PixelLeftTop . X , PixelLeftTop . Y ,
PixelRightBottom . X - PixelLeftTop . X - 1 , PixelRightBottom . Y - PixelLeftTop . Y - 1 ,
0 , 0 , 1 , 1 , Color ) ;
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
}
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
if ( HighlightedEvent )
{
DrawBorder ( Canvas , HighlightedRect , FLinearColor ( 0.8f , 0 , 0 , 0.5f ) ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
// Offset to not intersect with crosshair (in editor) or arrow (in game).
FIntPoint Pos = MousePos + FIntPoint ( 12 , 4 ) ;
if ( HighlightedEvent - > GetEventType ( ) = = ERTPE_Phase )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
FString PhaseText = * FString : : Printf ( TEXT ( " Phase: %s " ) , * HighlightedEvent - > GetPhaseName ( ) ) ;
Canvas . DrawShadowedString ( Pos . X , Pos . Y + 0 * FontHeight , * PhaseText , GEngine - > GetTinyFont ( ) , FLinearColor ( 0.5f , 0.5f , 1 ) ) ;
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
else
{
FString SizeString = FString : : Printf ( TEXT ( " %d KB " ) , ( HighlightedEvent - > GetSizeInBytes ( ) + 1024 ) / 1024 ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
Canvas . DrawShadowedString ( Pos . X , Pos . Y + 0 * FontHeight , HighlightedEvent - > GetDesc ( ) . DebugName , GEngine - > GetTinyFont ( ) , FLinearColor ( 1 , 1 , 0 ) ) ;
Canvas . DrawShadowedString ( Pos . X , Pos . Y + 1 * FontHeight , * HighlightedEvent - > GetDesc ( ) . GenerateInfoString ( ) , GEngine - > GetTinyFont ( ) , FLinearColor ( 1 , 1 , 0 ) ) ;
Canvas . DrawShadowedString ( Pos . X , Pos . Y + 2 * FontHeight , * SizeString , GEngine - > GetTinyFont ( ) , FLinearColor ( 1 , 1 , 0 ) ) ;
}
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
GRenderTargetPool . CurrentEventRecordingTime = 0 ;
GRenderTargetPool . RenderTargetPoolEvents . Empty ( ) ;
} ) ;
2018-12-03 22:25:23 -05:00
}
}
2020-09-24 00:43:27 -04:00
# if SUPPORTS_VISUALIZE_TEXTURE
FVisualizeTexture : : FCaptured & Captured = GVisualizeTexture . Captured ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
if ( ! Captured . PooledRenderTarget & & ! Captured . Texture )
2018-12-03 22:25:23 -05:00
{
// visualize feature is deactivated
return ;
}
2020-09-24 00:43:27 -04:00
// Reset bitmap flags now that we know we've saved out the bitmap we're seeing on screen.
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
using EFlags = FVisualizeTexture : : EFlags ;
EnumRemoveFlags ( GVisualizeTexture . Config . Flags , EFlags : : SaveBitmap | EFlags : : SaveBitmapAsStencil ) ;
}
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
const FPooledRenderTargetDesc & Desc = Captured . Desc ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
FRDGTextureRef VisualizeTexture2D = Captured . Texture ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
// The RDG version may be stale. The IPooledRenderTarget overrides it.
if ( Captured . PooledRenderTarget )
{
Captured . Texture = nullptr ;
VisualizeTexture2D = GraphBuilder . RegisterExternalTexture ( Captured . PooledRenderTarget , Desc . DebugName ) ;
}
RDG_EVENT_SCOPE ( GraphBuilder , " VisualizeTexture " ) ;
using EInputUVMapping = FVisualizeTexture : : EInputUVMapping ;
const EInputUVMapping InputUVMapping = VisualizeTexture2D - > Desc . IsTexture2D ( ) ? GVisualizeTexture . Config . InputUVMapping : EInputUVMapping : : Whole ;
using EInputValueMapping = FVisualizeTexture : : EInputValueMapping ;
const EInputValueMapping InputValueMapping = Captured . InputValueMapping ;
{
FScreenPassTexture CopyInput ( VisualizeTexture2D ) ;
FScreenPassRenderTarget CopyOutput = Output ;
switch ( InputUVMapping )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
case EInputUVMapping : : LeftTop :
CopyOutput . ViewRect = View . UnconstrainedViewRect ;
break ;
case EInputUVMapping : : PixelPerfectCenter :
{
FIntPoint SrcSize = CopyInput . ViewRect . Size ( ) ;
2018-12-03 22:25:23 -05:00
FIntPoint Center = View . UnconstrainedViewRect . Size ( ) / 2 ;
FIntPoint HalfMin = SrcSize / 2 ;
FIntPoint HalfMax = SrcSize - HalfMin ;
2020-09-24 00:43:27 -04:00
CopyOutput . ViewRect = FIntRect ( Center - HalfMin , Center + HalfMax ) ;
2018-12-03 22:25:23 -05:00
}
break ;
2020-09-24 00:43:27 -04:00
case EInputUVMapping : : PictureInPicture :
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
const FIntPoint CopyInputExtent = CopyInput . Texture - > Desc . Extent ;
const float CopyInputAspectRatio = float ( CopyInputExtent . X ) / float ( CopyInputExtent . Y ) ;
2018-12-03 22:25:23 -05:00
int32 TargetedHeight = 0.3f * View . UnconstrainedViewRect . Height ( ) ;
2020-09-24 00:43:27 -04:00
int32 TargetedWidth = CopyInputAspectRatio * TargetedHeight ;
2018-12-03 22:25:23 -05:00
int32 OffsetFromBorder = 100 ;
2020-09-24 00:43:27 -04:00
CopyOutput . ViewRect . Min . X = View . UnconstrainedViewRect . Min . X + OffsetFromBorder ;
CopyOutput . ViewRect . Max . X = CopyOutput . ViewRect . Min . X + TargetedWidth ;
CopyOutput . ViewRect . Max . Y = View . UnconstrainedViewRect . Max . Y - OffsetFromBorder ;
CopyOutput . ViewRect . Min . Y = CopyOutput . ViewRect . Max . Y - TargetedHeight ;
2018-12-03 22:25:23 -05:00
}
break ;
}
2020-09-24 00:43:27 -04:00
AddDrawTexturePass ( GraphBuilder , View , CopyInput , CopyOutput ) ;
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
Output . LoadAction = ERenderTargetLoadAction : : ELoad ;
2019-10-11 15:33:31 -04:00
2021-01-11 14:49:16 -04:00
const FIntPoint BufferSizeXY = GetSceneTextureExtent ( ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
AddDrawCanvasPass ( GraphBuilder , { } , View , Output ,
[ VisualizeTexture2D , BufferSizeXY , Desc , & View , InputUVMapping , InputValueMapping ] ( FCanvas & Canvas )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
float X = 100 + View . UnconstrainedViewRect . Min . X ;
float Y = 160 + View . UnconstrainedViewRect . Min . Y ;
float YStep = 14 ;
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
const uint32 VersionCount = GVisualizeTexture . GetVersionCount ( VisualizeTexture2D - > Name ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
FString ExtendedName ;
if ( VersionCount > 0 )
{
const uint32 Version = FMath : : Min ( GVisualizeTexture . Requested . Version . Get ( VersionCount ) , VersionCount - 1 ) ;
// was reused this frame
ExtendedName = FString : : Printf ( TEXT ( " %s@%d @0..%d " ) , VisualizeTexture2D - > Name , Version , VersionCount - 1 ) ;
}
else
{
// was not reused this frame but can be referenced
ExtendedName = FString : : Printf ( TEXT ( " %s " ) , VisualizeTexture2D - > Name ) ;
}
const FVisualizeTexture : : FConfig & Config = GVisualizeTexture . Config ;
FString Channels = TEXT ( " RGB " ) ;
switch ( Config . SingleChannel )
{
case 0 : Channels = TEXT ( " R " ) ; break ;
case 1 : Channels = TEXT ( " G " ) ; break ;
case 2 : Channels = TEXT ( " B " ) ; break ;
case 3 : Channels = TEXT ( " A " ) ; break ;
}
float Multiplier = ( Config . SingleChannel = = - 1 ) ? Config . RGBMul : Config . SingleChannelMul ;
FString Line = FString : : Printf ( TEXT ( " VisualizeTexture: \" %s \" %s*%g UV%d " ) ,
* ExtendedName ,
* Channels ,
Multiplier ,
InputUVMapping ) ;
Canvas . DrawShadowedString ( X , Y + = YStep , * Line , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
{
FString Line = FString : : Printf ( TEXT ( " TextureInfoString(): %s " ) , * ( Desc . GenerateInfoString ( ) ) ) ;
Canvas . DrawShadowedString ( X + 10 , Y + = YStep , * Line , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
{
FString Line = FString : : Printf ( TEXT ( " BufferSize:(%d,%d) " ) , BufferSizeXY . X , BufferSizeXY . Y ) ;
Canvas . DrawShadowedString ( X + 10 , Y + = YStep , * Line , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
const FSceneViewFamily & ViewFamily = * View . Family ;
for ( int32 ViewId = 0 ; ViewId < ViewFamily . Views . Num ( ) ; + + ViewId )
{
const FViewInfo * ViewIt = static_cast < const FViewInfo * > ( ViewFamily . Views [ ViewId ] ) ;
FString Line = FString : : Printf ( TEXT ( " View #%d: (%d,%d)-(%d,%d) " ) , ViewId + 1 ,
ViewIt - > UnscaledViewRect . Min . X , ViewIt - > UnscaledViewRect . Min . Y , ViewIt - > UnscaledViewRect . Max . X , ViewIt - > UnscaledViewRect . Max . Y ) ;
Canvas . DrawShadowedString ( X + 10 , Y + = YStep , * Line , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
X + = 40 ;
2021-05-24 14:25:19 -04:00
if ( EnumHasAnyFlags ( Desc . Flags , TexCreate_CPUReadback ) )
2020-09-24 00:43:27 -04:00
{
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Content cannot be visualized on the GPU (TexCreate_CPUReadback) " ) , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 0 ) ) ;
2018-12-03 22:25:23 -05:00
}
else
{
2020-09-24 00:43:27 -04:00
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Blinking Red: <0 " ) , GetStatsFont ( ) , FLinearColor ( 1 , 0 , 0 ) ) ;
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Blinking Blue: NAN or Inf " ) , GetStatsFont ( ) , FLinearColor ( 0 , 0 , 1 ) ) ;
2018-12-03 22:25:23 -05:00
2020-09-24 00:43:27 -04:00
if ( InputValueMapping = = EInputValueMapping : : Shadow )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Color Key: Linear with white near and teal distant " ) , GetStatsFont ( ) , FLinearColor ( 54.f / 255.f , 117.f / 255.f , 136.f / 255.f ) ) ;
2018-12-03 22:25:23 -05:00
}
2020-09-24 00:43:27 -04:00
else if ( InputValueMapping = = EInputValueMapping : : Depth )
2018-12-03 22:25:23 -05:00
{
2020-09-24 00:43:27 -04:00
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Color Key: Nonlinear with white distant " ) , GetStatsFont ( ) , FLinearColor ( 0.5 , 0 , 0 ) ) ;
2018-12-03 22:25:23 -05:00
}
}
2020-09-24 00:43:27 -04:00
} ) ;
# endif
}