FPooledRenderTargetDesc FRCPassPostProcessVisualizeBloomOverlay::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("VisualizeBloomOverlay"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceSetup"); // alpha is unsed, todo: consider 32bit format return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceExtractSpecular::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_Todo_PassContext().GetSceneColor()->GetDesc(); Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceExtractSpecular"); // alpha is not used Ret.Format = PF_FloatRGB; return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessMotionBlurRecombine::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); // we don't need the alpha channel and 32bit is faster and costs less memory Ret.Format = PF_FloatRGB; Ret.DebugName = TEXT("MotionBlurRecombine"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessVisualizeBloomSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("VisualizeBloomSetup"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceVisualize::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_Todo_PassContext().GetSceneColor()->GetDesc(); Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceVisualize"); // alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering) Ret.Format = PF_FloatRGBA; return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessLensBlur::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); // more precision for additive blending Ret.Format = PF_FloatRGBA; Ret.DebugName = TEXT("LensBlur"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessMaterial::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; if (OutputFormat != PF_Unknown) { Ret.Format = OutputFormat; } Ret.Reset(); Ret.DebugName = TEXT("PostProcessMaterial"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessVisualizeLPV::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; Ret.Reset(); // we assume this pass is additively blended with the scene color so this data is not needed // FPooledRenderTargetDesc Ret; Ret.DebugName = TEXT("VisualizeLPV"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessSelectionOutlineColor::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.Format = PF_DepthStencil; Ret.Flags = TexCreate_None; Ret.TargetableFlags = TexCreate_DepthStencilTargetable; Ret.DebugName = TEXT("SelectionDepthStencil"); Ret.NumSamples = FSceneRenderTargets::Get_FrameConstantsOnly().GetEditorMSAACompositingSampleCount(); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceRecombine::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.DebugName = TEXT("SceneColorSubsurface"); if(bSingleViewportMode) { // we don't need an alpha channel any more as it was used for ScreenSpaceSubsurfaceScattering only Ret.Format = (Ret.Format == PF_FloatRGBA) ? PF_FloatRGB : PF_FloatRGBA; } // we replace the HDR SceneColor with this one return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessVelocityFlatten::ComputeOutputDesc(EPassOutputId InPassOutputId) const { if( InPassOutputId == ePId_Output0 ) { // Flattened velocity FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.TargetableFlags |= TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("VelocityFlat"); return Ret; } /*else if( InPassOutputId == ePId_Output1 ) { // Packed VelocityLength, Depth FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.Format = PF_R8G8; Ret.TargetableFlags |= TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("PackedVelocityDepth"); return Ret; }*/ else { // Max tile velocity FPooledRenderTargetDesc UnmodifiedRet = PassInputs[0].GetOutput()->RenderTargetDesc; UnmodifiedRet.Reset(); FIntPoint PixelExtent = UnmodifiedRet.Extent; FIntPoint ThreadGroupCount = ComputeThreadGroupCount(PixelExtent); FIntPoint NewSize = ThreadGroupCount; // format can be optimized later FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(NewSize, PF_G16R16F, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); Ret.DebugName = TEXT("MaxVelocity"); return Ret; } }
FPooledRenderTargetDesc FRCPassPostProcessNoiseBlur::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; Ret.Reset(); if(OverrideFormat != PF_Unknown) { Ret.Format = OverrideFormat; } Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("NoiseBlur"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessMotionBlurSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { if(InPassOutputId == ePId_Output0) { // downsampled velocity FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.Extent /= 2; Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); // we need at least a format in the range 0..1 with RGB channels, A is unused // Ret.Format = PF_A2B10G10R10; // we need alpha to renormalize Ret.Format = PF_FloatRGBA; Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("MotionBlurSetup0"); return Ret; } else { check(InPassOutputId == ePId_Output1); // scene color with depth in alpha FPooledRenderTargetDesc Ret = PassInputs[1].GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.Extent /= 2; Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); Ret.Format = PF_FloatRGBA; Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = TEXT("MotionBlurSetup1"); return Ret; } }
FPooledRenderTargetDesc FRCPassPostProcessSubsurfaceSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = FSceneRenderTargets::Get_Todo_PassContext().GetSceneColor()->GetDesc(); Ret.Reset(); Ret.DebugName = TEXT("SubsurfaceSetup"); // alpha is used to store depth and renormalize (alpha==0 means there is no subsurface scattering) Ret.Format = PF_FloatRGBA; Ret.Extent = ViewRect.Size(); // half res Ret.Extent = FIntPoint::DivideAndRoundUp(Ret.Extent, 2); Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessHistogramReduce::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc UnmodifiedRet = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; UnmodifiedRet.Reset(); FIntPoint PixelExtent = UnmodifiedRet.Extent; // each ThreadGroup outputs one histogram FIntPoint NewSize = FIntPoint(FRCPassPostProcessHistogram::HistogramTexelCount, 2); // for quality float4 to get best quality for smooth eye adaptation transitions FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(NewSize, PF_A32B32G32R32F, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable, false)); Ret.DebugName = TEXT("HistogramReduce"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessHistogram::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc UnmodifiedRet = PassInputs[0].GetOutput()->RenderTargetDesc; UnmodifiedRet.Reset(); FIntPoint PixelExtent = UnmodifiedRet.Extent; FIntPoint ThreadGroupCount = ComputeThreadGroupCount(PixelExtent); // each ThreadGroup outputs one histogram FIntPoint NewSize = FIntPoint(HistogramTexelCount, ThreadGroupCount.X * ThreadGroupCount.Y); // format can be optimized later FPooledRenderTargetDesc Ret(FPooledRenderTargetDesc::Create2DDesc(NewSize, PF_FloatRGBA, TexCreate_None, TexCreate_RenderTargetable | TexCreate_UAV, false)); Ret.DebugName = TEXT("Histogram"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessDOFSetup::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; // Ret.Extent = FIntPoint::DivideAndRoundUp(ret.Extent, 2); Ret.Extent /= 2; Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); Ret.Reset(); Ret.TargetableFlags &= ~(uint32)TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = (InPassOutputId == ePId_Output0) ? TEXT("DOFSetup0") : TEXT("DOFSetup1"); // more precision for additive blending and we need the alpha channel Ret.Format = PF_FloatRGBA; return Ret; }
void FVisualizeTexture::QueryInfo( FQueryVisualizeTexureInfo& Out ) { for(uint32 i = 0; ; ++i) { FPooledRenderTarget* RT = GRenderTargetPool.GetElementById(i); if (!RT) { break; } 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); } }
FPooledRenderTargetDesc FRCPassPostProcessPassThrough::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret; // we assume this pass is additively blended with the scene color so an intermediate is not always needed if(!Dest) { Ret = PassInputs[0].GetOutput()->RenderTargetDesc; if(NewDesc.IsValid()) { Ret = NewDesc; } } Ret.Reset(); Ret.DebugName = TEXT("PassThrough"); return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessCircleDOFDilate::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; // Ret.Extent = FIntPoint::DivideAndRoundUp(ret.Extent, 2); Ret.Extent /= 2; Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); Ret.Reset(); Ret.TargetableFlags &= ~(uint32)TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = (InPassOutputId == ePId_Output0) ? TEXT("CircleDOFDilate0") : TEXT("CircleDOFDilate1"); // Ret.Format = PF_FloatRGBA; // we only use one channel, maybe using 4 channels would save memory as we reuse Ret.Format = PF_R16F; return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessWeightedSampleSum::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassInputs[0].GetOutput()->RenderTargetDesc; if(DoFastBlur()) { if(FilterShape == EFS_Horiz) { Ret.Extent.X = FMath::DivideAndRoundUp(Ret.Extent.X, 2); } else { // not perfect - we might get a RT one texel larger Ret.Extent.X *= 2; } } Ret.Reset(); Ret.DebugName = DebugName; return Ret; }
FPooledRenderTargetDesc FRCPassPostProcessDownsample::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = GetInput(ePId_Input0)->GetOutput()->RenderTargetDesc; Ret.Reset(); Ret.Extent = FIntPoint::DivideAndRoundUp(Ret.Extent, 2); Ret.Extent.X = FMath::Max(1, Ret.Extent.X); Ret.Extent.Y = FMath::Max(1, Ret.Extent.Y); if(OverrideFormat != PF_Unknown) { Ret.Format = OverrideFormat; } Ret.TargetableFlags &= ~TexCreate_UAV; Ret.TargetableFlags |= TexCreate_RenderTargetable; Ret.DebugName = DebugName; return Ret; }
void FVisualizeTexture::GenerateContent(const FSceneRenderTargetItem& RenderTargetItem, const FPooledRenderTargetDesc& Desc) { // otherwise StartFrame() wasn't called check(ViewRect != FIntRect(0, 0, 0, 0)) 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(); RHISetRenderTarget(DestRenderTarget.TargetableTexture, FTextureRHIRef()); RHIClear(true, FLinearColor(1,1,0,1), false, 0.0f, false, 0, FIntRect()); RHISetBlendState(TStaticBlendState<>::GetRHI()); RHISetRasterizerState(TStaticRasterizerState<>::GetRHI()); RHISetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI()); 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; { SCOPED_DRAW_EVENT(VisualizeTexture, DEC_SCENE_ITEMS); // continue rendering to HDR if necessary RenderVisualizeTexture(VisualizeTextureData); } RHICopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); 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; RHIReadSurfaceData(Texture, FIntRect(0, 0, Extent.X, Extent.Y), Bitmap, ReadDataFlags); // 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")); } } }
void FVisualizeTexture::PresentContent(const FSceneView& View) { 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) { GenerateContent(Element->GetRenderTargetItem(), Element->GetDesc()); } } const FTexture2DRHIRef& RenderTargetTexture = View.Family->RenderTarget->GetRenderTargetTexture(); if(!VisualizeTextureContent || !IsValidRef(RenderTargetTexture) || GRHIFeatureLevel < ERHIFeatureLevel::SM3) { // visualize feature is deactivated return; } FPooledRenderTargetDesc Desc = VisualizeTextureDesc; RHISetRenderTarget(View.Family->RenderTarget->GetRenderTargetTexture(),FTextureRHIRef()); RHISetViewport(0, 0, 0.0f, GSceneRenderTargets.GetBufferSizeXY().X, GSceneRenderTargets.GetBufferSizeXY().Y, 1.0f ); RHISetBlendState(TStaticBlendState<>::GetRHI()); RHISetRasterizerState(TStaticRasterizerState<>::GetRHI()); RHISetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI()); TShaderMapRef<FPostProcessVS> VertexShader(GetGlobalShaderMap()); TShaderMapRef<FVisualizeTexturePresentPS> PixelShader(GetGlobalShaderMap()); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); VertexShader->SetParameters(View); PixelShader->SetParameters(View, *VisualizeTextureContent); FIntRect DestRect = View.ViewRect; FIntRect VisualizeTextureRect = ComputeVisualizeTextureRect(Desc.Extent); // Draw a quad mapping scene color to the view's render target DrawRectangle( VisualizeTextureRect.Min.X, VisualizeTextureRect.Min.Y, VisualizeTextureRect.Width(), VisualizeTextureRect.Height(), 0, 0, VisualizeTextureRect.Width(), VisualizeTextureRect.Height(), GSceneRenderTargets.GetBufferSizeXY(), VisualizeTextureRect.Size(), EDRF_Default); // 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); FCanvas Canvas(&TempRenderTarget, NULL, View.Family->CurrentRealTime, View.Family->CurrentWorldTime, View.Family->DeltaWorldTime); 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; 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)); Canvas.Flush(); }
void FVisualizeTexture::DebugLog(bool bExtended) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { TArray<FSortedLines> SortedLines; for(uint32 i = 0;; ++i) { FPooledRenderTarget* RT = GRenderTargetPool.GetElementById(i); if(!RT) { break; } 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); } 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 }