シーンキャプチャの際に Shadow.Virtual.PhysicalPagePool が増加する

お世話になっております。

NiagaraをUSceneCaptureComponent2Dでキャプチャを実行すると、Shadow.Virtual.PhysicalPagePool が増える現象が発生しております。

Niagaraの描画では影は必要ないため、Shadow.Virtual.PhysicalPagePool が増えることは想定外のため原因を調査を行っておりますが、原因の特定に至らずご質問させて頂ければと思います。

【試した内容】

1. Niagaraをキャプチャする USceneCaptureComponent2D の ShowFlags の全てのフラグをOFFにしたのち、Niagara描画に必要なフラグのみをONにする

ShowFlags.SetNiagara(true);

ShowFlags.SetParticles(true);

ShowFlags.SetTranslucency(true);

ShowFlags.SetSeparateTranslucency(true);

ShowFlags.SetRendering(true);

ShowFlags.SetDeferredLighting(true);

ShowFlags.SetGame(true);

この場合、Shadow.Virtual.PhysicalPagePool が増えることはありませんでした。

2. 1の設定で、追加で下記フラグをONにすると、Shadow.Virtual.PhysicalPagePool が増加する

ShowFlags.SetVirtualShadowMapPersistentData(true);

3. 2の結果を受け、どのフラグをONにしたときにShadow.Virtual.PhysicalPagePool が増加するのかを確認しました。

ShowFlags の全てのフラグをOFFにしたのち、

ShowFlags.SetVirtualShadowMapPersistentData(true);

ShowFlags.SetRendering(true);

これらのフラグのみをONにすると、Shadow.Virtual.PhysicalPagePool が増加しました。

Shadow.Virtual.PhysicalPagePool の増加は、初回のみで継続的に増加し続けることはありません。

しかしながら、一度増加すると減少することはないため、増加させないようにしたいと考えております。

【確認したいこと】

① SceneCaptureComponent でキャプチャする際、ShowFlags の VirtualShadowMapPersistentData を OFFにするのは問題ないのでしょうか?

また、SceneCaptureComponent の VirtualShadowMapPersistentData を OFFにすることが、ゲームメインの描画に影響することはないでしょうか?

VirtualShadowMapPersistentData をOFFにすると、VSMの情報が毎フレーム生成するとなり負荷上昇につながる認識となります。

キャプチャの際に設定した VirtualShadowMapPersistentData の設定がゲーム本体側にも影響し負荷が上昇することは避けたい問題となります。

VirtualShadowMapPersistentData をOFFの効果は、キャプチャ時の描画のみにしたいと考えております。

② ①の対応は問題がある、ゲームメインの描画に影響するとなった場合、Shadow.Virtual.PhysicalPagePool を増やさないようにするにはどうすれば良いでしょうか?

③ Niagara以外(StaticMeshなど)を SceneCaptureComponent でキャプチャする際にもShadow.Virtual.PhysicalPagePool の増加を確認しております。

SetFlagsで DynamicShadow と VirtualShadowMapPersistentData を OFF にする対応を行った場合でも、Shadow.Virtual.PhysicalPagePool が増加することを確認しており、原因箇所の特定と対処方法の調査を進めておりますが難航しております。

そこで質問なのですが、DynamicShadow を OFFにした場合にもかかわらず、Shadow.Virtual.PhysicalPagePool が増加する原因としてどのようなものが考えられるでしょうか?

以上、よろしくお願いいたします。

> ③ Niagara以外(StaticMeshなど)を SceneCaptureComponent でキャプチャする際にもShadow.Virtual.PhysicalPagePool の増加を確認しております。

こちらの件ですが、計測していたもの以外にキャプチャが動作していたため、

SetFlagsで DynamicShadow と VirtualShadowMapPersistentData を OFF にしても Shadow.Virtual.PhysicalPagePool が増加しておりました。

Niagara以外(StaticMeshなど)を SceneCaptureComponent でキャプチャする際もNiagaraと同様、

DynamicShadow をOFFにした場合でも VirtualShadowMapPersistentData をONにすることで、Shadow.Virtual.PhysicalPagePool が増加しました。

このため、キャプチャする際に、VirtualShadowMapPersistentData をONにすることが Shadow.Virtual.PhysicalPagePool 増加の原因と考えております。

お世話になっております。

本件確認させていただいておりますが、Shadow.Virtual.PhysicalPagePoolが増えてしまう現象を再現できていない状態です。

こちらで確認させていただいた内容を以下に共有させていただきますので、改めて必要な手順等がありましたらお知らせ頂けますと幸いです。

検証内容

1. SceneCapture2Dを持つActorをNiagaraエフェクトが見えるようにLevel上に配置しRenderTargetに描画(仮にNiagaraのMesh RendererでCubeを表示)

2. ”r.Shadow.Virtual.Stats 1”でPhysicalPagePoolの消費状況を表示し、SceneCapture2DのDynamicShadowをオンオフすることで消費状況が変化することを確認

3. rhi.DumpResourceMemoryでリソースの状況を確認

確認事項

VSMはNiagara、Static Meshなど対象の描画対象毎ではなく、ライトの数によって予めプールとして用意したPhysicalPageを消費しますが、

今回問題となっているのは、PhysicalPagePool自体の数が増えてしまっているという状態でしょうか?

※PIEで実行する場合、Editorとランタイム用で2つのPhysicalPagePoolが作成されますが、スタンドアローン、パッケージではSceneCapture2Dを含めて1つのPhysicalPagePoolで動作する想定です。

※以下ではライト毎にPageが消費される状態を紹介しています。

https://www.docswell.com/s/EpicGamesJapan/5Q8Q67-2023-12-21-185240#p90

お手数おかけしますが、上記内容をご確認いただけますと幸いです。

よろしくお願いいたします。

お世話になっております。

ご報告させていただいた症状ですが、現在開発中のプロジェクトでの症状となっております。

本プロジェクトでは、シーケンサーでキャプチャ・表示する実装となっております。

確認していた手順

1. Standaloneで実行し、症状発生箇所に移動。

2. r.DumpRenderTargetPoolMemory を実行する。

3. シーケンサーを再生し、キャプチャが実行される

4. r.DumpRenderTargetPoolMemory を実行する。

2 のタイミングでは Shadow.Virtual.PhysicalPagePool が2つ分確保されています。

256.000MB 16384x2048 [ 2] 1mip(s) Shadow.Virtual.PhysicalPagePool (R32_UINT) Unused frames: 0

256.000MB 16384x2048 [ 2] 1mip(s) Shadow.Virtual.PhysicalPagePool (R32_UINT) Unused frames: 0

4 のタイミングでは 3 つ確保されています。

256.000MB 16384x2048 [ 2] 1mip(s) Shadow.Virtual.PhysicalPagePool (R32_UINT) Unused frames: 0

256.000MB 16384x2048 [ 2] 1mip(s) Shadow.Virtual.PhysicalPagePool (R32_UINT) Unused frames: 0

256.000MB 16384x2048 [ 2] 1mip(s) Shadow.Virtual.PhysicalPagePool (R32_UINT) Unused frames: 0

※ 他に、Shadow.Virtual.HZBPhysicalPagePool も 2つ分から3つ分に確保数が増加しております。

-------------------------------------------------------

検証頂いた方法での確認

・ r.Shadow.Virtual.Stats 1

前述のとおり、シーケンサーで再生しておりますので、キャプチャ中の DynamicShadow のON/OFFでの確認はできておりません。

動画を撮影し数値の変化を確認しましたが、キャプチャ前とキャプチャ中で大きな差はなさそうです。

​ ​

・ rhi.DumpResourceMemory でリソースの状況を確認

上記の、2と4のタイミングで rhi.DumpResourceMemory を行ったところ、r.DumpRenderTargetPoolMemory と同様、

Shadow.Virtual.PhysicalPagePool 、Shadow.Virtual.HZBPhysicalPagePool ともに増加しております。

RHIResources: Name: Shadow.Virtual.PhysicalPagePool - Type: Texture - Size: 256.000000000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.PhysicalPagePool - Type: Texture - Size: 256.000000000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.PhysicalPagePool - Type: Texture - Size: 256.000000000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.PhysicalPagePool - Type: Texture - Size: 256.000000000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.PhysicalPagePool - Type: Texture - Size: 256.000000000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.HZBPhysicalPagePool - Type: Texture - Size: 42.687500000 MB - Flags: UAV - Owner: None

RHIResources: Name: Shadow.Virtual.HZBPhysicalPagePool - Type: Texture - Size: 42.687500000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.HZBPhysicalPagePool - Type: Texture - Size: 42.687500000 MB - Flags: UAV - Owner: None

RHIResources: Name: Shadow.Virtual.HZBPhysicalPagePool - Type: Texture - Size: 42.687500000 MB - Flags: Resident | UAV - Owner: None

RHIResources: Name: Shadow.Virtual.HZBPhysicalPagePool - Type: Texture - Size: 42.687500000 MB - Flags: Resident | UAV - Owner: None

これらの結果から、

> PhysicalPagePool自体の数が増えてしまっているという状態

と考えておりますが、認識が間違っていればご指摘をお願いいたします。

ご確認ありがとうございます。

頂いた情報を元にシーケンサー(Level Sequence)を組み合わせて確認させて頂きましたが、ご報告の現象は確認できていない状態となります

現状確認が難しいため、お手数ですが再現用サンプルプロジェクトの作成、添付を検討頂けますと幸いです。

よろしくお願いいたします。

お世話になっております。

開発後期のプロジェクトで発生しており、症状が発生する再現プロジェクトの作成に時間がかかる見込みとなります。

再現プロジェクトの準備と並行して、プロジェクト側の実装の確認も進めたいと思いますので、いくつか確認をさせて頂ければと思います。

1. 今回報告させていただいた症状ですが、 Shadow.Virtual.PhysicalPagePool が増加しているという認識なのですが、この認識に間違いないでしょうか?

また、今回のように Shadow.Virtual.PhysicalPagePool が増加することは、想定された挙動ではないということで間違いないでしょうか?

2. こちらの検証では、キャプチャシーンの ShowFlags に対して

ShowFlags.SetVirtualShadowMapPersistentData(fale);

とすることで、プールが増加しないことを確認しております。

キャプチャシーンのみ、ShowFlags.SetVirtualShadowMapPersistentData(fale); とすることは問題ないでしょうか?

また、キャプチャシーンで ShowFlags.SetVirtualShadowMapPersistentData(fale); とすることが、キャプチャ以外のシーンに影響するものでしょうか?

3. Shadow.Virtual.PhysicalPagePool を確保する要因として考えられるものは何かあるでしょうか?

些細なことでも構いません、何かしらヒントとなる事がありましたらご教示いただけると助かります。

以上、よろしくお願いいたします。

ご確認ありがとうございます。

PhysicalPagePoolは通常UWorld->FScene毎に1つのものを共有する想定となっており、

ご提供頂いたログから複数のPhysicalPagePoolが作られている状況が読み取れますが、

USceneCaptureComponent2DのCaptureSceneでは通常1つのPhysicalPagePoolが作成される見込みです。

void USceneCaptureComponent2D::CaptureScene()

ShowFlags.SetVirtualShadowMapPersistentData(False)設定によるallowPersistentDataの無効化に関しては、

ExtractFrameData()関数の冒頭にありますようにFreePhysicalPoolやFreeHZBPhysicalPoolにて開放を行うため、

どういった形でPhysicalPagePoolが保持されているかにもよりますが、メイン描画のキャッシュにも影響や負荷への懸念があります。(2)

※FreePhysicalPoolからInvalidateが走ります。

.\Engine\Source\Runtime\Renderer\Private\VirtualShadowMaps\VirtualShadowMapCacheManager.cpp

void FVirtualShadowMapArrayCacheManager::ExtractFrameData(
	FRDGBuilder& GraphBuilder,	
	FVirtualShadowMapArray &VirtualShadowMapArray,
	const FSceneRenderer& SceneRenderer,
	bool bAllowPersistentData)
{
...
if (bDropAll)
{
	// We drop the physical page pool here as well to ensure that it disappears in the case where
	// thumbnail rendering or similar creates multiple FSceneRenderers that never get deleted.
	// Caching is disabled on these contexts intentionally to avoid these issues.
	FreePhysicalPool(GraphBuilder);
	FreeHZBPhysicalPool(GraphBuilder);
}

bAllowPersistentDataがtrueの場合に増えてしまうとのことですが、実際にShadow.Virtual.PhysicalPagePoolを確保しているSetPhysicalPoolSize()関数から確認のため以下ログが出力されているかご確認いただけますでしょうか?(3)

.\Engine\Source\Runtime\Renderer\Private\VirtualShadowMaps\VirtualShadowMapCacheManager.cpp

void FVirtualShadowMapArrayCacheManager::SetPhysicalPoolSize(...){
	if (PhysicalPagePool)
	{
		UE_LOG(LogRenderer, Display, TEXT("Recreating Shadow.Virtual.PhysicalPagePool due to size or flags change. This will also drop any cached pages."));
	}

お手数おかけしますが、よろしくお願いいたします。

お世話になっております。

頂いた情報をもとに調査を行っておりましたが、原因が判明いたしました。

【原因】

キャプチャするデータは別途作成したワールドに紐づけることで、キャプチャ時に不要なデータが映りこまないように行っておりました。

この別途作成したワールドが Shadow.Virtual.PhysicalPagePool を作成しており、プール自体が増加することとなっておりました。

現状のプロジェクトの状況から、キャプチャ用のワールドの作成を行わないという選択は困難なことから、

キャプチャ用にワールドを作成するが、Shadow.Virtual.PhysicalPagePool を増加させないようにする方向で検討を進めております。

【対処案】

bool FVirtualShadowMapArrayCacheManager::ShouldCreateExtension(FScene& Scene)
{
    return DoesPlatformSupportVirtualShadowMaps(GetFeatureLevelShaderPlatform(Scene.GetFeatureLevel()));
}

こちらのコードを false で返し VirtualShadowMapArrayCacheManager を作成しない場合 Shadow.Virtual.PhysicalPagePool が作成されなくなることを確認しております。

このため、キャプチャ用のワールドでは、上記関数をfalse で返すようにし、Shadow.Virtual.PhysicalPagePool を作成させない方向で対応しようと考えております。

こちらの関数ではグローバルな値を参照しているため、個々のワールドで設定を変更することができないようですので、

プロジェクト側でワールドを作成する前にグローバルなフラグを立て、上記関数内でフラグが立っている場合は false を返すという実装を考えております。

上記の実装に対する懸念点や、作成するワールド毎に VirtualShadowMapArrayCacheManager を作成するかどうかを変更する何か良いアイデアなどありましたらご教示いただけると助かります。

調査結果をご共有頂きありがとうございます。

今回の問題に関しましてはSceneCapture時にWorldを別途作成していたため発生しているとのこと承知いたしました。

こちらでも確認を行わせて頂きましたが現状World個別でのVSMオンオフが難しいため、記載いただいていたShouldCreateExtension()関数にて、Scene、Worldによって作成しないといった分岐を行って頂く対応となってしまいそうです。

bool FVirtualShadowMapArrayCacheManager::ShouldCreateExtension(FScene& Scene)

お手数おかけしますが、よろしくお願いいたします。

ご確認ありがとうございます。

本件に関して、以上で解決とさせていただきます。

長くご対応頂きましてありがとうございました。

こちらこそ調査にご協力頂きありがとうございました。

本件はクローズとさせて頂きますが、また何かございましたらお気軽にご相談ください。

よろしくお願いいたします。