From ecc904e06a31a9bf2d703cc37c05ed79dd5cdd7b Mon Sep 17 00:00:00 2001 From: kuba Date: Sat, 26 Sep 2026 08:08:37 +0200 Subject: [PATCH] [GPU] Clamp a volume render-target view to the volume depth Unreal binds a whole volume as a render target with the last slice set to its depth, one past the end, and the resolver stopped the session on it. The color block writes only the slices the volume has, so the view is now clamped to them. A view that starts past the last slice is still fatal. --- .../ImageRequestBuilders.ColorTarget.cs | 11 +++++++++-- .../Gpu/Images/ImageRequestBuildersTests.cs | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/SharpEmu.Libs/Gpu/Images/ImageRequestBuilders.ColorTarget.cs b/src/SharpEmu.Libs/Gpu/Images/ImageRequestBuilders.ColorTarget.cs index 1be295f..e23ac96 100644 --- a/src/SharpEmu.Libs/Gpu/Images/ImageRequestBuilders.ColorTarget.cs +++ b/src/SharpEmu.Libs/Gpu/Images/ImageRequestBuilders.ColorTarget.cs @@ -289,9 +289,16 @@ public static partial class ImageRequestBuilders var viewExtent = new Extent2D(Math.Max(width >> (int)words.MipLevel, 1), Math.Max(height >> (int)words.MipLevel, 1)); var viewDepth = Math.Max(depth >> (int)words.MipLevel, 1); - if (volume && (view.BaseLayer >= viewDepth || view.LayerCount > viewDepth - view.BaseLayer)) + if (volume && view.BaseLayer < viewDepth && view.LayerCount > viewDepth - view.BaseLayer) { - throw SubmissionScheduler.Fatal($"The 3D render-target view exceeds the mip depth: base={view.BaseLayer} count={view.LayerCount} depth={viewDepth} mip={words.MipLevel}."); + // Titles bind a whole volume with the last slice set to its depth, one past the end; + // the color block stops at the last slice of the mip. + view = view with { LayerCount = viewDepth - view.BaseLayer, ImageLayers = viewDepth }; + } + + if (volume && view.BaseLayer >= viewDepth) + { + throw SubmissionScheduler.Fatal($"The 3D render-target view starts past the mip depth: base={view.BaseLayer} count={view.LayerCount} depth={viewDepth} mip={words.MipLevel}."); } var description = ImageDescription.Create(); diff --git a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs index 31b1a2e..0388856 100644 --- a/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs +++ b/tests/SharpEmu.Libs.Tests/Gpu/Images/ImageRequestBuildersTests.cs @@ -145,6 +145,25 @@ public sealed class ImageRequestBuildersTests : IClassFixture(() => ImageRequestBuilders.ColorTarget( + RegisterWords.Color(Base, 32, 32, GuestTileMode.RenderTarget, sliceStart: 32, sliceMax: 32, dimension: 2, depth: 31), 0xF, 0, false)); + } + [Fact] public void ColorTarget_RejectsUnsupportedRegisterStates() {