128 lines
4.7 KiB
C++
128 lines
4.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Capture/DisplayClusterMediaCaptureNodeTile.h"
|
|
|
|
#include "DisplayClusterMediaHelpers.h"
|
|
#include "DisplayClusterMediaLog.h"
|
|
|
|
#include "RenderGraphBuilder.h"
|
|
#include "RenderGraphUtils.h"
|
|
#include "RHICommandList.h"
|
|
#include "RHIResources.h"
|
|
#include "UnrealClient.h"
|
|
|
|
#include "Engine/Engine.h"
|
|
#include "Engine/GameViewportClient.h"
|
|
|
|
|
|
FDisplayClusterMediaCaptureNodeTile::FDisplayClusterMediaCaptureNodeTile(
|
|
const FString& InMediaId,
|
|
const FString& InClusterNodeId,
|
|
const FIntPoint& InTileLayout,
|
|
const FIntPoint& InTilePosition,
|
|
UMediaOutput* InMediaOutput,
|
|
UDisplayClusterMediaOutputSynchronizationPolicy* SyncPolicy
|
|
)
|
|
: FDisplayClusterMediaCaptureNodeBase(InMediaId, InClusterNodeId, InMediaOutput, SyncPolicy)
|
|
, bValidTileSettings(
|
|
DisplayClusterMediaHelpers::IsValidLayout(InTileLayout, GetMaxTileLayout()) && // Valid layout
|
|
DisplayClusterMediaHelpers::IsValidTileCoordinate(InTilePosition, InTileLayout)) // Valid coordinates
|
|
, bEndingX(InTilePosition.X == InTileLayout.X - 1)
|
|
, bEndingY(InTilePosition.Y == InTileLayout.Y - 1)
|
|
, TileLayout(InTileLayout)
|
|
, TilePosition(InTilePosition)
|
|
{
|
|
checkSlow(bValidTileSettings);
|
|
}
|
|
|
|
bool FDisplayClusterMediaCaptureNodeTile::StartCapture()
|
|
{
|
|
// Don't start capture if there is something invalid
|
|
if (bValidTileSettings)
|
|
{
|
|
return FDisplayClusterMediaCaptureNodeBase::StartCapture();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FIntPoint FDisplayClusterMediaCaptureNodeTile::GetCaptureSize() const
|
|
{
|
|
// Return backbuffer runtime size
|
|
if (!(GEngine && GEngine->GameViewport && GEngine->GameViewport->Viewport))
|
|
{
|
|
UE_LOG(LogDisplayClusterMedia, Warning, TEXT("'%s' couldn't get viewport size"), *GetMediaId());
|
|
return { };
|
|
}
|
|
|
|
const FIntPoint GameViewportSize = GEngine->GameViewport->Viewport->GetSizeXY();
|
|
|
|
// Non-ending tile width/height for reference
|
|
const int32 NonEndingTileWidth = GameViewportSize.X / TileLayout.X;
|
|
const int32 NonEndingTileHeight = GameViewportSize.Y / TileLayout.Y;
|
|
|
|
// Ending tile width/height for reference
|
|
const int32 EndingTileWidth = (GameViewportSize.X % TileLayout.X == 0 ? NonEndingTileWidth : GameViewportSize.X % TileLayout.X);
|
|
const int32 EndingTileHeight = (GameViewportSize.Y % TileLayout.Y == 0 ? NonEndingTileHeight : GameViewportSize.Y % TileLayout.Y);
|
|
|
|
// This tile size
|
|
const int32 ThisTileWidth = bEndingX ? EndingTileWidth : NonEndingTileWidth;
|
|
const int32 ThisTileHeight = bEndingY ? EndingTileHeight : NonEndingTileHeight;
|
|
|
|
UE_LOG(LogDisplayClusterMedia, Log, TEXT("'%s' capture size is [%d, %d]"), *GetMediaId(), ThisTileWidth, ThisTileHeight);
|
|
|
|
return FIntPoint{ ThisTileWidth, ThisTileHeight };
|
|
}
|
|
|
|
void FDisplayClusterMediaCaptureNodeTile::ProcessPostBackbufferUpdated_RenderThread(FRHICommandListImmediate& RHICmdList, FViewport* Viewport)
|
|
{
|
|
if (!Viewport)
|
|
{
|
|
UE_LOG(LogDisplayClusterMedia, Warning, TEXT("'%s' couldn't capture backbuffer tile [%d:%d], nullptr viewport"), *GetMediaId(), TilePosition.X, TilePosition.Y);
|
|
return;
|
|
}
|
|
|
|
if (!bValidTileSettings)
|
|
{
|
|
UE_LOG(LogDisplayClusterMedia, Warning, TEXT("'%s' couldn't capture backbuffer tile [%d:%d], layout [%d:%d] - invalid tile settings"), *GetMediaId(), TilePosition.X, TilePosition.Y, TileLayout.X, TileLayout.Y);
|
|
return;
|
|
}
|
|
|
|
if (FRHITexture* const BackbufferTexture = Viewport->GetRenderTargetTexture())
|
|
{
|
|
FRDGBuilder GraphBuilder(RHICmdList);
|
|
|
|
FRDGTextureRef BackbufferTextureRef = RegisterExternalTexture(GraphBuilder, BackbufferTexture, TEXT("DCMediaOutBackbufferTex"));
|
|
|
|
// Tile width/height (non-edge case)
|
|
const int32 TileWidth = BackbufferTextureRef->Desc.Extent.X / TileLayout.X;
|
|
const int32 TileHeight = BackbufferTextureRef->Desc.Extent.Y / TileLayout.Y;
|
|
|
|
// Top-left of the tile sub-region
|
|
const FIntPoint RectStart{
|
|
TilePosition.X * TileWidth,
|
|
TilePosition.Y * TileHeight
|
|
};
|
|
|
|
// Bottom-right of the tile sub-region. Ending tiles might have a little bit more pixels then TileWidth or TileHeight.
|
|
const FIntPoint RectEnd{
|
|
bEndingX ? BackbufferTextureRef->Desc.Extent.X : (TilePosition.X + 1) * TileWidth,
|
|
bEndingY ? BackbufferTextureRef->Desc.Extent.Y : (TilePosition.Y + 1) * TileHeight
|
|
};
|
|
|
|
// Final tile sub-region
|
|
const FIntRect TextureRegion = { RectStart, RectEnd };
|
|
|
|
UE_LOG(LogDisplayClusterMedia, VeryVerbose, TEXT("'%s' capturing backbuffer tile [%d:%d], region [%d:%d - %d:%d] of size [%dx%d]"),
|
|
*GetMediaId(), TilePosition.X, TilePosition.Y,
|
|
RectStart.X, RectStart.Y, RectEnd.X, RectEnd.Y,
|
|
BackbufferTextureRef->Desc.Extent.X, BackbufferTextureRef->Desc.Extent.Y);
|
|
|
|
// Capture
|
|
const FMediaOutputTextureInfo TextureInfo{ BackbufferTextureRef, TextureRegion };
|
|
ExportMediaData_RenderThread(GraphBuilder, TextureInfo);
|
|
|
|
GraphBuilder.Execute();
|
|
}
|
|
}
|