fix(rendering): restore classic transparent batching
Restore the pre-c4 classic immediate path for transparent commands without active building detail: always use the shared alpha pipeline and coalesce adjacent same-cull commands across TranslucencyKind boundaries. Keep detail-active material selection, detail arm/reset, and inner cull-run splitting unchanged. Required mutations and first discriminating failures (all restored): 1. Non-detail arm restored to PipelineForBlend: ClassicImmediate_NonDetailUsesAlphaBlendWhenDetailIsDisabledOrUnavailable first reported InvAlpha/detail-disabled at line 1258; expected wb-mesh-alpha-1x, actual wb-mesh-inverse-1x. 2. Translucency equality split restored with the alpha arm intact: ClassicImmediate_NonDetailCrossBlendRunCoalescesIntoOnePhysicalDraw failed at line 1279; Assert.Single saw 3 physical MDI records. 3. Detail-active command forced onto AlphaBlend: ClassicImmediate_DetailActiveUsesExactMaterialPipelineAndArm failed at line 1303; expected wb-mesh-raw-additive-depth-write-1x, actual wb-mesh-alpha-1x.
This commit is contained in:
parent
d5cfd1c916
commit
03a108ffa5
2 changed files with 176 additions and 7 deletions
|
|
@ -725,7 +725,6 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
int end = command + _transparentDrawCount;
|
||||
while (command < end)
|
||||
{
|
||||
TranslucencyKind blend = _groupInputScratch[command].Translucency;
|
||||
RetailSetSurfaceMaterialState materialState =
|
||||
_groupInputScratch[command].MaterialState;
|
||||
bool hasDetail = detailEnabled
|
||||
|
|
@ -734,7 +733,6 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
usedDetailCategories);
|
||||
int runEnd = command + 1;
|
||||
while (runEnd < end
|
||||
&& _groupInputScratch[runEnd].Translucency == blend
|
||||
&& !hasDetail
|
||||
&& (!detailEnabled
|
||||
|| !CommandContainsDetailCategory(
|
||||
|
|
@ -748,7 +746,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
|||
encoder,
|
||||
hasDetail
|
||||
? PipelineForMaterial(pipelines, materialState, pipelines.Opaque)
|
||||
: PipelineForBlend(pipelines, blend),
|
||||
: pipelines.AlphaBlend,
|
||||
mesh);
|
||||
if (hasDetail)
|
||||
ArmBuildingDetail(ref pushConstants, materialState);
|
||||
|
|
|
|||
|
|
@ -1231,6 +1231,117 @@ public sealed class WalkStaticStreamPopulatorTests
|
|||
call => call.Constants.TextureIndexA == 99u && call.Constants.ParamA == 2f);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SurfaceType.Additive, true, false)]
|
||||
[InlineData(SurfaceType.InvAlpha, true, false)]
|
||||
[InlineData(SurfaceType.Additive, false, true)]
|
||||
[InlineData(SurfaceType.InvAlpha, false, true)]
|
||||
public void ClassicImmediate_NonDetailUsesAlphaBlendWhenDetailIsDisabledOrUnavailable(
|
||||
SurfaceType surfaceType,
|
||||
bool detailAvailable,
|
||||
bool detailEnabled)
|
||||
{
|
||||
using var fx = new DispatcherFixture(
|
||||
detailAvailable: detailAvailable,
|
||||
detailEnabled: detailEnabled);
|
||||
using DrawScope draw = fx.BeginDraw();
|
||||
|
||||
ExecuteClassicGroups(
|
||||
fx,
|
||||
AlphaInstanceGroup(
|
||||
detailCategory: 1u,
|
||||
surfaceType: surfaceType,
|
||||
sortDistance: 10f));
|
||||
|
||||
(string Pipeline, GpuPushConstants Constants, GpuRecordedMultiDrawIndirect Draw) transcript =
|
||||
Assert.Single(ClassicDrawTranscript(fx.Device));
|
||||
Assert.Equal("wb-mesh-alpha-1x", transcript.Pipeline);
|
||||
Assert.Equal(1u, transcript.Draw.DrawCount);
|
||||
Assert.Equal(0u, transcript.Constants.TextureIndexA);
|
||||
Assert.Equal(0f, transcript.Constants.ParamA);
|
||||
Assert.Equal(0f, transcript.Constants.ParamB);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClassicImmediate_NonDetailCrossBlendRunCoalescesIntoOnePhysicalDraw()
|
||||
{
|
||||
using var fx = new DispatcherFixture(
|
||||
detailAvailable: true,
|
||||
detailEnabled: false);
|
||||
using DrawScope draw = fx.BeginDraw();
|
||||
|
||||
ExecuteClassicGroups(
|
||||
fx,
|
||||
AlphaInstanceGroup(1u, SurfaceType.Alpha, sortDistance: 30f),
|
||||
AlphaInstanceGroup(1u, SurfaceType.Additive, sortDistance: 20f),
|
||||
AlphaInstanceGroup(1u, SurfaceType.InvAlpha, sortDistance: 10f));
|
||||
|
||||
(string Pipeline, GpuPushConstants Constants, GpuRecordedMultiDrawIndirect Draw) transcript =
|
||||
Assert.Single(ClassicDrawTranscript(fx.Device));
|
||||
Assert.Equal("wb-mesh-alpha-1x", transcript.Pipeline);
|
||||
Assert.Equal(3u, transcript.Draw.DrawCount);
|
||||
Assert.Equal(0f, transcript.Constants.ParamA);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClassicImmediate_DetailActiveUsesExactMaterialPipelineAndArm()
|
||||
{
|
||||
using var fx = new DispatcherFixture(
|
||||
detailAvailable: true,
|
||||
detailEnabled: true);
|
||||
using DrawScope draw = fx.BeginDraw();
|
||||
|
||||
ExecuteClassicGroups(
|
||||
fx,
|
||||
AlphaInstanceGroup(
|
||||
1u,
|
||||
SurfaceType.Additive | SurfaceType.Base1ClipMap,
|
||||
sortDistance: 10f));
|
||||
|
||||
(string Pipeline, GpuPushConstants Constants, GpuRecordedMultiDrawIndirect Draw) transcript =
|
||||
Assert.Single(ClassicDrawTranscript(fx.Device));
|
||||
Assert.Equal("wb-mesh-raw-additive-depth-write-1x", transcript.Pipeline);
|
||||
Assert.Equal(1u, transcript.Draw.DrawCount);
|
||||
Assert.Equal(99u, transcript.Constants.TextureIndexA);
|
||||
Assert.Equal(2f, transcript.Constants.ParamA);
|
||||
Assert.Equal(200f / 255f, transcript.Constants.ParamB);
|
||||
Assert.NotEqual(
|
||||
0,
|
||||
transcript.Constants.RenderPass & RetailDetailTextureContract.NoFogRenderPassFlag);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClassicImmediate_NonDetailDetailNonDetailKeepsBothBoundariesAndDoesNotLeak()
|
||||
{
|
||||
using var fx = new DispatcherFixture(
|
||||
detailAvailable: true,
|
||||
detailEnabled: true);
|
||||
using DrawScope draw = fx.BeginDraw();
|
||||
|
||||
ExecuteClassicGroups(
|
||||
fx,
|
||||
AlphaInstanceGroup(0u, SurfaceType.Alpha, sortDistance: 30f),
|
||||
AlphaInstanceGroup(
|
||||
1u,
|
||||
SurfaceType.Additive | SurfaceType.Base1ClipMap,
|
||||
sortDistance: 20f),
|
||||
AlphaInstanceGroup(0u, SurfaceType.InvAlpha, sortDistance: 10f));
|
||||
|
||||
var transcript = ClassicDrawTranscript(fx.Device);
|
||||
Assert.Equal(3, transcript.Count);
|
||||
Assert.Equal(
|
||||
["wb-mesh-alpha-1x", "wb-mesh-raw-additive-depth-write-1x", "wb-mesh-alpha-1x"],
|
||||
transcript.Select(entry => entry.Pipeline));
|
||||
Assert.All(transcript, entry => Assert.Equal(1u, entry.Draw.DrawCount));
|
||||
Assert.Equal(0f, transcript[0].Constants.ParamA);
|
||||
Assert.Equal(2f, transcript[1].Constants.ParamA);
|
||||
Assert.Equal(99u, transcript[1].Constants.TextureIndexA);
|
||||
Assert.Equal(200f / 255f, transcript[1].Constants.ParamB);
|
||||
Assert.Equal(0f, transcript[2].Constants.ParamA);
|
||||
Assert.Equal(0u, transcript[2].Constants.TextureIndexA);
|
||||
Assert.Equal(0f, transcript[2].Constants.ParamB);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SurfaceType.Alpha, false, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 0f, true)]
|
||||
[InlineData(SurfaceType.Alpha | SurfaceType.Additive, false, "wb-mesh-additive-1x", GpuBlendMode.Additive, 0f, false)]
|
||||
|
|
@ -1415,7 +1526,10 @@ public sealed class WalkStaticStreamPopulatorTests
|
|||
IsOpaque: false,
|
||||
LocalSortCenter: Vector3.Zero);
|
||||
|
||||
private static WbDrawDispatcher.InstanceGroup AlphaInstanceGroup(uint detailCategory)
|
||||
private static WbDrawDispatcher.InstanceGroup AlphaInstanceGroup(
|
||||
uint detailCategory,
|
||||
SurfaceType surfaceType = SurfaceType.Alpha,
|
||||
float sortDistance = 0f)
|
||||
{
|
||||
var group = new WbDrawDispatcher.InstanceGroup
|
||||
{
|
||||
|
|
@ -1424,13 +1538,13 @@ public sealed class WalkStaticStreamPopulatorTests
|
|||
IndexCount = 3,
|
||||
TextureSlot = new GpuTextureSlot(1),
|
||||
TextureLayer = 0,
|
||||
Translucency = TranslucencyKind.AlphaBlend,
|
||||
Translucency = TranslucencyKindExtensions.FromSurfaceType(surfaceType),
|
||||
MaterialState = RetailSetSurfaceMaterialState.Resolve(
|
||||
SurfaceType.Alpha,
|
||||
surfaceType,
|
||||
texturePresent: true,
|
||||
textureHasPalette: false),
|
||||
};
|
||||
group.Matrices.Add(Matrix4x4.Identity);
|
||||
group.Matrices.Add(Matrix4x4.CreateTranslation(0f, 0f, sortDistance));
|
||||
group.SubmissionOrders.Add(0);
|
||||
group.Slots.Add(0);
|
||||
group.LightSets.Add(WbDrawDispatcher.InstanceLightSet.Disabled);
|
||||
|
|
@ -1441,6 +1555,63 @@ public sealed class WalkStaticStreamPopulatorTests
|
|||
return group;
|
||||
}
|
||||
|
||||
private static void ExecuteClassicGroups(
|
||||
DispatcherFixture fixture,
|
||||
params WbDrawDispatcher.InstanceGroup[] groups)
|
||||
{
|
||||
fixture.Dispatcher.BeginFrame(frameSlot: 0);
|
||||
MethodInfo execute = typeof(WbDrawDispatcher).GetMethod(
|
||||
"ExecuteClassifiedGroups",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
execute.Invoke(
|
||||
fixture.Dispatcher,
|
||||
[
|
||||
Matrix4x4.Identity,
|
||||
Vector3.Zero,
|
||||
0u,
|
||||
groups,
|
||||
WbDrawDispatcher.EntitySet.All,
|
||||
groups.Length,
|
||||
groups.Length,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
}
|
||||
|
||||
private static List<(
|
||||
string Pipeline,
|
||||
GpuPushConstants Constants,
|
||||
GpuRecordedMultiDrawIndirect Draw)> ClassicDrawTranscript(
|
||||
RecordingGpuDevice device)
|
||||
{
|
||||
var transcript = new List<(
|
||||
string Pipeline,
|
||||
GpuPushConstants Constants,
|
||||
GpuRecordedMultiDrawIndirect Draw)>();
|
||||
IReadOnlyList<GpuRecordedCall> calls = device.Calls;
|
||||
for (int i = 0; i < calls.Count; i++)
|
||||
{
|
||||
if (calls[i] is not GpuRecordedMultiDrawIndirect draw)
|
||||
continue;
|
||||
|
||||
string? pipeline = null;
|
||||
GpuPushConstants? constants = null;
|
||||
for (int prior = i - 1; prior >= 0 && (pipeline is null || constants is null); prior--)
|
||||
{
|
||||
if (pipeline is null && calls[prior] is GpuRecordedPipelineBind bind)
|
||||
pipeline = bind.PipelineName;
|
||||
if (constants is null && calls[prior] is GpuRecordedPushConstants push)
|
||||
constants = push.Constants;
|
||||
}
|
||||
|
||||
Assert.NotNull(pipeline);
|
||||
Assert.NotNull(constants);
|
||||
transcript.Add((pipeline!, constants!.Value, draw));
|
||||
}
|
||||
|
||||
return transcript;
|
||||
}
|
||||
|
||||
private static ObjectMeshData PreparedTriangle(uint objectId, uint surfaceId) => new()
|
||||
{
|
||||
ObjectId = objectId,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue