You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* Existing calls to CreateSceneTextureShaderParameters and similar functions use "GetSceneTexturesChecked", which allows for the possibility that they are reached in a code path where scene textures haven't been initialized, and nullptr is returned instead of asserting. The shader parameter setup functions then fill in dummy defaults for that case. The goal was to precisely match the original behavior, which queried the RDG blackboard, and gracefully handled null if scene textures weren't there. This definitely appears to occur in FNiagaraGpuComputeDispatch::ProcessPendingTicksFlush, which can be called with a dummy scene with no scene textures. In the future, I may change this so dummy defaults are filled in for FSceneTextures at construction time, so the structure is never in an uninitialized state, but I would like to set up a test case for the Niagara code path before doing that, and the checks aren't harmful in the meantime. * I marked as deprecated global functions which query values from FSceneTexturesConfig, but they'll still work with the caveat that if you use multi-view-family rendering, the results will be indeterminate (whatever view family rendered last). There was only one case outside the scene renderer that accessed the globals (depth clear value), which I removed, noting that there is nowhere in the code where we modify the depth clear value from its global default. I would like to permanently deprecate or remove these at some point. Display Cluster is the only code that's currently using the multi-view-family code path, and as a new (still incomplete) feature, third party code can't be using it, and won't be affected. #jira NONE #rb chris.kulla zach.bethel mihnea.balta #preflight 6261aca76119a1a496bd2644 [CL 19873983 by jason hoerner in ue5-main branch]
188 lines
6.6 KiB
C++
188 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"
|
|
|
|
void FVisualizeTexturePresent::OnStartRender(const FViewInfo& View)
|
|
{
|
|
#if SUPPORTS_VISUALIZE_TEXTURE
|
|
GVisualizeTexture.FeatureLevel = View.GetFeatureLevel();
|
|
GVisualizeTexture.Captured = {};
|
|
GVisualizeTexture.VersionCountMap.Empty();
|
|
#endif
|
|
}
|
|
|
|
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 BufferSizeXY = View.GetSceneTexturesConfig().Extent;
|
|
|
|
AddDrawCanvasPass(GraphBuilder, {}, View, Output,
|
|
[VisualizeTexture2D, BufferSizeXY, Desc, &View, InputUVMapping, InputValueMapping](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(" 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;
|
|
|
|
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
|
|
} |