2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
VisualizeTexture . cpp : Post processing visualize texture .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "RendererPrivate.h"
# include "ScenePrivate.h"
# include "ScreenRendering.h"
# include "SceneFilterRendering.h"
# include "VisualizeTexture.h"
# include "PostProcessing.h"
# include "PostProcessWeightedSampleSum.h"
2014-08-21 06:03:00 -04:00
# include "SceneUtils.h"
2014-03-14 14:13:41 -04:00
/** A pixel shader which filters a texture. */
// @param TextureType 0:Cube, 1:1D(not yet supported), 2:2D, 3:3D, 4:Cube[], 5:2D MSAA
template < uint32 TextureType >
class VisualizeTexturePS : public FGlobalShader
{
DECLARE_SHADER_TYPE ( VisualizeTexturePS , Global ) ;
public :
static bool ShouldCache ( EShaderPlatform Platform )
{
2014-09-12 17:21:49 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
static void ModifyCompilationEnvironment ( EShaderPlatform Platform , FShaderCompilerEnvironment & OutEnvironment )
{
FGlobalShader : : ModifyCompilationEnvironment ( Platform , OutEnvironment ) ;
OutEnvironment . SetDefine ( TEXT ( " TEXTURE_TYPE " ) , TextureType ) ;
}
/** Default constructor. */
VisualizeTexturePS ( ) { }
/** Initialization constructor. */
VisualizeTexturePS ( const ShaderMetaType : : CompiledShaderInitializerType & Initializer ) :
FGlobalShader ( Initializer )
{
VisualizeTexture2D . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture2D " ) ) ;
VisualizeDepthStencilTexture . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeDepthStencilTexture " ) ) ;
VisualizeTexture2DSampler . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture2DSampler " ) ) ;
VisualizeTexture2DMS . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture2DMS " ) ) ;
VisualizeTexture3D . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture3D " ) ) ;
VisualizeTexture3DSampler . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture3DSampler " ) ) ;
VisualizeTextureCube . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTextureCube " ) ) ;
VisualizeTextureCubeSampler . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTextureCubeSampler " ) ) ;
VisualizeTextureCubeArray . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTextureCubeArray " ) ) ;
VisualizeTextureCubeArraySampler . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTextureCubeArraySampler " ) ) ;
VisualizeParam . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeParam " ) ) ;
TextureExtent . Bind ( Initializer . ParameterMap , TEXT ( " TextureExtent " ) ) ;
}
/** Serializer */
virtual bool Serialize ( FArchive & Ar )
{
bool bShaderHasOutdatedParameters = FGlobalShader : : Serialize ( Ar ) ;
Ar < < VisualizeTexture2D ;
Ar < < VisualizeDepthStencilTexture ;
Ar < < VisualizeTexture2DSampler ;
Ar < < VisualizeTexture2DMS ;
Ar < < VisualizeTexture3D ;
Ar < < VisualizeTexture3DSampler ;
Ar < < VisualizeTextureCube ;
Ar < < VisualizeTextureCubeSampler ;
Ar < < VisualizeTextureCubeArray ;
Ar < < VisualizeTextureCubeArraySampler ;
Ar < < VisualizeParam ;
Ar < < TextureExtent ;
return bShaderHasOutdatedParameters ;
}
2014-06-10 07:29:49 -04:00
void SetParameters ( FRHICommandList & RHICmdList , const FVisualizeTextureData & Data )
2014-03-14 14:13:41 -04:00
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader ( ) ;
{
// alternates between 0 and 1 with a short pause
const float FracTimeScale = 2.0f ;
2014-04-23 18:12:58 -04:00
float FracTime = FApp : : GetCurrentTime ( ) * FracTimeScale - floor ( FApp : : GetCurrentTime ( ) * FracTimeScale ) ;
2014-03-14 14:13:41 -04:00
float BlinkState = ( FracTime > 0.5f ) ? 1.0f : 0.0f ;
FVector4 VisualizeParamValue [ 3 ] ;
float Add = 0.0f ;
float FracScale = 1.0f ;
// w * almost_1 to avoid frac(1) => 0
VisualizeParamValue [ 0 ] = FVector4 ( Data . RGBMul , Data . AMul , Add , FracScale * 0.9999f ) ;
VisualizeParamValue [ 1 ] = FVector4 ( BlinkState , Data . bSaturateInsteadOfFrac ? 1.0f : 0.0f , Data . ArrayIndex , Data . CustomMip ) ;
VisualizeParamValue [ 2 ] = FVector4 ( Data . InputValueMapping , 0 , 0 , 0 ) ;
2014-06-05 16:38:54 -04:00
SetShaderValueArray ( RHICmdList , ShaderRHI , VisualizeParam , VisualizeParamValue , 3 ) ;
2014-03-14 14:13:41 -04:00
}
{
FVector4 TextureExtentValue ( Data . Desc . Extent . X , Data . Desc . Extent . Y , Data . Desc . Depth , 0 ) ;
2014-06-05 16:38:54 -04:00
SetShaderValue ( RHICmdList , ShaderRHI , TextureExtent , TextureExtentValue ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-05 16:38:54 -04:00
SetSRVParameter ( RHICmdList , ShaderRHI , VisualizeDepthStencilTexture , Data . StencilSRV ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTexture2D , VisualizeTexture2DSampler , TStaticSamplerState < SF_Point , AM_Clamp , AM_Clamp , AM_Clamp > : : GetRHI ( ) , ( FTextureRHIRef & ) Data . RenderTargetItem . ShaderResourceTexture ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTexture2DMS , ( FTextureRHIRef & ) Data . RenderTargetItem . TargetableTexture ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTexture3D , VisualizeTexture3DSampler , TStaticSamplerState < SF_Point , AM_Clamp , AM_Clamp , AM_Clamp > : : GetRHI ( ) , ( FTextureRHIRef & ) Data . RenderTargetItem . ShaderResourceTexture ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTextureCube , VisualizeTextureCubeSampler , TStaticSamplerState < SF_Point , AM_Clamp , AM_Clamp , AM_Clamp > : : GetRHI ( ) , ( FTextureRHIRef & ) Data . RenderTargetItem . ShaderResourceTexture ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTextureCubeArray , VisualizeTextureCubeArraySampler , TStaticSamplerState < SF_Point , AM_Clamp , AM_Clamp , AM_Clamp > : : GetRHI ( ) , ( FTextureRHIRef & ) Data . RenderTargetItem . ShaderResourceTexture ) ;
2014-03-14 14:13:41 -04:00
}
static const TCHAR * GetSourceFilename ( )
{
return TEXT ( " VisualizeTexture " ) ;
}
static const TCHAR * GetFunctionName ( )
{
return TEXT ( " VisualizeTexturePS " ) ;
}
protected :
FShaderResourceParameter VisualizeTexture2D ;
FShaderResourceParameter VisualizeDepthStencilTexture ;
FShaderResourceParameter VisualizeTexture2DSampler ;
FShaderResourceParameter VisualizeTexture2DMS ;
FShaderResourceParameter VisualizeTexture3D ;
FShaderResourceParameter VisualizeTexture3DSampler ;
FShaderResourceParameter VisualizeTextureCube ;
FShaderResourceParameter VisualizeTextureCubeSampler ;
FShaderResourceParameter VisualizeTextureCubeArray ;
FShaderResourceParameter VisualizeTextureCubeArraySampler ;
FShaderParameter VisualizeParam ;
FShaderParameter TextureExtent ;
} ;
// #define avoids a lot of code duplication
# define VARIATION1(A) typedef VisualizeTexturePS<A> VisualizeTexturePS##A; \
IMPLEMENT_SHADER_TYPE2 ( VisualizeTexturePS # # A , SF_Pixel ) ;
VARIATION1 ( 0 ) VARIATION1 ( 2 ) VARIATION1 ( 3 ) VARIATION1 ( 4 ) VARIATION1 ( 5 )
# undef VARIATION1
/** Encapsulates a simple copy pixel shader. */
class FVisualizeTexturePresentPS : public FGlobalShader
{
DECLARE_SHADER_TYPE ( FVisualizeTexturePresentPS , Global ) ;
static bool ShouldCache ( EShaderPlatform Platform )
{
2014-09-12 17:21:49 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
/** Default constructor. */
FVisualizeTexturePresentPS ( ) { }
public :
FShaderResourceParameter VisualizeTexture2D ;
FShaderResourceParameter VisualizeTexture2DSampler ;
/** Initialization constructor. */
FVisualizeTexturePresentPS ( const ShaderMetaType : : CompiledShaderInitializerType & Initializer )
: FGlobalShader ( Initializer )
{
VisualizeTexture2D . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture2D " ) ) ;
VisualizeTexture2DSampler . Bind ( Initializer . ParameterMap , TEXT ( " VisualizeTexture2DSampler " ) ) ;
}
// FShader interface.
virtual bool Serialize ( FArchive & Ar )
{
bool bShaderHasOutdatedParameters = FGlobalShader : : Serialize ( Ar ) ;
Ar < < VisualizeTexture2D < < VisualizeTexture2DSampler ;
return bShaderHasOutdatedParameters ;
}
2014-06-10 07:29:49 -04:00
void SetParameters ( FRHICommandList & RHICmdList , const FSceneView & View , const IPooledRenderTarget & Src )
2014-03-14 14:13:41 -04:00
{
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader ( ) ;
2014-06-05 16:38:54 -04:00
FGlobalShader : : SetParameters ( RHICmdList , ShaderRHI , View ) ;
SetTextureParameter ( RHICmdList , ShaderRHI , VisualizeTexture2D , VisualizeTexture2DSampler ,
2014-03-14 14:13:41 -04:00
TStaticSamplerState < SF_Point , AM_Clamp , AM_Clamp , AM_Clamp > : : GetRHI ( ) , ( FTextureRHIRef & ) Src . GetRenderTargetItem ( ) . ShaderResourceTexture ) ;
}
} ;
IMPLEMENT_SHADER_TYPE ( , FVisualizeTexturePresentPS , TEXT ( " VisualizeTexture " ) , TEXT ( " PresentPS " ) , SF_Pixel ) ;
2014-08-19 10:41:34 -04:00
template < uint32 TextureType > void VisualizeTextureForTextureType ( FRHICommandList & RHICmdList , ERHIFeatureLevel : : Type FeatureLevel , const FVisualizeTextureData & Data )
2014-03-14 14:13:41 -04:00
{
2014-08-28 06:22:54 -04:00
auto ShaderMap = GetGlobalShaderMap ( FeatureLevel ) ;
TShaderMapRef < FScreenVS > VertexShader ( ShaderMap ) ;
TShaderMapRef < VisualizeTexturePS < TextureType > > PixelShader ( ShaderMap ) ;
2014-03-14 14:13:41 -04:00
static FGlobalBoundShaderState BoundShaderState ;
2014-06-27 11:07:13 -04:00
2014-06-12 07:13:34 -04:00
2014-08-19 10:41:34 -04:00
SetGlobalBoundShaderState ( RHICmdList , FeatureLevel , BoundShaderState , GFilterVertexDeclaration . VertexDeclarationRHI , * VertexShader , * PixelShader ) ;
2014-06-05 16:38:54 -04:00
PixelShader - > SetParameters ( RHICmdList , Data ) ;
2014-03-14 14:13:41 -04:00
DrawRectangle (
2014-06-12 07:13:34 -04:00
RHICmdList ,
2014-03-14 14:13:41 -04:00
// XY
0 , 0 ,
// SizeXY
GSceneRenderTargets . GetBufferSizeXY ( ) . X , GSceneRenderTargets . GetBufferSizeXY ( ) . Y ,
// UV
Data . Tex00 . X , Data . Tex00 . Y ,
// SizeUV
Data . Tex11 . X - Data . Tex00 . X , Data . Tex11 . Y - Data . Tex00 . Y ,
// TargetSize
GSceneRenderTargets . GetBufferSizeXY ( ) ,
// TextureSize
FIntPoint ( 1 , 1 ) ,
2014-04-23 17:26:59 -04:00
* VertexShader ,
2014-03-14 14:13:41 -04:00
EDRF_UseTriangleOptimization ) ;
}
2014-08-19 10:41:34 -04:00
void RenderVisualizeTexture ( FRHICommandListImmediate & RHICmdList , ERHIFeatureLevel : : Type FeatureLevel , const FVisualizeTextureData & Data )
2014-03-14 14:13:41 -04:00
{
if ( Data . Desc . Is2DTexture ( ) )
{
// 2D
if ( Data . Desc . NumSamples > 1 )
{
// MSAA
2014-08-19 10:41:34 -04:00
VisualizeTextureForTextureType < 5 > ( RHICmdList , FeatureLevel , Data ) ;
2014-03-14 14:13:41 -04:00
}
else
{
// non MSAA
2014-08-19 10:41:34 -04:00
VisualizeTextureForTextureType < 2 > ( RHICmdList , FeatureLevel , Data ) ;
2014-03-14 14:13:41 -04:00
}
}
else if ( Data . Desc . Is3DTexture ( ) )
{
// Volume
2014-08-19 10:41:34 -04:00
VisualizeTextureForTextureType < 3 > ( RHICmdList , FeatureLevel , Data ) ;
2014-03-14 14:13:41 -04:00
}
else if ( Data . Desc . IsCubemap ( ) )
{
if ( Data . Desc . IsArray ( ) )
{
// Cube[]
2014-08-19 10:41:34 -04:00
VisualizeTextureForTextureType < 4 > ( RHICmdList , FeatureLevel , Data ) ;
2014-03-14 14:13:41 -04:00
}
else
{
// Cube
2014-08-19 10:41:34 -04:00
VisualizeTextureForTextureType < 0 > ( RHICmdList , FeatureLevel , Data ) ;
2014-03-14 14:13:41 -04:00
}
}
}
FVisualizeTexture : : FVisualizeTexture ( )
{
Mode = 0 ;
RGBMul = 1.0f ;
AMul = 0.0f ;
UVInputMapping = 3 ;
Flags = 0 ;
ObservedDebugNameReusedGoal = 0xffffffff ;
ArrayIndex = 0 ;
CustomMip = 0 ;
bSaveBitmap = false ;
bOutputStencil = false ;
bFullList = false ;
SortOrder = - 1 ;
2014-05-08 09:05:50 -04:00
bEnabled = true ;
2014-03-14 14:13:41 -04:00
}
FIntRect FVisualizeTexture : : ComputeVisualizeTextureRect ( FIntPoint InputTextureSize ) const
{
FIntRect ret = ViewRect ;
FIntPoint ViewExtent = ViewRect . Size ( ) ;
// set ViewRect
switch ( UVInputMapping )
{
// pixel perfect centered (not yet for volume textures)
case 2 :
{
FIntPoint Center = ViewExtent / 2 ;
FIntPoint HalfMin = InputTextureSize / 2 ;
FIntPoint HalfMax = InputTextureSize - HalfMin ;
ret = FIntRect ( Center - HalfMin , Center + HalfMax ) ;
2014-05-07 09:49:28 -04:00
break ;
2014-03-14 14:13:41 -04:00
}
// whole texture in PIP
case 3 :
2014-05-07 09:49:28 -04:00
{
int32 LeftOffset = AspectRatioConstrainedViewRect . Min . X ;
int32 BottomOffset = AspectRatioConstrainedViewRect . Max . Y - ViewRect . Max . Y ;
ret = FIntRect ( LeftOffset + 80 , ViewExtent . Y - ViewExtent . Y / 3 - 10 + BottomOffset , ViewExtent . X / 3 + 10 , ViewExtent . Y - 10 + BottomOffset ) + ViewRect . Min ;
2014-03-14 14:13:41 -04:00
break ;
2014-05-07 09:49:28 -04:00
}
2014-03-14 14:13:41 -04:00
default :
2014-05-07 09:49:28 -04:00
{
2014-03-14 14:13:41 -04:00
break ;
2014-05-07 09:49:28 -04:00
}
2014-03-14 14:13:41 -04:00
}
return ret ;
}
2014-06-27 11:07:13 -04:00
void FVisualizeTexture : : GenerateContent ( FRHICommandListImmediate & RHICmdList , const FSceneRenderTargetItem & RenderTargetItem , const FPooledRenderTargetDesc & Desc )
2014-03-14 14:13:41 -04:00
{
// otherwise StartFrame() wasn't called
check ( ViewRect ! = FIntRect ( 0 , 0 , 0 , 0 ) )
2014-06-12 07:13:34 -04:00
2014-03-14 14:13:41 -04:00
FTexture2DRHIRef VisTexture = ( FTexture2DRHIRef & ) RenderTargetItem . ShaderResourceTexture ;
if ( ! IsValidRef ( VisTexture ) | | ! Desc . IsValid ( ) )
{
// todo: improve
return ;
}
FIntRect VisualizeTextureRect = ComputeVisualizeTextureRect ( Desc . Extent ) ;
FIntPoint Size = VisualizeTextureRect . Size ( ) ;
// clamp to reasonable value to prevent crash
Size . X = FMath : : Max ( Size . X , 1 ) ;
Size . Y = FMath : : Max ( Size . Y , 1 ) ;
FPooledRenderTargetDesc OutputDesc ( FPooledRenderTargetDesc : : Create2DDesc ( Size , PF_B8G8R8A8 , TexCreate_None , TexCreate_RenderTargetable | TexCreate_ShaderResource , false ) ) ;
GRenderTargetPool . FindFreeElement ( OutputDesc , VisualizeTextureContent , TEXT ( " VisualizeTexture " ) ) ;
if ( ! VisualizeTextureContent )
{
return ;
}
const FSceneRenderTargetItem & DestRenderTarget = VisualizeTextureContent - > GetRenderTargetItem ( ) ;
2014-06-12 07:13:34 -04:00
SetRenderTarget ( RHICmdList , DestRenderTarget . TargetableTexture , FTextureRHIRef ( ) ) ;
RHICmdList . Clear ( true , FLinearColor ( 1 , 1 , 0 , 1 ) , false , 0.0f , false , 0 , FIntRect ( ) ) ;
RHICmdList . SetBlendState ( TStaticBlendState < > : : GetRHI ( ) ) ;
RHICmdList . SetRasterizerState ( TStaticRasterizerState < > : : GetRHI ( ) ) ;
RHICmdList . SetDepthStencilState ( TStaticDepthStencilState < false , CF_Always > : : GetRHI ( ) ) ;
2014-03-14 14:13:41 -04:00
FIntPoint RTExtent = GSceneRenderTargets . GetBufferSizeXY ( ) ;
FVector2D Tex00 = FVector2D ( 0 , 0 ) ;
FVector2D Tex11 = FVector2D ( 1 , 1 ) ;
uint32 LocalVisualizeTextureInputMapping = UVInputMapping ;
if ( ! Desc . Is2DTexture ( ) )
{
LocalVisualizeTextureInputMapping = 1 ;
}
// set UV
switch ( LocalVisualizeTextureInputMapping )
{
// UV in left top
case 0 :
Tex11 = FVector2D ( ( float ) ViewRect . Width ( ) / RTExtent . X , ( float ) ViewRect . Height ( ) / RTExtent . Y ) ;
break ;
// whole texture
default :
break ;
}
bool bIsDefault = StencilSRVSrc = = GBlackTexture - > TextureRHI ;
bool bDepthStencil = Desc . Is2DTexture ( ) & & Desc . Format = = PF_DepthStencil ;
//clear if this is a new different Stencil buffer, or it's not a stencil buffer and we haven't switched to the default yet.
bool bNeedsClear = bDepthStencil & & ( StencilSRVSrc ! = RenderTargetItem . TargetableTexture ) ;
bNeedsClear | = ! bDepthStencil & & ! bIsDefault ;
if ( bNeedsClear )
{
StencilSRVSrc = nullptr ;
StencilSRV . SafeRelease ( ) ;
}
//always set something into the StencilSRV slot for platforms that require a full resource binding, even if
//dynamic branching will cause them not to be used.
if ( bDepthStencil & & ! StencilSRVSrc )
{
StencilSRVSrc = RenderTargetItem . TargetableTexture ;
StencilSRV = RHICreateShaderResourceView ( ( FTexture2DRHIRef & ) RenderTargetItem . TargetableTexture , 0 , 1 , PF_X24_G8 ) ;
}
else if ( ! StencilSRVSrc )
{
StencilSRVSrc = GBlackTexture - > TextureRHI ;
StencilSRV = RHICreateShaderResourceView ( ( FTexture2DRHIRef & ) GBlackTexture - > TextureRHI , 0 , 1 , PF_B8G8R8A8 ) ;
}
FVisualizeTextureData VisualizeTextureData ( RenderTargetItem , Desc ) ;
bool bDepthTexture = ( Desc . TargetableFlags & TexCreate_DepthStencilTargetable ) ! = 0 ;
VisualizeTextureData . RGBMul = RGBMul ;
VisualizeTextureData . AMul = AMul ;
VisualizeTextureData . Tex00 = Tex00 ;
VisualizeTextureData . Tex11 = Tex11 ;
VisualizeTextureData . bSaturateInsteadOfFrac = ( Flags & 1 ) ! = 0 ;
VisualizeTextureData . InputValueMapping = bDepthTexture ? 1 : 0 ;
VisualizeTextureData . ArrayIndex = ArrayIndex ;
VisualizeTextureData . CustomMip = CustomMip ;
VisualizeTextureData . StencilSRV = StencilSRV ;
2014-04-02 18:09:23 -04:00
if ( ! ( Desc . Flags & TexCreate_CPUReadback ) ) // We cannot make a texture lookup on such elements
2014-03-14 14:13:41 -04:00
{
2014-09-11 09:38:38 -04:00
SCOPED_DRAW_EVENT ( RHICmdList , VisualizeTexture , DEC_SCENE_ITEMS ) ;
2014-03-14 14:13:41 -04:00
// continue rendering to HDR if necessary
2014-08-19 10:41:34 -04:00
RenderVisualizeTexture ( RHICmdList , FeatureLevel , VisualizeTextureData ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-08 16:16:23 -04:00
{
2014-09-11 09:38:38 -04:00
SCOPED_DRAW_EVENT ( RHICmdList , VisCopy , DEC_SCENE_ITEMS ) ;
2014-08-08 16:16:23 -04:00
RHICmdList . CopyToResolveTarget ( DestRenderTarget . TargetableTexture , DestRenderTarget . ShaderResourceTexture , false , FResolveParams ( ) ) ;
}
2014-03-14 14:13:41 -04:00
VisualizeTextureDesc = Desc ;
// save to disk
if ( bSaveBitmap )
{
bSaveBitmap = false ;
uint32 MipAdjustedExtentX = FMath : : Clamp ( Desc . Extent . X > > CustomMip , 0 , Desc . Extent . X ) ;
uint32 MipAdjustedExtentY = FMath : : Clamp ( Desc . Extent . Y > > CustomMip , 0 , Desc . Extent . Y ) ;
FIntPoint Extent ( MipAdjustedExtentX , MipAdjustedExtentY ) ;
FReadSurfaceDataFlags ReadDataFlags ;
ReadDataFlags . SetLinearToGamma ( false ) ;
ReadDataFlags . SetOutputStencil ( bOutputStencil ) ;
ReadDataFlags . SetMip ( CustomMip ) ;
FTextureRHIRef Texture = RenderTargetItem . TargetableTexture ? RenderTargetItem . TargetableTexture : RenderTargetItem . ShaderResourceTexture ;
check ( Texture ) ;
TArray < FColor > Bitmap ;
2014-06-27 11:07:13 -04:00
RHICmdList . ReadSurfaceData ( Texture , FIntRect ( 0 , 0 , Extent . X , Extent . Y ) , Bitmap , ReadDataFlags ) ;
2014-03-14 14:13:41 -04:00
// if the format and texture type is supported
if ( Bitmap . Num ( ) )
{
// Create screenshot folder if not already present.
IFileManager : : Get ( ) . MakeDirectory ( * FPaths : : ScreenShotDir ( ) , true ) ;
const FString ScreenFileName ( FPaths : : ScreenShotDir ( ) / TEXT ( " VisualizeTexture " ) ) ;
uint32 ExtendXWithMSAA = Bitmap . Num ( ) / Extent . Y ;
// Save the contents of the array to a bitmap file. (24bit only so alpha channel is dropped)
FFileHelper : : CreateBitmap ( * ScreenFileName , ExtendXWithMSAA , Extent . Y , Bitmap . GetTypedData ( ) ) ;
UE_LOG ( LogConsoleResponse , Display , TEXT ( " Content was saved to \" %s \" " ) , * FPaths : : ScreenShotDir ( ) ) ;
}
else
{
UE_LOG ( LogConsoleResponse , Error , TEXT ( " Failed to save BMP for VisualizeTexture, format or texture type is not supported " ) ) ;
}
}
}
2014-08-28 06:22:54 -04:00
void FVisualizeTexture : : PresentContent ( FRHICommandListImmediate & RHICmdList , const FViewInfo & View )
2014-03-14 14:13:41 -04:00
{
if ( Mode ! = 0 )
{
// old mode is used, lets copy the specified texture to do it similar to the new system
FPooledRenderTarget * Element = GRenderTargetPool . GetElementById ( Mode - 1 ) ;
if ( Element )
{
2014-06-12 07:13:34 -04:00
GenerateContent ( RHICmdList , Element - > GetRenderTargetItem ( ) , Element - > GetDesc ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
const FTexture2DRHIRef & RenderTargetTexture = View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
if ( ! VisualizeTextureContent
| | ! IsValidRef ( RenderTargetTexture )
2014-05-08 09:05:50 -04:00
| | ! bEnabled )
2014-03-14 14:13:41 -04:00
{
// visualize feature is deactivated
return ;
}
FPooledRenderTargetDesc Desc = VisualizeTextureDesc ;
2014-04-23 19:08:42 -04:00
auto & RenderTarget = View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
2014-06-12 07:13:34 -04:00
SetRenderTarget ( RHICmdList , RenderTarget , FTextureRHIRef ( ) ) ;
RHICmdList . SetViewport ( 0 , 0 , 0.0f , RenderTarget - > GetSizeX ( ) , RenderTarget - > GetSizeY ( ) , 1.0f ) ;
2014-03-14 14:13:41 -04:00
2014-06-12 07:13:34 -04:00
RHICmdList . SetBlendState ( TStaticBlendState < > : : GetRHI ( ) ) ;
RHICmdList . SetRasterizerState ( TStaticRasterizerState < > : : GetRHI ( ) ) ;
RHICmdList . SetDepthStencilState ( TStaticDepthStencilState < false , CF_Always > : : GetRHI ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-28 06:22:54 -04:00
auto ShaderMap = View . ShaderMap ;
TShaderMapRef < FPostProcessVS > VertexShader ( ShaderMap ) ;
TShaderMapRef < FVisualizeTexturePresentPS > PixelShader ( ShaderMap ) ;
2014-03-14 14:13:41 -04:00
static FGlobalBoundShaderState BoundShaderState ;
2014-06-27 11:07:13 -04:00
2014-03-14 14:13:41 -04:00
2014-08-19 10:41:34 -04:00
SetGlobalBoundShaderState ( RHICmdList , FeatureLevel , BoundShaderState , GFilterVertexDeclaration . VertexDeclarationRHI , * VertexShader , * PixelShader ) ;
2014-03-14 14:13:41 -04:00
2014-06-05 16:38:54 -04:00
VertexShader - > SetParameters ( RHICmdList , View ) ;
PixelShader - > SetParameters ( RHICmdList , View , * VisualizeTextureContent ) ;
2014-03-14 14:13:41 -04:00
FIntRect DestRect = View . ViewRect ;
FIntRect VisualizeTextureRect = ComputeVisualizeTextureRect ( Desc . Extent ) ;
2014-08-08 16:16:23 -04:00
{
2014-09-11 09:38:38 -04:00
SCOPED_DRAW_EVENT ( RHICmdList , VisCopyToMain , DEC_SCENE_ITEMS ) ;
2014-08-08 16:16:23 -04:00
// Draw a quad mapping scene color to the view's render target
DrawRectangle (
RHICmdList ,
VisualizeTextureRect . Min . X , VisualizeTextureRect . Min . Y ,
VisualizeTextureRect . Width ( ) , VisualizeTextureRect . Height ( ) ,
0 , 0 ,
VisualizeTextureRect . Width ( ) , VisualizeTextureRect . Height ( ) ,
FIntPoint ( RenderTarget - > GetSizeX ( ) , RenderTarget - > GetSizeY ( ) ) ,
VisualizeTextureRect . Size ( ) ,
* VertexShader ,
EDRF_Default ) ;
}
2014-03-14 14:13:41 -04:00
// this is a helper class for FCanvas to be able to get screen size
class FRenderTargetTemp : public FRenderTarget
{
public :
const FSceneView & View ;
FRenderTargetTemp ( const FSceneView & InView ) : View ( InView )
{
}
virtual FIntPoint GetSizeXY ( ) const
{
return View . UnscaledViewRect . Size ( ) ;
} ;
virtual const FTexture2DRHIRef & GetRenderTargetTexture ( ) const
{
return View . Family - > RenderTarget - > GetRenderTargetTexture ( ) ;
}
} TempRenderTarget ( View ) ;
2014-08-19 10:41:34 -04:00
FCanvas Canvas ( & TempRenderTarget , NULL , View . Family - > CurrentRealTime , View . Family - > CurrentWorldTime , View . Family - > DeltaWorldTime , View . GetFeatureLevel ( ) ) ;
2014-03-14 14:13:41 -04:00
float X = 100 + View . ViewRect . Min . X ;
float Y = 160 + View . ViewRect . Min . Y ;
float YStep = 14 ;
{
uint32 ReuseCount = ObservedDebugNameReusedCurrent ;
FString ExtendedName ;
if ( ReuseCount )
{
uint32 ReuseGoal = FMath : : Min ( ReuseCount - 1 , ObservedDebugNameReusedGoal ) ;
// was reused this frame
ExtendedName = FString : : Printf ( TEXT ( " %s@%d @0..%d " ) , Desc . DebugName , ReuseGoal , ReuseCount - 1 ) ;
}
else
{
// was not reused this frame but can be referenced
ExtendedName = FString : : Printf ( TEXT ( " %s " ) , Desc . DebugName ) ;
}
FString Line = FString : : Printf ( TEXT ( " VisualizeTexture: %d \" %s \" RGB*%g+A*%g UV%d " ) ,
Mode ,
* ExtendedName ,
RGBMul ,
AMul ,
UVInputMapping ) ;
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) " ) , GSceneRenderTargets . GetBufferSizeXY ( ) . X , GSceneRenderTargets . GetBufferSizeXY ( ) . 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 FSceneView & ViewIt = * ViewFamily . Views [ ViewId ] ;
FString Line = FString : : Printf ( TEXT ( " View #%d: (%d,%d)-(%d,%d) " ) , ViewId + 1 ,
ViewIt . ViewRect . Min . X , ViewIt . ViewRect . Min . Y , ViewIt . ViewRect . Max . X , ViewIt . ViewRect . Max . Y ) ;
Canvas . DrawShadowedString ( X + 10 , Y + = YStep , * Line , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 1 ) ) ;
}
X + = 40 ;
2014-04-02 18:09:23 -04:00
if ( Desc . Flags & TexCreate_CPUReadback )
{
Canvas . DrawShadowedString ( X , Y + = YStep , TEXT ( " Content cannot be visualized on the GPU (TexCreate_CPUReadback) " ) , GetStatsFont ( ) , FLinearColor ( 1 , 1 , 0 ) ) ;
}
else
{
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 ) ) ;
}
2014-07-02 14:13:59 -04:00
Canvas . Flush_RenderThread ( RHICmdList ) ;
2014-03-14 14:13:41 -04:00
}
void FVisualizeTexture : : SetObserveTarget ( const FString & InObservedDebugName , uint32 InObservedDebugNameReusedGoal )
{
ObservedDebugName = InObservedDebugName ;
ObservedDebugNameReusedGoal = InObservedDebugNameReusedGoal ;
}
2014-08-04 12:04:27 -04:00
void FVisualizeTexture : : SetCheckPoint ( FRHICommandList & RHICmdList , const IPooledRenderTarget * PooledRenderTarget )
2014-03-14 14:13:41 -04:00
{
2014-06-27 11:07:13 -04:00
2014-03-14 14:13:41 -04:00
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
2014-08-04 12:04:27 -04:00
check ( IsInRenderingThread ( ) ) ;
2014-05-08 09:05:50 -04:00
if ( ! PooledRenderTarget | | ! bEnabled )
2014-03-14 14:13:41 -04:00
{
// Don't checkpoint on ES2 to avoid TMap alloc/reallocations
return ;
}
const FSceneRenderTargetItem & RenderTargetItem = PooledRenderTarget - > GetRenderTargetItem ( ) ;
const FPooledRenderTargetDesc & Desc = PooledRenderTarget - > GetDesc ( ) ;
const TCHAR * DebugName = Desc . DebugName ;
uint32 * UsageCountPtr = VisualizeTextureCheckpoints . Find ( DebugName ) ;
if ( ! UsageCountPtr )
{
// create a new element with count 0
UsageCountPtr = & VisualizeTextureCheckpoints . Add ( DebugName , 0 ) ;
}
// is this is the name we are observing with visualize texture?
if ( ObservedDebugName = = DebugName )
{
// if multiple times reused during the frame, is that the one we want to look at?
if ( * UsageCountPtr = = ObservedDebugNameReusedGoal | | ObservedDebugNameReusedGoal = = 0xffffffff )
{
2014-08-04 12:04:27 -04:00
FRHICommandListImmediate & RHICmdListIm = FRHICommandListExecutor : : GetImmediateCommandList ( ) ;
if ( RHICmdListIm . IsExecuting ( ) )
{
UE_LOG ( LogConsoleResponse , Fatal , TEXT ( " We can't create a checkpoint because that requires the immediate commandlist, which is currently executing. You might try disabling parallel rendering. " ) ) ;
}
else
{
if ( & RHICmdList ! = & RHICmdListIm )
{
UE_LOG ( LogConsoleResponse , Warning , TEXT ( " Attempt to checkpoint a render target from a non-immediate command list. We will flush it and hope that works. If it doesn't you might try disabling parallel rendering. " ) ) ;
RHICmdList . Flush ( ) ;
}
GenerateContent ( RHICmdListIm , RenderTargetItem , Desc ) ;
if ( & RHICmdList ! = & RHICmdListIm )
{
RHICmdListIm . Flush ( ) ;
}
}
2014-03-14 14:13:41 -04:00
}
}
// only needed for VisualizeTexture (todo: optimize out when possible)
* UsageCountPtr = * UsageCountPtr + 1 ;
# endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
struct FSortedLines
{
FString Line ;
int32 SortIndex ;
uint32 PoolIndex ;
FORCEINLINE bool operator < ( const FSortedLines & B ) const
{
// first large ones
if ( SortIndex < B . SortIndex )
{
return true ;
}
if ( SortIndex > B . SortIndex )
{
return false ;
}
return Line < B . Line ;
}
} ;
void FVisualizeTexture : : DebugLog ( bool bExtended )
{
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
{
TArray < FSortedLines > SortedLines ;
2014-04-23 19:58:00 -04:00
for ( uint32 i = 0 , Num = GRenderTargetPool . GetElementCount ( ) ; i < Num ; + + i )
2014-03-14 14:13:41 -04:00
{
FPooledRenderTarget * RT = GRenderTargetPool . GetElementById ( i ) ;
if ( ! RT )
{
2014-04-23 19:58:00 -04:00
continue ;
2014-03-14 14:13:41 -04:00
}
FPooledRenderTargetDesc Desc = RT - > GetDesc ( ) ;
if ( bFullList | | ( Desc . Flags & TexCreate_HideInVisualizeTexture ) = = 0 )
{
uint32 SizeInKB = ( RT - > ComputeMemorySize ( ) + 1023 ) / 1024 ;
FString UnusedStr ;
if ( RT - > GetUnusedForNFrames ( ) > 0 )
{
if ( ! bFullList )
{
continue ;
}
UnusedStr = FString : : Printf ( TEXT ( " unused(%d) " ) , RT - > GetUnusedForNFrames ( ) ) ;
}
FSortedLines Element ;
Element . PoolIndex = i ;
// sort by index
Element . SortIndex = i ;
if ( SortOrder = = - 1 )
{
// sort by index
Element . Line = FString : : Printf ( TEXT ( " %s %s %d KB%s " ) , * Desc . GenerateInfoString ( ) , Desc . DebugName , SizeInKB , * UnusedStr ) ;
}
else if ( SortOrder = = 0 )
{
// sort by name
Element . Line = FString : : Printf ( TEXT ( " %s %s %d KB%s " ) , Desc . DebugName , * Desc . GenerateInfoString ( ) , SizeInKB , * UnusedStr ) ;
Element . SortIndex = 0 ;
}
else if ( SortOrder = = 1 )
{
// sort by size (large ones first)
Element . Line = FString : : Printf ( TEXT ( " %d KB %s %s%s " ) , SizeInKB , * Desc . GenerateInfoString ( ) , Desc . DebugName , * UnusedStr ) ;
Element . SortIndex = - ( int32 ) SizeInKB ;
}
else
{
check ( 0 ) ;
}
2014-04-30 12:13:37 -04:00
if ( Desc . Flags & TexCreate_FastVRAM )
{
FRHIResourceInfo Info ;
2014-04-30 14:29:00 -04:00
FTextureRHIRef Texture = RT - > GetRenderTargetItem ( ) . ShaderResourceTexture ;
2014-04-30 12:13:37 -04:00
if ( ! IsValidRef ( Texture ) )
{
2014-04-30 18:14:48 -04:00
Texture = RT - > GetRenderTargetItem ( ) . TargetableTexture ;
2014-04-30 12:13:37 -04:00
}
if ( IsValidRef ( Texture ) )
{
RHIGetResourceInfo ( Texture , Info ) ;
}
if ( Info . VRamAllocation . AllocationSize )
{
// note we do KB for more readable numbers but this can cause quantization loss
Element . Line + = FString : : Printf ( TEXT ( " VRamInKB(Start/Size):%d/%d " ) ,
Info . VRamAllocation . AllocationStart / 1024 ,
( Info . VRamAllocation . AllocationSize + 1023 ) / 1024 ) ;
}
else
{
Element . Line + = TEXT ( " VRamInKB(Start/Size):<NONE> " ) ;
}
}
2014-03-14 14:13:41 -04:00
SortedLines . Add ( Element ) ;
}
}
SortedLines . Sort ( ) ;
{
for ( int32 Index = 0 ; Index < SortedLines . Num ( ) ; Index + + )
{
const FSortedLines & Entry = SortedLines [ Index ] ;
UE_LOG ( LogConsoleResponse , Log , TEXT ( " %3d = %s " ) , Entry . PoolIndex + 1 , * Entry . Line ) ;
}
}
// clean flags for next use
bFullList = false ;
SortOrder = - 1 ;
}
UE_LOG ( LogConsoleResponse , Log , TEXT ( " " ) ) ;
// log names (alternative method to look at the rendertargets)
if ( bExtended )
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " CheckpointName (what was rendered this frame, use <Name>@<Number> to get intermediate versions): " ) ) ;
TArray < FString > Entries ;
// sorted by pointer for efficiency, now we want to print sorted alphabetically
for ( TMap < FString , uint32 > : : TIterator It ( GRenderTargetPool . VisualizeTexture . VisualizeTextureCheckpoints ) ; It ; + + It )
{
const FString & Key = It . Key ( ) ;
uint32 Value = It . Value ( ) ;
/* if(Value)
{
// was reused this frame
Entries . Add ( FString : : Printf ( TEXT ( " %s @0..%d " ) , * Key . GetPlainNameString ( ) , Value - 1 ) ) ;
}
else
*/ {
// was not reused this frame but can be referenced
Entries . Add ( Key ) ;
}
}
Entries . Sort ( ) ;
// print them sorted, if possible multiple in a line
{
FString Line ;
FString Separator = " , " ;
for ( int32 Index = 0 ; Index < Entries . Num ( ) ; Index + + )
{
const FString & Entry = * Entries [ Index ] ;
if ( Line . Len ( ) + 2 + Entry . Len ( ) > 80 )
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " %s " ) , * Line ) ;
Line . Empty ( ) ;
}
Line + = Entry ;
Line + = Separator ;
}
if ( ! Line . IsEmpty ( ) )
{
// remove separator in the end
Line = Line . Left ( Line . Len ( ) - Separator . Len ( ) ) ;
UE_LOG ( LogConsoleResponse , Log , TEXT ( " %s " ) , * Line ) ;
}
}
}
{
uint32 WholeCount ;
uint32 WholePoolInKB ;
uint32 UsedInKB ;
GRenderTargetPool . GetStats ( WholeCount , WholePoolInKB , UsedInKB ) ;
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Pool: %d/%d MB (referenced/allocated) " ) , ( UsedInKB + 1023 ) / 1024 , ( WholePoolInKB + 1023 ) / 1024 ) ;
}
# endif
}
// @return 0 if not found
IPooledRenderTarget * FVisualizeTexture : : GetObservedElement ( ) const
{
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
IPooledRenderTarget * RT = VisualizeTextureContent . GetReference ( ) ;
if ( ! RT & & Mode > = 0 )
{
uint32 Id = Mode - 1 ;
RT = GRenderTargetPool . GetElementById ( Id ) ;
}
return RT ;
# else
return 0 ;
# endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void FVisualizeTexture : : OnStartFrame ( const FSceneView & View )
{
2014-08-19 10:41:34 -04:00
FeatureLevel = View . GetFeatureLevel ( ) ;
2014-09-12 17:21:49 -04:00
bEnabled = true ;
2014-04-23 19:08:42 -04:00
ViewRect = View . UnscaledViewRect ;
2014-05-07 09:49:28 -04:00
AspectRatioConstrainedViewRect = View . Family - > EngineShowFlags . CameraAspectRatioBars ? View . CameraConstrainedViewRect : ViewRect ;
2014-03-14 14:13:41 -04:00
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
// VisualizeTexture observed render target is set each frame
VisualizeTextureContent . SafeRelease ( ) ;
VisualizeTextureDesc = FPooledRenderTargetDesc ( ) ;
2014-05-19 17:59:23 -04:00
VisualizeTextureDesc . DebugName = TEXT ( " VisualizeTexture " ) ;
2014-03-14 14:13:41 -04:00
ObservedDebugNameReusedCurrent = 0 ;
// only needed for VisualizeTexture (todo: optimize out when possible)
{
for ( TMap < FString , uint32 > : : TIterator It ( VisualizeTextureCheckpoints ) ; It ; + + It )
{
uint32 & Value = It . Value ( ) ;
// 0 as it was not used this frame yet
Value = 0 ;
}
}
# endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void FVisualizeTexture : : QueryInfo ( FQueryVisualizeTexureInfo & Out )
{
2014-04-23 19:58:00 -04:00
for ( uint32 i = 0 , Num = GRenderTargetPool . GetElementCount ( ) ; i < Num ; + + i )
2014-03-14 14:13:41 -04:00
{
FPooledRenderTarget * RT = GRenderTargetPool . GetElementById ( i ) ;
2014-04-23 19:58:00 -04:00
if ( ! RT )
2014-03-14 14:13:41 -04:00
{
2014-04-23 19:58:00 -04:00
continue ;
2014-03-14 14:13:41 -04:00
}
FPooledRenderTargetDesc Desc = RT - > GetDesc ( ) ;
uint32 SizeInKB = ( RT - > ComputeMemorySize ( ) + 1023 ) / 1024 ;
FString Entry = FString : : Printf ( TEXT ( " %s %d %s %d " ) ,
* Desc . GenerateInfoString ( ) ,
i + 1 ,
Desc . DebugName ? Desc . DebugName : TEXT ( " <Unnamed> " ) ,
SizeInKB ) ;
Out . Entries . Add ( Entry ) ;
}
}