[DX12] RHIThreadにてGetAccelerationStructureAddress実行時にアクセス違反が発生する

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

度々穴をふさぐような対応となってしまい申し訳ございません。

改めて確認を行ったところ、関連データに関して並列タスクによって発生していた競合問題への修正(CL52403885)がUE5.8にて行われておりました。

お手数ですが、これまでの修正に加えてこちらのCLをマージすることで改善しないかご確認いただけますと幸いです。

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

[Attachment Removed]

ご回答ありがとうございます。

  • CL54000792の取り込み
  • HasValidAccelerationStructure() を使用したチェック処理および GRayTracingGeometryManager->RequestUpdateCachedRenderState(GroupHandle) によるState更新、およびこのState更新をRenderThreadで行うようにする対応
  • RHICmdList.EnqueueLambda()内で ReferencedGeometries[GeometryIndex]->IsValid() をチェックする対応
  • CL52403885の取り込み

で様子を見てみます。

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

[Attachment Removed]

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

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

[Attachment Removed]

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

こちらに関して、特定のルートで進行するとハードウェア内部のRaytracing処理でGPUクラッシュする状態になっていました(MMU Fault)。

WorldPartitionのロードによって発生しているような雰囲気です。

まだ塞げていない問題があるようなので、お手数ですが相談を再開させていただけますと幸いです。

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

[Attachment Removed]

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

情報ありがとうございます。

コマンドを試してみましたがクラッシュは解決せずでした…。

ひとまずUE5.8で実装されている RayTracingValidation を移植してみたところ、以下のようなエラーが出ていました。

Ray Tracing Validation for DirectX 12 and Vulkan | NVIDIA Technical Blog で紹介されている機能になります)

LogD3D12RHI: Error: Ray Tracing Validation message: [VERTEX_INDEX_OUT_OF_BOUNDS] Out-of-bounds vertex index encountered.
  geometry index: 0
  primitive index: 31
  vertex index: 1155039648
  vertex count: 55
  current operation: 
    type: build
    object type: BLAS
    object address: 0x19c29500

クラッシュがこのエラーによるものだとすると、アセット側の問題もあったりするのでしょうか?

お手数ですがご確認いただけますと幸いです。

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

[Attachment Removed]

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

FRayTracingInstanceBufferBuilder::FillAccelerationStructureAddressesBuffer の不正アクセスを防ぐために行った対応を一部巻き戻して、

  • CL54000792の取り込み
  • CL52403885の取り込み

としても発生することが分かりました。そのため、上記のGPUクラッシュは今回施した修正とは関係なさそうでした。

さらに細かく調べていくと、FCableSceneProxy のコンストラクタで StaticRayTracingGeometry が作られており、この処理を通らなくする( = bSupportRayTracing を false にする)

ことでクラッシュしなくなることが確認できました。

※ FRayTracingGeometryManager::SetupBuildParams() 内で *InBuildRequest.Owner->Initializer.DebugName.ToString() を出力するようにしたら FCableSceneProxy が紛れ込んでいて不審に思ったという流れです。

CVarRayTracingCableMeshes は 0 に設定しているのですが、StaticRayTracingGeometry は作成されており、それによって BLAS 作成が行われクラッシュする…という状況のようでした。

CableComponent の BLAS 作成処理でクラッシュする問題についてなにか報告があったり修正が入っていたりなどしていますでしょうか?

お忙しいところ恐縮ですが、ご確認いただけますと幸いです。

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

[Attachment Removed]

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

CLのご提示ありがとうございます。

確認いたします。

処理を追ってみたところ、CableComponent がロードされる -> FCableSceneProxy のコンストラクタが呼ばれる -> CreateRayTracingGeometry() が行われる

という処理になっており、BuildCableMesh() が呼ばれることなく BLAS が作られていそうです。

BuildCableMesh() が呼ばれないと IndexBuffer や VertexBuffer にデータが入っていない状態なのではないかと思ったのですが、そちらに関しては問題ないのでしょうか?

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

[Attachment Removed]

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

ご提案いただいた修正を入れたことでRayTracingValidationのエラーも出なくなり、クラッシュもしなくなりました。

やり取りも長くなってきましたので、ひとまずこちらのスレッドについては解決済みとさせていただければと思います。

(またレイトレ起因のクラッシュが発生するようであれば別途ご相談させていただけますと幸いです)

お忙しいところ、ご対応ありがとうございました。

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

[Attachment Removed]

ご対応ありがとうございます。

依然として発生してしまうとのことで、こちら実際のクラッシュ時のコールスタックなどはありますでしょうか?

念のためご確認いただけますと幸いです。

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

[Attachment Removed]

ご確認ありがとうございます。本件お時間を頂いており申し訳ございません。

ご提供頂いたデータの状況からすると、ストリームアウト時などのD3D12RayTracingGeometry::ReleaseUnderlyingResource()処理で、

オブジェクトは残りつつBufferだけ解放されている可能性がありそうですが、再現確認は行えていないため、どのパスで起きてしまっているかは不明な状態です。

調査を行ったところインスタンス追加のタイミングでGeometry->IsEvicted()のみの判定でGeometry->IsValid()の確認がない箇所があり、

タイミングによって破棄対象となっている可能性がありそうでしたので、以下のように修正することで改善しないかお試しいただけますと幸いです。

.\Engine\Source\Runtime\Renderer\Private\RayTracing\RayTracing.cpp:886行目あたり

// if (Geometry->IsEvicted())
if (!Geometry->IsValid() || Geometry->IsEvicted())

上記で治らない場合、問題切り分けのため"r.RayTracing.UseReferenceBasedResidency 0"設定で挙動が変わるかお試しいただけますと幸いです。

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

[Attachment Removed]

各種ご確認頂きありがとうございます。

状態管理の問題によって本来は削除するべきオブジェクトが残ってしまっている状況かと思われます。

完全に同じ状態ではないですが直近弊社内でも類似の問題を確認し調査が行われていたようでして、

こちら CL54000792 として修正が行われておりました。

お手数ですがCLのマージをお試しいただけますと幸いです。

※改善が見られない場合、前回お試しいただいていたEnqueueLambda内の処理に加えて、

以下のような防衛的なスキップを行うことでクラッシュを回避できる可能性もありそうです。

必要に応じて、こちらもご確認いただければと思います。

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

\Engine\Source\Runtime\D3D12RHI\Private\D3D12RayTracing.cpp:4511行目当たり

	const int32 NumReferencedGeometries = Scene.ReferencedGeometries.Num();
	for (int32 Index = 0; Index < NumReferencedGeometries; ++Index)
	{
		FD3D12RayTracingGeometry* Geometry = FD3D12DynamicRHI::ResourceCast(Scene.ReferencedGeometries[Index].GetReference());
 
		// 以下4行を追加
		if (!Geometry->AccelerationStructureBuffers[GPUIndex])
		{
			continue;
		}
 
 		checkf(!Geometry->IsDirty(CommandContext.GetGPUIndex()),

\Engine\Source\Runtime\D3D12RHI\Private\D3D12RayTracing.cpp:4062行目当たり

	const uint32 GPUIndex = CommandContext.GetGPUIndex();
	// CommandContext.UpdateResidency(AccelerationStructureBuffers[GPUIndex]->GetResource());
	// 以下4行を追加
	if (AccelerationStructureBuffers[GPUIndex])
	{
		CommandContext.UpdateResidency(AccelerationStructureBuffers[GPUIndex]->GetResource());
	}
}

[Attachment Removed]

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

Githubの場合以下URLが該当のコミットとなっておりました。

https://github.com/EpicGames/UnrealEngine/commit/83c8ac82c8d1c04221e6e027438c8753176e804c

お手数おかけしますが、こちらからご確認いただけますと幸いです。

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

[Attachment Removed]

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

前回の対応を行った状態でも問題が発生してしまっている状況の旨承知いたしました。

ご確認いただいているように遅延削除を行っており、また内部でキャッシュを持っている部分があるため、

具体的に再現確認はできておりませんがキャッシュ経由で再度追加されてしまっているケースがありそうです。

こちら追加でBuildRayTracingSceneInitializationDataによる構築時に確認を行うことで回避できないかお試しいただけますでしょうか?

.\Engine\Source\Runtime\Renderer\Private\RayTracing\RayTracingInstanceBufferUtil.cpp(175行目当たり)

FRayTracingSceneInitializationData BuildRayTracingSceneInitializationData(TConstArrayView<FRayTracingGeometryInstance> Instances, const TBitArray<>& VisibleInstances)
...
// 以下checkfをコメントアウトし4行を追加
// checkf(InstanceDesc.GeometryRHI, TEXT("Ray tracing instance must have a valid geometry."));
if (!InstanceDesc.GeometryRHI || !InstanceDesc.GeometryRHI->IsValid())
{
  continue;
}

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

[Attachment Removed]

ご確認ありがとうございます。状況承知いたしました。

こちら一度Pendingとさせて頂きますので、進展があった際は再度ご連絡いただければと思います。

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

[Attachment Removed]

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

現状も問題が発生してしまっているとのことで一度改めて調査を行わせて頂きましたが、

問題としてはFD3D12RayTracingGeometryの保持するAccelerationStructureBuffers[GPUIndex]へのアクセスが問題となっており、

こちらのデータがストリームアウト時に先に破棄(ReleaseUnderlyingResource())されてしまうことから、タイミングによって問題が発生している状況と思われます。

そのため、ASバッファを参照する各箇所GetAccelerationStructureAddress および PrepareAccelerationStructureBuildで、

AccelerationStructureBuffers[GPUIndex]及びResourceLocationの生存確認を行うことで対策できればと考えております。

1. AccelerationStructureBuffers[GPUIndex]->ResourceLocation.IsValid()の確認

※判定処理はcpp側でも使うので関数化

.\Engine\Source\Runtime\D3D12RHI\Private\D3D12RayTracing.h

// 追加
bool HasValidAccelerationStructure(uint32 GPUIndex) const
{
        return AccelerationStructureBuffers[GPUIndex].IsValid()
                && AccelerationStructureBuffers[GPUIndex]->ResourceLocation.IsValid();
}
 
virtual FRayTracingAccelerationStructureAddress GetAccelerationStructureAddress(uint64 GPUIndex) const final override
{                
        // 追加
        if (!HasValidAccelerationStructure(GPUIndex))
        {
                return 0;
        }
        return AccelerationStructureBuffers[GPUIndex]->ResourceLocation.GetGPUVirtualAddress();
}

2. ReferencedGeometriesのTRefCountPtr保持は以前の形に戻す

.\Engine\Source\Runtime\Renderer\Private\RayTracing\RayTracingInstanceBufferUtil.cpp

const TArrayView<FRHIRayTracingGeometry*> ReferencedGeometries = RHICmdList.AllocArray(MakeConstArrayView(Data.ReferencedGeometries)); 3. PrepareAccelerationStructureBuild内でも確認

.\Engine\Source\Runtime\D3D12RHI\Private\D3D12RayTracing.cpp

void PrepareAccelerationStructureBuild(...
// ...
        FD3D12RayTracingGeometry* Geometry = FD3D12DynamicRHI::ResourceCast(Scene.ReferencedGeometries[Index].GetReference());
        
        // 以下の判定を変更
        // if (!Geometry->AccelerationStructureBuffers[GPUIndex])
        if (!Geometry->HasValidAccelerationStructure(GPUIndex))
        {
                continue;
        }

お手数おかけしますが、上記ワークアラウンドにて対応可能かご確認いただけますと幸いです。

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

[Attachment Removed]

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

スクリーンショットを拝見させていただくと、キャッシュしていたポインタが再利用されてしまっている状況のように見受けられます。

前回案内させて頂いたようなチェックだと通り抜けてしまうため適切にキャッシュを無効化することが必要と思われます。

再現確認が行えておらず推測での対応となり申し訳ございませんが、

Evict()時点で行われているGRayTracingGeometryManagerのキャッシュの更新を、

ReleaseRHI時にも行うことで回避できないかご確認いただけますでしょうか?

void FRayTracingGeometry::ReleaseRHI()
{
	RemoveBuildRequest();
	RayTracingGeometryRHI.SafeRelease();
	GeometryState = EGeometryStateFlags::Invalid;
 
	GRayTracingGeometryManager->RefreshRegisteredGeometry(RayTracingGeometryHandle);
 
        //以下を追加
	if (GroupHandle != INDEX_NONE)
	{
		GRayTracingGeometryManager->RequestUpdateCachedRenderState(GroupHandle);
	}
}

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

[Attachment Removed]

現状をまとめて頂きありがとうございます。

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

[Attachment Removed]

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

本件引き続き最新の情報がないか確認させて頂いておりますが、

SBT周りの処理に関して継続的にクラッシュしてしまう報告を確認しており、

お手数おかけしますが、下記コマンドにて改善可能かご確認いただけますと幸いです。

r.RayTracing.PersistentSBT 0
r.RayTracing.PersistentSBT.ForceAlwaysDirty 1

[Content removed]

[Content removed]

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

[Attachment Removed]

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

本件問題の切り分けを行って頂きありがとうございます。

頂いた情報を元に再確認したところ、CableComponentを含むIndexBufferの競合問題への修正(CL54901816とCL54907185)が直近で行われており、こちらが関連している可能性がありそうでした。

お手数ですが上記CLにて改善可能かご確認頂けますと幸いです。

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

[Attachment Removed]

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

こちらの確認不足となり申し訳ございません。

該当箇所に関しましては、ご指摘いただいたように初期化を行っていないため問題となり得そうです。

以下のようにIndexBufferを初期化することで対応可能かご確認頂けますでしょうか?

※VertexBufferに関してはダミーデータでも問題ないかと思われます。

class FCableIndexBuffer : public FIndexBuffer 
{
public:
	virtual void InitRHI(FRHICommandListBase& RHICmdList) override
	{
		...
		IndexBufferRHI = RHICmdList.CreateBuffer(CreateDesc);
		
		// 以下を追加
		void* IndexData = RHICmdList.LockBuffer(IndexBufferRHI, 0, NumIndices * sizeof(int32), RLM_WriteOnly);
		FMemory::Memzero(IndexData, NumIndices * sizeof(int32));
		RHICmdList.UnlockBuffer(IndexBufferRHI);

また、CableComponentのレイトレーシングをオフ(CVarRayTracingCableMeshes 0)にした状態で今回のクラッシュが再現できないか確認しておりましたが、

現状は再現確認できておらずでして、お手数ですがお手元にてご確認頂けますと幸いです。

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

[Attachment Removed]