fix(rendering): match empty packed submissions

The production dispatcher forces transparent deferral off when no top-level VAO was resolved, even if the frame alpha queue is active. Carry the same per-draw VAO sentinel into the compare-only packed classifier so its empty-submission state is exact rather than sampling only the later queue state.
This commit is contained in:
Erik 2026-07-25 01:48:02 +02:00
parent 29195fb255
commit 06e7754619
2 changed files with 43 additions and 4 deletions

View file

@ -85,6 +85,7 @@ public sealed unsafe partial class WbDrawDispatcher
rangeIndex++) rangeIndex++)
{ {
_nextPackedInstanceSubmissionOrder = 0; _nextPackedInstanceSubmissionOrder = 0;
uint anyVao = 0;
foreach (InstanceGroup group in _packedGroups.Values) foreach (InstanceGroup group in _packedGroups.Values)
group.ClearPerInstanceData(); group.ClearPerInstanceData();
@ -134,11 +135,13 @@ public sealed unsafe partial class WbDrawDispatcher
in candidate, in candidate,
meshParts.Slice( meshParts.Slice(
source.MeshPartOffset, source.MeshPartOffset,
source.MeshPartCount)); source.MeshPartCount),
ref anyVao);
} }
bool deferTransparent = bool deferTransparent = ShouldDeferPackedTransparent(
_alphaQueue?.IsCollecting == true; anyVao,
_alphaQueue?.IsCollecting == true);
InstanceLayoutCounts counts = PartitionInstanceGroups( InstanceLayoutCounts counts = PartitionInstanceGroups(
_packedGroups.Values, _packedGroups.Values,
deferTransparent, deferTransparent,
@ -165,7 +168,8 @@ public sealed unsafe partial class WbDrawDispatcher
private void ClassifyPackedEntity( private void ClassifyPackedEntity(
in RenderInstanceCandidate entity, in RenderInstanceCandidate entity,
ReadOnlySpan<RenderFrameMeshPart> meshParts) ReadOnlySpan<RenderFrameMeshPart> meshParts,
ref uint anyVao)
{ {
(uint slot, bool culled) = ResolveSlotForFrame( (uint slot, bool culled) = ResolveSlotForFrame(
_clipRoutingActive, _clipRoutingActive,
@ -216,6 +220,8 @@ public sealed unsafe partial class WbDrawDispatcher
_meshAdapter.TryGetRenderData(meshRef.GfxObjId); _meshAdapter.TryGetRenderData(meshRef.GfxObjId);
if (renderData is null) if (renderData is null)
continue; continue;
if (anyVao == 0)
anyVao = renderData.VAO;
if (renderData.IsSetup if (renderData.IsSetup
&& renderData.SetupParts.Count > 0) && renderData.SetupParts.Count > 0)
@ -291,6 +297,16 @@ public sealed unsafe partial class WbDrawDispatcher
} }
} }
/// <summary>
/// Mirrors the production dispatcher's no-VAO early return. That return
/// records an empty submission with transparent deferral disabled even
/// when the frame alpha queue is collecting.
/// </summary>
internal static bool ShouldDeferPackedTransparent(
uint anyVao,
bool alphaQueueCollecting) =>
anyVao != 0 && alphaQueueCollecting;
private float PackedPartOpacity( private float PackedPartOpacity(
uint localEntityId, uint localEntityId,
uint setupPartIndex) uint setupPartIndex)

View file

@ -0,0 +1,23 @@
using AcDream.App.Rendering.Wb;
namespace AcDream.App.Tests.Rendering.Wb;
public sealed class PackedDispatcherOracleTests
{
[Theory]
[InlineData(0u, false, false)]
[InlineData(0u, true, false)]
[InlineData(7u, false, false)]
[InlineData(7u, true, true)]
public void TransparentDeferral_MatchesProductionNoVaoEarlyReturn(
uint anyVao,
bool alphaQueueCollecting,
bool expected)
{
Assert.Equal(
expected,
WbDrawDispatcher.ShouldDeferPackedTransparent(
anyVao,
alphaQueueCollecting));
}
}