Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/VisualizeTexturePresent.cpp
jason hoerner 2b0f208938 Visualize Texture: Performance and feature upgrades.
* Visualize texture system starts out in an inactive state until a command is issued, avoiding overhead of tracking views and scene textures, saving 1.4% on the render thread.
* Visualization overhead eliminated for views besides the one currently being visualized.
* Support for visualization of textures from scene captures, via "view=N" option (specifying the unique ID of the view), with "view=?" displaying a list of views for reference.
* Improved visualization for cube maps.  PIP uses 2:1 aspect for the longitudinal render to match resource viewer display, and pixel perfect option shows tiled flat cube map faces (actual pixels) rather than running a projection.
* Padding for scene or screen pass textures is removed in the visualization -- the padding otherwise shows up as garbage or blank space.

To remove scene texture padding, it's necessary to add a field to RDG textures to provide an option to track the viewport sizes that were rendered for a given texture.  If not set, the assumption is the whole texture was rendered.  The field is set for FSceneTextures and FScreenPassTexture, covering the vast majority of cases, plus the denoiser was spot fixed -- worst case if any other cases are missed, you still see the padding.  You can tell padding was present when visualizing by contrasting the texture size with the viewport size.

Padding was always a potential issue for the visualizer, but is exacerbated by scene captures, as the padded scene textures are set to a size that's a union of the main view and any scene captures.  Padding is also exacerbated by dynamic resolution scaling, as the buffers will be padded to the maximum resolution.  For example, a cube map rendering at 512x512 will have 93% of the pixel area as padding if the front buffer is at 1440p, or the default dynamic resolution setup will have 70% of the pixels as padding at minimum res.

#rb Jason.Nadro

[CL 31160232 by jason hoerner in ue5-main branch]
2024-02-03 16:07:46 -05:00

184 lines
6.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "VisualizeTexturePresent.h"
#include "VisualizeTexture.h"
#include "ScreenPass.h"
#include "UnrealEngine.h"
#include "Engine/Canvas.h"
#include "Engine/Engine.h"
#include "RenderTargetPool.h"
#include "SceneRendering.h"
void FVisualizeTexturePresent::PresentContent(FRDGBuilder& GraphBuilder, const FViewInfo& View, FScreenPassRenderTarget Output)
{
check(Output.IsValid());
#if SUPPORTS_VISUALIZE_TEXTURE
FVisualizeTexture::FCaptured& Captured = GVisualizeTexture.Captured;
if (!Captured.PooledRenderTarget && !Captured.Texture)
{
// visualize feature is deactivated
return;
}
// Reset bitmap flags now that we know we've saved out the bitmap we're seeing on screen.
{
using EFlags = FVisualizeTexture::EFlags;
EnumRemoveFlags(GVisualizeTexture.Config.Flags, EFlags::SaveBitmap | EFlags::SaveBitmapAsStencil);
}
const FPooledRenderTargetDesc& Desc = Captured.Desc;
FRDGTextureRef VisualizeTexture2D = Captured.Texture;
// 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)
{
case EInputUVMapping::LeftTop:
CopyOutput.ViewRect = View.UnconstrainedViewRect;
break;
case EInputUVMapping::PixelPerfectCenter:
{
FIntPoint SrcSize = CopyInput.ViewRect.Size();
FIntPoint Center = View.UnconstrainedViewRect.Size() / 2;
FIntPoint HalfMin = SrcSize / 2;
FIntPoint HalfMax = SrcSize - HalfMin;
CopyOutput.ViewRect = FIntRect(Center - HalfMin, Center + HalfMax);
}
break;
case EInputUVMapping::PictureInPicture:
{
const FIntPoint CopyInputExtent = CopyInput.Texture->Desc.Extent;
const float CopyInputAspectRatio = float(CopyInputExtent.X) / float(CopyInputExtent.Y);
int32 TargetedHeight = 0.3f * View.UnconstrainedViewRect.Height();
int32 TargetedWidth = CopyInputAspectRatio * TargetedHeight;
int32 OffsetFromBorder = 100;
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;
}
break;
}
AddDrawTexturePass(GraphBuilder, View, CopyInput, CopyOutput);
}
Output.LoadAction = ERenderTargetLoadAction::ELoad;
const FIntPoint ViewportSizeXY = Captured.OutputExtent;
FString ViewDescription = GVisualizeTexture.ViewDescriptionMap[Captured.ViewUniqueId];
AddDrawCanvasPass(GraphBuilder, {}, View, Output,
[VisualizeTexture2D, ViewportSizeXY, Desc, &View, InputUVMapping, InputValueMapping, ViewUniqueId = Captured.ViewUniqueId, ViewDescription, ViewRects = CopyTemp(Captured.ViewRects)](FCanvas& Canvas)
{
float X = 100 + View.UnconstrainedViewRect.Min.X;
float Y = 160 + View.UnconstrainedViewRect.Min.Y;
float YStep = 14;
{
const uint32 VersionCount = GVisualizeTexture.GetVersionCount(VisualizeTexture2D->Name);
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("View ID %d: \"%s\""), ViewUniqueId, *ViewDescription);
Canvas.DrawShadowedString(X, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
}
{
FString Line = FString::Printf(TEXT(" TextureInfo: %s"), *(Desc.GenerateInfoString()));
Canvas.DrawShadowedString(X + 10, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
}
{
FString Line = FString::Printf(TEXT(" ViewportSize:(%d,%d)"), ViewportSizeXY.X, ViewportSizeXY.Y);
Canvas.DrawShadowedString(X + 10, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
}
const FSceneViewFamily& ViewFamily = *View.Family;
for (int32 ViewId = 0; ViewId < ViewRects.Num(); ++ViewId)
{
const FIntRect& ViewRect = ViewRects[ViewId];
FString Line = FString::Printf(TEXT(" View #%d: (%d,%d)-(%d,%d)"), ViewId + 1, ViewRect.Min.X, ViewRect.Min.Y, ViewRect.Max.X, ViewRect.Max.Y);
Canvas.DrawShadowedString(X + 10, Y += YStep, *Line, GetStatsFont(), FLinearColor(1, 1, 1));
}
X += 40;
if (EnumHasAnyFlags(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));
if (InputValueMapping == EInputValueMapping::Shadow)
{
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));
}
else if (InputValueMapping == EInputValueMapping::Depth)
{
Canvas.DrawShadowedString(X, Y += YStep, TEXT("Color Key: Nonlinear with white distant"), GetStatsFont(), FLinearColor(0.5, 0, 0));
}
}
});
#endif
}