Fix alpha-tested blend depth writes
Add paired depth-write variants for all five blended SetSurface families in ordinary and atmospheric Wb pipeline sets at both sample counts and in EnvCell. Select them only from the carried AlphaTestEnabled state, retain pure-Clip and Translucent override behavior, and cover disposal plus partial-construction rollback. Correct the three stale depth oracles and the AP register count/temporary AP-232 overclaim. Required restored mutations and first discriminating failures: 1. Wb StraightAlpha+Clip collapsed to depth-off: WalkStaticStreamPopulatorTests.ImmediateBuildingDetail_UsesExactResolvedSetSurfaceState failed at line 1278; expected wb-mesh-alpha-depth-write-1x, binds were wb-mesh-alpha-1x. 2. EnvCell raw Additive+Clip collapsed to depth-off: EnvCellAlphaDrawSourceTests.DetailOn_EveryEnvCellFamilyDrawsOnceInPlaceWithAuthoredOpacity failed at line 132; expected envcell-raw-additive-depth-write, actual envcell-raw-additive. 3. EnvCell non-Clip raw Additive forced depth-on: the same production transcript failed at line 132; first row expected envcell-raw-additive, actual envcell-raw-additive-depth-write. 4. Late Translucent|Clip override forced alpha-test/depth-on: the same production transcript failed at line 132; expected envcell-alpha, actual envcell-alpha-depth-write.
This commit is contained in:
parent
15ed57a1e7
commit
d5cfd1c916
8 changed files with 285 additions and 82 deletions
File diff suppressed because one or more lines are too long
|
|
@ -27,11 +27,16 @@ public sealed unsafe partial class EnvCellRenderer
|
||||||
private readonly IWorldPassScope? _scope;
|
private readonly IWorldPassScope? _scope;
|
||||||
private IGpuPipeline? _opaquePipeline;
|
private IGpuPipeline? _opaquePipeline;
|
||||||
private IGpuPipeline? _alphaPipeline;
|
private IGpuPipeline? _alphaPipeline;
|
||||||
|
private IGpuPipeline? _alphaDepthWritePipeline;
|
||||||
private IGpuPipeline? _clipPipeline;
|
private IGpuPipeline? _clipPipeline;
|
||||||
private IGpuPipeline? _additivePipeline;
|
private IGpuPipeline? _additivePipeline;
|
||||||
|
private IGpuPipeline? _additiveDepthWritePipeline;
|
||||||
private IGpuPipeline? _rawAdditivePipeline;
|
private IGpuPipeline? _rawAdditivePipeline;
|
||||||
|
private IGpuPipeline? _rawAdditiveDepthWritePipeline;
|
||||||
private IGpuPipeline? _inversePipeline;
|
private IGpuPipeline? _inversePipeline;
|
||||||
|
private IGpuPipeline? _inverseDepthWritePipeline;
|
||||||
private IGpuPipeline? _inverseAdditivePipeline;
|
private IGpuPipeline? _inverseAdditivePipeline;
|
||||||
|
private IGpuPipeline? _inverseAdditiveDepthWritePipeline;
|
||||||
private readonly TerrainAtlas.RetailDetailTextureBinding _environmentDetail;
|
private readonly TerrainAtlas.RetailDetailTextureBinding _environmentDetail;
|
||||||
private readonly Func<bool> _buildingDetailEnabled;
|
private readonly Func<bool> _buildingDetailEnabled;
|
||||||
|
|
||||||
|
|
@ -72,33 +77,51 @@ public sealed unsafe partial class EnvCellRenderer
|
||||||
_environmentDetail = environmentDetail;
|
_environmentDetail = environmentDetail;
|
||||||
_buildingDetailEnabled = buildingDetailEnabled ?? DisableDetailTextures;
|
_buildingDetailEnabled = buildingDetailEnabled ?? DisableDetailTextures;
|
||||||
|
|
||||||
_opaquePipeline = CreateShellPipeline(
|
try
|
||||||
device, "envcell-opaque", GpuBlendMode.None, depthWrite: true, scope.SampleCount);
|
{
|
||||||
_alphaPipeline = CreateShellPipeline(
|
_opaquePipeline = CreateShellPipeline(
|
||||||
device, "envcell-alpha", GpuBlendMode.StraightAlpha, depthWrite: false, scope.SampleCount);
|
device, "envcell-opaque", GpuBlendMode.None, depthWrite: true, scope.SampleCount);
|
||||||
_clipPipeline = CreateShellPipeline(
|
_alphaPipeline = CreateShellPipeline(
|
||||||
device,
|
device, "envcell-alpha", GpuBlendMode.StraightAlpha, depthWrite: false, scope.SampleCount);
|
||||||
"envcell-clip",
|
_alphaDepthWritePipeline = CreateShellPipeline(
|
||||||
GpuBlendMode.PremultipliedAlpha,
|
device, "envcell-alpha-depth-write", GpuBlendMode.StraightAlpha, depthWrite: true, scope.SampleCount);
|
||||||
depthWrite: true,
|
_clipPipeline = CreateShellPipeline(
|
||||||
scope.SampleCount);
|
device,
|
||||||
_additivePipeline = CreateShellPipeline(
|
"envcell-clip",
|
||||||
device, "envcell-additive", GpuBlendMode.Additive, depthWrite: false, scope.SampleCount);
|
GpuBlendMode.PremultipliedAlpha,
|
||||||
_rawAdditivePipeline = CreateShellPipeline(
|
depthWrite: true,
|
||||||
device, "envcell-raw-additive", GpuBlendMode.RawAdditive, depthWrite: false, scope.SampleCount);
|
scope.SampleCount);
|
||||||
_inversePipeline = CreateShellPipeline(
|
_additivePipeline = CreateShellPipeline(
|
||||||
device, "envcell-inverse", GpuBlendMode.InverseAlpha, depthWrite: false, scope.SampleCount);
|
device, "envcell-additive", GpuBlendMode.Additive, depthWrite: false, scope.SampleCount);
|
||||||
_inverseAdditivePipeline = CreateShellPipeline(
|
_additiveDepthWritePipeline = CreateShellPipeline(
|
||||||
device, "envcell-inverse-additive", GpuBlendMode.InverseAdditive, depthWrite: false, scope.SampleCount);
|
device, "envcell-additive-depth-write", GpuBlendMode.Additive, depthWrite: true, scope.SampleCount);
|
||||||
_initialized = true;
|
_rawAdditivePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-raw-additive", GpuBlendMode.RawAdditive, depthWrite: false, scope.SampleCount);
|
||||||
|
_rawAdditiveDepthWritePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-raw-additive-depth-write", GpuBlendMode.RawAdditive, depthWrite: true, scope.SampleCount);
|
||||||
|
_inversePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-inverse", GpuBlendMode.InverseAlpha, depthWrite: false, scope.SampleCount);
|
||||||
|
_inverseDepthWritePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-inverse-depth-write", GpuBlendMode.InverseAlpha, depthWrite: true, scope.SampleCount);
|
||||||
|
_inverseAdditivePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-inverse-additive", GpuBlendMode.InverseAdditive, depthWrite: false, scope.SampleCount);
|
||||||
|
_inverseAdditiveDepthWritePipeline = CreateShellPipeline(
|
||||||
|
device, "envcell-inverse-additive-depth-write", GpuBlendMode.InverseAdditive, depthWrite: true, scope.SampleCount);
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DisposeRhiResources();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DisableDetailTextures() => false;
|
private static bool DisableDetailTextures() => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// One pipeline per blend state the shell pass uses. Everything else is
|
/// One pipeline per blend/depth-write state the shell pass uses. Everything
|
||||||
/// shared: <c>mesh_modern</c>, the 32-byte world-mesh vertex, triangle lists,
|
/// else is shared: <c>mesh_modern</c>, the 32-byte world-mesh vertex, triangle
|
||||||
/// back-face culling with clockwise front faces.
|
/// lists, back-face culling with clockwise front faces.
|
||||||
///
|
///
|
||||||
/// <para>Depth compare is <see cref="AcDream.App.Rendering.WorldDepthContract.WorldCompare"/>
|
/// <para>Depth compare is <see cref="AcDream.App.Rendering.WorldDepthContract.WorldCompare"/>
|
||||||
/// (<c>Less</c>), not the contract's <c>LessOrEqual</c> default — see that
|
/// (<c>Less</c>), not the contract's <c>LessOrEqual</c> default — see that
|
||||||
|
|
@ -335,11 +358,21 @@ public sealed unsafe partial class EnvCellRenderer
|
||||||
material.Blend switch
|
material.Blend switch
|
||||||
{
|
{
|
||||||
RetailSetSurfaceBlend.Opaque => _opaquePipeline!,
|
RetailSetSurfaceBlend.Opaque => _opaquePipeline!,
|
||||||
RetailSetSurfaceBlend.StraightAlpha => _alphaPipeline!,
|
RetailSetSurfaceBlend.StraightAlpha => material.AlphaTestEnabled
|
||||||
RetailSetSurfaceBlend.AlphaAdditive => _additivePipeline!,
|
? _alphaDepthWritePipeline!
|
||||||
RetailSetSurfaceBlend.Additive => _rawAdditivePipeline!,
|
: _alphaPipeline!,
|
||||||
RetailSetSurfaceBlend.InverseAlpha => _inversePipeline!,
|
RetailSetSurfaceBlend.AlphaAdditive => material.AlphaTestEnabled
|
||||||
RetailSetSurfaceBlend.InverseAdditive => _inverseAdditivePipeline!,
|
? _additiveDepthWritePipeline!
|
||||||
|
: _additivePipeline!,
|
||||||
|
RetailSetSurfaceBlend.Additive => material.AlphaTestEnabled
|
||||||
|
? _rawAdditiveDepthWritePipeline!
|
||||||
|
: _rawAdditivePipeline!,
|
||||||
|
RetailSetSurfaceBlend.InverseAlpha => material.AlphaTestEnabled
|
||||||
|
? _inverseDepthWritePipeline!
|
||||||
|
: _inversePipeline!,
|
||||||
|
RetailSetSurfaceBlend.InverseAdditive => material.AlphaTestEnabled
|
||||||
|
? _inverseAdditiveDepthWritePipeline!
|
||||||
|
: _inverseAdditivePipeline!,
|
||||||
RetailSetSurfaceBlend.Clip => _clipPipeline!,
|
RetailSetSurfaceBlend.Clip => _clipPipeline!,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(material), material, "Unknown SetSurface blend."),
|
_ => throw new ArgumentOutOfRangeException(nameof(material), material, "Unknown SetSurface blend."),
|
||||||
};
|
};
|
||||||
|
|
@ -455,15 +488,25 @@ public sealed unsafe partial class EnvCellRenderer
|
||||||
_opaquePipeline = null;
|
_opaquePipeline = null;
|
||||||
_alphaPipeline?.Dispose();
|
_alphaPipeline?.Dispose();
|
||||||
_alphaPipeline = null;
|
_alphaPipeline = null;
|
||||||
|
_alphaDepthWritePipeline?.Dispose();
|
||||||
|
_alphaDepthWritePipeline = null;
|
||||||
_clipPipeline?.Dispose();
|
_clipPipeline?.Dispose();
|
||||||
_clipPipeline = null;
|
_clipPipeline = null;
|
||||||
_additivePipeline?.Dispose();
|
_additivePipeline?.Dispose();
|
||||||
_additivePipeline = null;
|
_additivePipeline = null;
|
||||||
|
_additiveDepthWritePipeline?.Dispose();
|
||||||
|
_additiveDepthWritePipeline = null;
|
||||||
_rawAdditivePipeline?.Dispose();
|
_rawAdditivePipeline?.Dispose();
|
||||||
_rawAdditivePipeline = null;
|
_rawAdditivePipeline = null;
|
||||||
|
_rawAdditiveDepthWritePipeline?.Dispose();
|
||||||
|
_rawAdditiveDepthWritePipeline = null;
|
||||||
_inversePipeline?.Dispose();
|
_inversePipeline?.Dispose();
|
||||||
_inversePipeline = null;
|
_inversePipeline = null;
|
||||||
|
_inverseDepthWritePipeline?.Dispose();
|
||||||
|
_inverseDepthWritePipeline = null;
|
||||||
_inverseAdditivePipeline?.Dispose();
|
_inverseAdditivePipeline?.Dispose();
|
||||||
_inverseAdditivePipeline = null;
|
_inverseAdditivePipeline = null;
|
||||||
|
_inverseAdditiveDepthWritePipeline?.Dispose();
|
||||||
|
_inverseAdditiveDepthWritePipeline = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
private readonly IWorldPassScope? _scope;
|
private readonly IWorldPassScope? _scope;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The five retail material/blend pipelines at ONE sample count.
|
/// The retail material/blend pipeline variants at ONE sample count.
|
||||||
///
|
///
|
||||||
/// <para>Campaign V slice V6l: there are two of these. Vulkan requires a
|
/// <para>Campaign V slice V6l: there are two of these. Vulkan requires a
|
||||||
/// pipeline's <c>rasterizationSamples</c> to equal the pass it draws in, and
|
/// pipeline's <c>rasterizationSamples</c> to equal the pass it draws in, and
|
||||||
|
|
@ -51,10 +51,15 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
IGpuPipeline Opaque,
|
IGpuPipeline Opaque,
|
||||||
IGpuPipeline OpaqueAlphaToCoverage,
|
IGpuPipeline OpaqueAlphaToCoverage,
|
||||||
IGpuPipeline AlphaBlend,
|
IGpuPipeline AlphaBlend,
|
||||||
|
IGpuPipeline AlphaBlendDepthWrite,
|
||||||
IGpuPipeline AlphaAdditive,
|
IGpuPipeline AlphaAdditive,
|
||||||
|
IGpuPipeline AlphaAdditiveDepthWrite,
|
||||||
IGpuPipeline RawAdditive,
|
IGpuPipeline RawAdditive,
|
||||||
|
IGpuPipeline RawAdditiveDepthWrite,
|
||||||
IGpuPipeline AlphaInverse,
|
IGpuPipeline AlphaInverse,
|
||||||
IGpuPipeline InverseAdditive);
|
IGpuPipeline AlphaInverseDepthWrite,
|
||||||
|
IGpuPipeline InverseAdditive,
|
||||||
|
IGpuPipeline InverseAdditiveDepthWrite);
|
||||||
|
|
||||||
private MeshPipelineSet? _backbufferPipelines;
|
private MeshPipelineSet? _backbufferPipelines;
|
||||||
private MeshPipelineSet? _offscreenPipelines;
|
private MeshPipelineSet? _offscreenPipelines;
|
||||||
|
|
@ -157,7 +162,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The RHI arm's constructor. No GL context, no <c>Shader</c>, no
|
/// The RHI arm's constructor. No GL context, no <c>Shader</c>, no
|
||||||
/// <c>BindlessSupport</c>: five base pipelines compile <c>mesh_modern</c>;
|
/// <c>BindlessSupport</c>: the SetSurface variants compile <c>mesh_modern</c>;
|
||||||
/// batch data already carries the device's own
|
/// batch data already carries the device's own
|
||||||
/// <c>GpuTextureSlot</c> (V4t) rather than a bindless handle.
|
/// <c>GpuTextureSlot</c> (V4t) rather than a bindless handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -229,7 +234,7 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
bool usesRenderPackShaderAbi = false)
|
bool usesRenderPackShaderAbi = false)
|
||||||
{
|
{
|
||||||
string suffix = samples > 1 ? string.Empty : "-1x";
|
string suffix = samples > 1 ? string.Empty : "-1x";
|
||||||
var created = new List<IGpuPipeline>(7);
|
var created = new List<IGpuPipeline>(12);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new MeshPipelineSet(
|
return new MeshPipelineSet(
|
||||||
|
|
@ -249,25 +254,50 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
shaders: baseShaders,
|
shaders: baseShaders,
|
||||||
shaderName: baseShaderName,
|
shaderName: baseShaderName,
|
||||||
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
|
Track(CreateMeshPipeline(
|
||||||
|
device, $"{namePrefix}-alpha-depth-write{suffix}", GpuBlendMode.StraightAlpha, true, false, samples,
|
||||||
|
shaders: baseShaders,
|
||||||
|
shaderName: baseShaderName,
|
||||||
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
Track(CreateMeshPipeline(
|
Track(CreateMeshPipeline(
|
||||||
device, $"{namePrefix}-additive{suffix}", GpuBlendMode.Additive, false, false, samples,
|
device, $"{namePrefix}-additive{suffix}", GpuBlendMode.Additive, false, false, samples,
|
||||||
shaders: baseShaders,
|
shaders: baseShaders,
|
||||||
shaderName: baseShaderName,
|
shaderName: baseShaderName,
|
||||||
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
|
Track(CreateMeshPipeline(
|
||||||
|
device, $"{namePrefix}-additive-depth-write{suffix}", GpuBlendMode.Additive, true, false, samples,
|
||||||
|
shaders: baseShaders,
|
||||||
|
shaderName: baseShaderName,
|
||||||
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
Track(CreateMeshPipeline(
|
Track(CreateMeshPipeline(
|
||||||
device, $"{namePrefix}-raw-additive{suffix}", GpuBlendMode.RawAdditive, false, false, samples,
|
device, $"{namePrefix}-raw-additive{suffix}", GpuBlendMode.RawAdditive, false, false, samples,
|
||||||
shaders: baseShaders,
|
shaders: baseShaders,
|
||||||
shaderName: baseShaderName,
|
shaderName: baseShaderName,
|
||||||
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
|
Track(CreateMeshPipeline(
|
||||||
|
device, $"{namePrefix}-raw-additive-depth-write{suffix}", GpuBlendMode.RawAdditive, true, false, samples,
|
||||||
|
shaders: baseShaders,
|
||||||
|
shaderName: baseShaderName,
|
||||||
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
Track(CreateMeshPipeline(
|
Track(CreateMeshPipeline(
|
||||||
device, $"{namePrefix}-inverse{suffix}", GpuBlendMode.InverseAlpha, false, false, samples,
|
device, $"{namePrefix}-inverse{suffix}", GpuBlendMode.InverseAlpha, false, false, samples,
|
||||||
shaders: baseShaders,
|
shaders: baseShaders,
|
||||||
shaderName: baseShaderName,
|
shaderName: baseShaderName,
|
||||||
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
|
Track(CreateMeshPipeline(
|
||||||
|
device, $"{namePrefix}-inverse-depth-write{suffix}", GpuBlendMode.InverseAlpha, true, false, samples,
|
||||||
|
shaders: baseShaders,
|
||||||
|
shaderName: baseShaderName,
|
||||||
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
Track(CreateMeshPipeline(
|
Track(CreateMeshPipeline(
|
||||||
device, $"{namePrefix}-inverse-additive{suffix}", GpuBlendMode.InverseAdditive, false, false, samples,
|
device, $"{namePrefix}-inverse-additive{suffix}", GpuBlendMode.InverseAdditive, false, false, samples,
|
||||||
shaders: baseShaders,
|
shaders: baseShaders,
|
||||||
shaderName: baseShaderName,
|
shaderName: baseShaderName,
|
||||||
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)),
|
||||||
|
Track(CreateMeshPipeline(
|
||||||
|
device, $"{namePrefix}-inverse-additive-depth-write{suffix}", GpuBlendMode.InverseAdditive, true, false, samples,
|
||||||
|
shaders: baseShaders,
|
||||||
|
shaderName: baseShaderName,
|
||||||
usesRenderPackShaderAbi: usesRenderPackShaderAbi)));
|
usesRenderPackShaderAbi: usesRenderPackShaderAbi)));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
@ -296,8 +326,9 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The imperative <c>Enable/Disable/BlendFunc/DepthMask</c> brackets became
|
/// The imperative <c>Enable/Disable/BlendFunc/DepthMask</c> brackets became
|
||||||
/// pipeline variants: opaque, opaque with alpha-to-coverage, and the three
|
/// pipeline variants: opaque, opaque with alpha-to-coverage, and each retail
|
||||||
/// retail blends. Cull mode and front face stay dynamic per MDI run, exactly
|
/// blend with its alpha-tested depth-write sibling. Cull mode and front face
|
||||||
|
/// stay dynamic per MDI run, exactly
|
||||||
/// where <c>ApplyCullMode</c> sets them, because core Vulkan 1.3 makes those
|
/// where <c>ApplyCullMode</c> sets them, because core Vulkan 1.3 makes those
|
||||||
/// dynamic and blend and alpha-to-coverage not.
|
/// dynamic and blend and alpha-to-coverage not.
|
||||||
///
|
///
|
||||||
|
|
@ -830,11 +861,21 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
IGpuPipeline opaquePipeline) => material.Blend switch
|
IGpuPipeline opaquePipeline) => material.Blend switch
|
||||||
{
|
{
|
||||||
RetailSetSurfaceBlend.Opaque => opaquePipeline,
|
RetailSetSurfaceBlend.Opaque => opaquePipeline,
|
||||||
RetailSetSurfaceBlend.StraightAlpha => pipelines.AlphaBlend,
|
RetailSetSurfaceBlend.StraightAlpha => material.AlphaTestEnabled
|
||||||
RetailSetSurfaceBlend.AlphaAdditive => pipelines.AlphaAdditive,
|
? pipelines.AlphaBlendDepthWrite
|
||||||
RetailSetSurfaceBlend.Additive => pipelines.RawAdditive,
|
: pipelines.AlphaBlend,
|
||||||
RetailSetSurfaceBlend.InverseAlpha => pipelines.AlphaInverse,
|
RetailSetSurfaceBlend.AlphaAdditive => material.AlphaTestEnabled
|
||||||
RetailSetSurfaceBlend.InverseAdditive => pipelines.InverseAdditive,
|
? pipelines.AlphaAdditiveDepthWrite
|
||||||
|
: pipelines.AlphaAdditive,
|
||||||
|
RetailSetSurfaceBlend.Additive => material.AlphaTestEnabled
|
||||||
|
? pipelines.RawAdditiveDepthWrite
|
||||||
|
: pipelines.RawAdditive,
|
||||||
|
RetailSetSurfaceBlend.InverseAlpha => material.AlphaTestEnabled
|
||||||
|
? pipelines.AlphaInverseDepthWrite
|
||||||
|
: pipelines.AlphaInverse,
|
||||||
|
RetailSetSurfaceBlend.InverseAdditive => material.AlphaTestEnabled
|
||||||
|
? pipelines.InverseAdditiveDepthWrite
|
||||||
|
: pipelines.InverseAdditive,
|
||||||
// AP-240: ordinary Gfx/building pure Clip stays on its selected
|
// AP-240: ordinary Gfx/building pure Clip stays on its selected
|
||||||
// opaque/A2C pipeline; exact final-X ParamB still reaches shader.
|
// opaque/A2C pipeline; exact final-X ParamB still reaches shader.
|
||||||
RetailSetSurfaceBlend.Clip => opaquePipeline,
|
RetailSetSurfaceBlend.Clip => opaquePipeline,
|
||||||
|
|
@ -1166,10 +1207,15 @@ public sealed unsafe partial class WbDrawDispatcher
|
||||||
pipelines.Opaque.Dispose();
|
pipelines.Opaque.Dispose();
|
||||||
pipelines.OpaqueAlphaToCoverage.Dispose();
|
pipelines.OpaqueAlphaToCoverage.Dispose();
|
||||||
pipelines.AlphaBlend.Dispose();
|
pipelines.AlphaBlend.Dispose();
|
||||||
|
pipelines.AlphaBlendDepthWrite.Dispose();
|
||||||
pipelines.AlphaAdditive.Dispose();
|
pipelines.AlphaAdditive.Dispose();
|
||||||
|
pipelines.AlphaAdditiveDepthWrite.Dispose();
|
||||||
pipelines.RawAdditive.Dispose();
|
pipelines.RawAdditive.Dispose();
|
||||||
|
pipelines.RawAdditiveDepthWrite.Dispose();
|
||||||
pipelines.AlphaInverse.Dispose();
|
pipelines.AlphaInverse.Dispose();
|
||||||
|
pipelines.AlphaInverseDepthWrite.Dispose();
|
||||||
pipelines.InverseAdditive.Dispose();
|
pipelines.InverseAdditive.Dispose();
|
||||||
|
pipelines.InverseAdditiveDepthWrite.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class NullRhiTimerScope : IDisposable
|
private sealed class NullRhiTimerScope : IDisposable
|
||||||
|
|
|
||||||
|
|
@ -95,16 +95,16 @@ public sealed class EnvCellAlphaDrawSourceTests
|
||||||
{ SurfaceType.Translucent | SurfaceType.InvAlpha, false, "envcell-inverse", GpuBlendMode.InverseAlpha, 0f, true },
|
{ SurfaceType.Translucent | SurfaceType.InvAlpha, false, "envcell-inverse", GpuBlendMode.InverseAlpha, 0f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Base1ClipMap, false, "envcell-clip", GpuBlendMode.PremultipliedAlpha, 200f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.Base1ClipMap, false, "envcell-clip", GpuBlendMode.PremultipliedAlpha, 200f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Base1ClipMap, true, "envcell-clip", GpuBlendMode.PremultipliedAlpha, 100f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.Base1ClipMap, true, "envcell-clip", GpuBlendMode.PremultipliedAlpha, 100f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Base1ClipMap, false, "envcell-alpha", GpuBlendMode.StraightAlpha, 200f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Base1ClipMap, false, "envcell-alpha-depth-write", GpuBlendMode.StraightAlpha, 200f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Base1ClipMap, true, "envcell-alpha", GpuBlendMode.StraightAlpha, 100f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Base1ClipMap, true, "envcell-alpha-depth-write", GpuBlendMode.StraightAlpha, 100f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-additive", GpuBlendMode.Additive, 200f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-additive-depth-write", GpuBlendMode.Additive, 200f / 255f, false },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-additive", GpuBlendMode.Additive, 100f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-additive-depth-write", GpuBlendMode.Additive, 100f / 255f, false },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-raw-additive", GpuBlendMode.RawAdditive, 200f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-raw-additive-depth-write", GpuBlendMode.RawAdditive, 200f / 255f, false },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-raw-additive", GpuBlendMode.RawAdditive, 100f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-raw-additive-depth-write", GpuBlendMode.RawAdditive, 100f / 255f, false },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, false, "envcell-inverse", GpuBlendMode.InverseAlpha, 200f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, false, "envcell-inverse-depth-write", GpuBlendMode.InverseAlpha, 200f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, true, "envcell-inverse", GpuBlendMode.InverseAlpha, 100f / 255f, true },
|
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, true, "envcell-inverse-depth-write", GpuBlendMode.InverseAlpha, 100f / 255f, true },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-inverse-additive", GpuBlendMode.InverseAdditive, 200f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "envcell-inverse-additive-depth-write", GpuBlendMode.InverseAdditive, 200f / 255f, false },
|
||||||
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-inverse-additive", GpuBlendMode.InverseAdditive, 100f / 255f, false },
|
{ SurfaceType.Base1Image | SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "envcell-inverse-additive-depth-write", GpuBlendMode.InverseAdditive, 100f / 255f, false },
|
||||||
{ SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive, false, "envcell-alpha", GpuBlendMode.StraightAlpha, 0f, false },
|
{ SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive, false, "envcell-alpha", GpuBlendMode.StraightAlpha, 0f, false },
|
||||||
{ SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive, true, "envcell-alpha", GpuBlendMode.StraightAlpha, 0f, false },
|
{ SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive, true, "envcell-alpha", GpuBlendMode.StraightAlpha, 0f, false },
|
||||||
};
|
};
|
||||||
|
|
@ -150,7 +150,7 @@ public sealed class EnvCellAlphaDrawSourceTests
|
||||||
Assert.Equal(expectedBlend, selected.Blend);
|
Assert.Equal(expectedBlend, selected.Blend);
|
||||||
Assert.True(selected.Depth.Test);
|
Assert.True(selected.Depth.Test);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
resolved.Blend is RetailSetSurfaceBlend.Opaque or RetailSetSurfaceBlend.Clip,
|
resolved.Blend == RetailSetSurfaceBlend.Opaque || resolved.AlphaTestEnabled,
|
||||||
selected.Depth.Write);
|
selected.Depth.Write);
|
||||||
Assert.Equal(WorldDepthContract.WorldCompare, selected.Depth.Compare);
|
Assert.Equal(WorldDepthContract.WorldCompare, selected.Depth.Compare);
|
||||||
Assert.Equal(0, fixture.Queue.PendingCount);
|
Assert.Equal(0, fixture.Queue.PendingCount);
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ public sealed class RetailDetailTextureContractTests
|
||||||
};
|
};
|
||||||
return new PipelineState(
|
return new PipelineState(
|
||||||
exactBlend,
|
exactBlend,
|
||||||
resolved.Blend is RetailSetSurfaceBlend.Opaque or RetailSetSurfaceBlend.Clip,
|
resolved.Blend == RetailSetSurfaceBlend.Opaque || resolved.AlphaTestEnabled,
|
||||||
resolved.AlphaTestEnabled,
|
resolved.AlphaTestEnabled,
|
||||||
resolved.AlphaTestReference,
|
resolved.AlphaTestReference,
|
||||||
resolved.FogEnabled,
|
resolved.FogEnabled,
|
||||||
|
|
|
||||||
|
|
@ -380,16 +380,16 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
atmospheric: true);
|
atmospheric: true);
|
||||||
using DrawScope draw = fx.BeginDraw();
|
using DrawScope draw = fx.BeginDraw();
|
||||||
OrderedDrawStream stream = StreamOf(
|
OrderedDrawStream stream = StreamOf(
|
||||||
MakeCommand(0),
|
MakeCommand(0, translucency: TranslucencyKind.Additive),
|
||||||
MakeCommand(
|
MakeCommand(
|
||||||
1,
|
1,
|
||||||
translucency: TranslucencyKind.Additive,
|
translucency: TranslucencyKind.Additive,
|
||||||
detailCategory: 1,
|
detailCategory: 1,
|
||||||
materialState: RetailSetSurfaceMaterialState.Resolve(
|
materialState: RetailSetSurfaceMaterialState.Resolve(
|
||||||
SurfaceType.Additive,
|
SurfaceType.Additive | SurfaceType.Base1ClipMap,
|
||||||
texturePresent: true,
|
texturePresent: true,
|
||||||
textureHasPalette: false)),
|
textureHasPalette: false)),
|
||||||
MakeCommand(2));
|
MakeCommand(2, translucency: TranslucencyKind.Additive));
|
||||||
|
|
||||||
PrepareAndDrawWhole(fx.Dispatcher, draw, stream);
|
PrepareAndDrawWhole(fx.Dispatcher, draw, stream);
|
||||||
|
|
||||||
|
|
@ -397,16 +397,24 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
Assert.Equal([(0, 1), (1, 1), (2, 1)],
|
Assert.Equal([(0, 1), (1, 1), (2, 1)],
|
||||||
runs.Select(run => (run.Start, run.Count)).ToList());
|
runs.Select(run => (run.Start, run.Count)).ToList());
|
||||||
Assert.Equal((0u, 0f, 0f, 0), DetailState(runs[0].Constants));
|
Assert.Equal((0u, 0f, 0f, 0), DetailState(runs[0].Constants));
|
||||||
Assert.Equal((77u, 3.5f, 0f, RetailDetailTextureContract.NoFogRenderPassFlag),
|
Assert.Equal((77u, 3.5f, 200f / 255f, RetailDetailTextureContract.NoFogRenderPassFlag),
|
||||||
DetailState(runs[1].Constants));
|
DetailState(runs[1].Constants));
|
||||||
Assert.Equal((0u, 0f, 0f, 0), DetailState(runs[2].Constants));
|
Assert.Equal((0u, 0f, 0f, 0), DetailState(runs[2].Constants));
|
||||||
Assert.Contains(fx.Device.Calls.OfType<GpuRecordedPipelineBind>(),
|
Assert.Contains(fx.Device.Calls.OfType<GpuRecordedPipelineBind>(),
|
||||||
call => call.PipelineName == "wb-mesh-atmospheric-raw-additive-1x");
|
call => call.PipelineName == "wb-mesh-atmospheric-raw-additive-depth-write-1x");
|
||||||
|
Assert.Contains(fx.Device.Calls.OfType<GpuRecordedPipelineBind>(),
|
||||||
|
call => call.PipelineName == "wb-mesh-atmospheric-additive-1x");
|
||||||
GpuPipelineDescription selected = fx.Device.CreatedPipelines
|
GpuPipelineDescription selected = fx.Device.CreatedPipelines
|
||||||
.Single(pipeline => pipeline.Description.Name == "wb-mesh-atmospheric-raw-additive-1x")
|
.Single(pipeline => pipeline.Description.Name == "wb-mesh-atmospheric-raw-additive-depth-write-1x")
|
||||||
.Description;
|
.Description;
|
||||||
Assert.Equal("mesh_atmospheric", selected.Shaders.Name);
|
Assert.Equal("mesh_atmospheric", selected.Shaders.Name);
|
||||||
Assert.Equal(GpuBlendMode.RawAdditive, selected.Blend);
|
Assert.Equal(GpuBlendMode.RawAdditive, selected.Blend);
|
||||||
|
Assert.True(selected.Depth.Write);
|
||||||
|
GpuPipelineDescription adjacent = fx.Device.CreatedPipelines
|
||||||
|
.Single(pipeline => pipeline.Description.Name == "wb-mesh-atmospheric-additive-1x")
|
||||||
|
.Description;
|
||||||
|
Assert.Equal(GpuBlendMode.Additive, adjacent.Blend);
|
||||||
|
Assert.False(adjacent.Depth.Write);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (uint Slot, float Tiling, float Reference, int NoFog) DetailState(
|
private static (uint Slot, float Tiling, float Reference, int NoFog) DetailState(
|
||||||
|
|
@ -414,6 +422,68 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
(constants.TextureIndexA, constants.ParamA, constants.ParamB,
|
(constants.TextureIndexA, constants.ParamA, constants.ParamB,
|
||||||
constants.RenderPass & RetailDetailTextureContract.NoFogRenderPassFlag);
|
constants.RenderPass & RetailDetailTextureContract.NoFogRenderPassFlag);
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(false, "wb-mesh")]
|
||||||
|
[InlineData(true, "wb-mesh-atmospheric")]
|
||||||
|
public void SetSurfacePipelineFamilies_CarryDepthWritePairsAcrossBothSampleCountsAndDispose(
|
||||||
|
bool atmospheric,
|
||||||
|
string prefix)
|
||||||
|
{
|
||||||
|
var fx = new DispatcherFixture(atmospheric: atmospheric, sampleCount: 4);
|
||||||
|
var families = new (string Name, GpuBlendMode Blend)[]
|
||||||
|
{
|
||||||
|
("alpha", GpuBlendMode.StraightAlpha),
|
||||||
|
("additive", GpuBlendMode.Additive),
|
||||||
|
("raw-additive", GpuBlendMode.RawAdditive),
|
||||||
|
("inverse", GpuBlendMode.InverseAlpha),
|
||||||
|
("inverse-additive", GpuBlendMode.InverseAdditive),
|
||||||
|
};
|
||||||
|
var retained = new List<RecordingGpuPipeline>();
|
||||||
|
|
||||||
|
foreach ((string name, GpuBlendMode blend) in families)
|
||||||
|
{
|
||||||
|
foreach ((string suffix, int samples) in new[] { (string.Empty, 4), ("-1x", 1) })
|
||||||
|
{
|
||||||
|
RecordingGpuPipeline depthOff = fx.Device.CreatedPipelines.Single(
|
||||||
|
pipeline => pipeline.Description.Name == $"{prefix}-{name}{suffix}");
|
||||||
|
RecordingGpuPipeline depthOn = fx.Device.CreatedPipelines.Single(
|
||||||
|
pipeline => pipeline.Description.Name == $"{prefix}-{name}-depth-write{suffix}");
|
||||||
|
retained.Add(depthOff);
|
||||||
|
retained.Add(depthOn);
|
||||||
|
Assert.Equal(blend, depthOff.Description.Blend);
|
||||||
|
Assert.Equal(blend, depthOn.Description.Blend);
|
||||||
|
Assert.Equal(samples, depthOff.Description.SampleCount);
|
||||||
|
Assert.Equal(samples, depthOn.Description.SampleCount);
|
||||||
|
Assert.True(depthOff.Description.Depth.Test);
|
||||||
|
Assert.True(depthOn.Description.Depth.Test);
|
||||||
|
Assert.False(depthOff.Description.Depth.Write);
|
||||||
|
Assert.True(depthOn.Description.Depth.Write);
|
||||||
|
Assert.Equal(WorldDepthContract.WorldCompare, depthOff.Description.Depth.Compare);
|
||||||
|
Assert.Equal(WorldDepthContract.WorldCompare, depthOn.Description.Depth.Compare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fx.Dispose();
|
||||||
|
|
||||||
|
Assert.All(retained, static pipeline => Assert.True(pipeline.IsDisposed));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetSurfacePipelineConstructionFailureRollsBackBothSampleCountOwners()
|
||||||
|
{
|
||||||
|
using var device = new RecordingGpuDevice();
|
||||||
|
device.PipelineFailure = description =>
|
||||||
|
description.Name == "wb-mesh-inverse-depth-write-1x"
|
||||||
|
? new InvalidOperationException("injected pipeline failure")
|
||||||
|
: null;
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
|
new DispatcherFixture(sampleCount: 4, device: device));
|
||||||
|
|
||||||
|
Assert.Equal(21, device.CreatedPipelines.Count);
|
||||||
|
Assert.All(device.CreatedPipelines, static pipeline => Assert.True(pipeline.IsDisposed));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PrepareThenDraw_OpaqueRunUsesRenderPassZeroAndAlphaBlendRunUsesRenderPassOne()
|
public void PrepareThenDraw_OpaqueRunUsesRenderPassZeroAndAlphaBlendRunUsesRenderPassOne()
|
||||||
{
|
{
|
||||||
|
|
@ -707,11 +777,13 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
public DispatcherFixture(
|
public DispatcherFixture(
|
||||||
bool detailAvailable = false,
|
bool detailAvailable = false,
|
||||||
bool detailEnabled = false,
|
bool detailEnabled = false,
|
||||||
bool atmospheric = false)
|
bool atmospheric = false,
|
||||||
|
int sampleCount = 1,
|
||||||
|
RecordingGpuDevice? device = null)
|
||||||
{
|
{
|
||||||
Device = new RecordingGpuDevice();
|
Device = device ?? new RecordingGpuDevice();
|
||||||
FrameLifetime = new GpuDeviceFrameLifetime(Device);
|
FrameLifetime = new GpuDeviceFrameLifetime(Device);
|
||||||
Scope = new VulkanWorldPassScope(sampleCount: 1);
|
Scope = new VulkanWorldPassScope(sampleCount);
|
||||||
_textures = new TextureCache(Device, new NoopDatReaderWriter());
|
_textures = new TextureCache(Device, new NoopDatReaderWriter());
|
||||||
_meshAdapter = new WbMeshAdapter(
|
_meshAdapter = new WbMeshAdapter(
|
||||||
Device,
|
Device,
|
||||||
|
|
@ -743,7 +815,7 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
var source = new BindableAtmosphericSource();
|
var source = new BindableAtmosphericSource();
|
||||||
WbDrawDispatcher.DirectionalShadowReceiverPipelineState candidate =
|
WbDrawDispatcher.DirectionalShadowReceiverPipelineState candidate =
|
||||||
Assert.IsType<WbDrawDispatcher.DirectionalShadowReceiverPipelineState>(
|
Assert.IsType<WbDrawDispatcher.DirectionalShadowReceiverPipelineState>(
|
||||||
Dispatcher.PrepareDirectionalShadowReceiver(source, sampleCount: 1));
|
Dispatcher.PrepareDirectionalShadowReceiver(source, sampleCount));
|
||||||
Assert.Null(Dispatcher.SwapDirectionalShadowReceiver(candidate));
|
Assert.Null(Dispatcher.SwapDirectionalShadowReceiver(candidate));
|
||||||
}
|
}
|
||||||
Atmospheric = atmospheric;
|
Atmospheric = atmospheric;
|
||||||
|
|
@ -772,7 +844,7 @@ public sealed class OrderPreservingSubmitterTests
|
||||||
? DirectionalShadowReceiverPolicy.AtmosphericWorldPassName
|
? DirectionalShadowReceiverPolicy.AtmosphericWorldPassName
|
||||||
: "fw2-ordered-stream-test",
|
: "fw2-ordered-stream-test",
|
||||||
Vector4.Zero,
|
Vector4.Zero,
|
||||||
sampleCount: 1));
|
Scope.SampleCount));
|
||||||
IDisposable publication = Scope.Publish(pass);
|
IDisposable publication = Scope.Publish(pass);
|
||||||
Device.Clear();
|
Device.Clear();
|
||||||
return new DrawScope(frame, pass, publication);
|
return new DrawScope(frame, pass, publication);
|
||||||
|
|
|
||||||
|
|
@ -1240,16 +1240,16 @@ public sealed class WalkStaticStreamPopulatorTests
|
||||||
[InlineData(SurfaceType.Translucent, false, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 0f, true)]
|
[InlineData(SurfaceType.Translucent, false, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 0f, true)]
|
||||||
[InlineData(SurfaceType.Translucent | SurfaceType.Additive, false, "wb-mesh-raw-additive-1x", GpuBlendMode.RawAdditive, 0f, false)]
|
[InlineData(SurfaceType.Translucent | SurfaceType.Additive, false, "wb-mesh-raw-additive-1x", GpuBlendMode.RawAdditive, 0f, false)]
|
||||||
[InlineData(SurfaceType.Translucent | SurfaceType.InvAlpha, false, "wb-mesh-inverse-1x", GpuBlendMode.InverseAlpha, 0f, true)]
|
[InlineData(SurfaceType.Translucent | SurfaceType.InvAlpha, false, "wb-mesh-inverse-1x", GpuBlendMode.InverseAlpha, 0f, true)]
|
||||||
[InlineData(SurfaceType.Alpha | SurfaceType.Base1ClipMap, false, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 200f / 255f, true)]
|
[InlineData(SurfaceType.Alpha | SurfaceType.Base1ClipMap, false, "wb-mesh-alpha-depth-write-1x", GpuBlendMode.StraightAlpha, 200f / 255f, true)]
|
||||||
[InlineData(SurfaceType.Alpha | SurfaceType.Base1ClipMap, true, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 100f / 255f, true)]
|
[InlineData(SurfaceType.Alpha | SurfaceType.Base1ClipMap, true, "wb-mesh-alpha-depth-write-1x", GpuBlendMode.StraightAlpha, 100f / 255f, true)]
|
||||||
[InlineData(SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-additive-1x", GpuBlendMode.Additive, 200f / 255f, false)]
|
[InlineData(SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-additive-depth-write-1x", GpuBlendMode.Additive, 200f / 255f, false)]
|
||||||
[InlineData(SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-additive-1x", GpuBlendMode.Additive, 100f / 255f, false)]
|
[InlineData(SurfaceType.Alpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-additive-depth-write-1x", GpuBlendMode.Additive, 100f / 255f, false)]
|
||||||
[InlineData(SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-raw-additive-1x", GpuBlendMode.RawAdditive, 200f / 255f, false)]
|
[InlineData(SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-raw-additive-depth-write-1x", GpuBlendMode.RawAdditive, 200f / 255f, false)]
|
||||||
[InlineData(SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-raw-additive-1x", GpuBlendMode.RawAdditive, 100f / 255f, false)]
|
[InlineData(SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-raw-additive-depth-write-1x", GpuBlendMode.RawAdditive, 100f / 255f, false)]
|
||||||
[InlineData(SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, false, "wb-mesh-inverse-1x", GpuBlendMode.InverseAlpha, 200f / 255f, true)]
|
[InlineData(SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, false, "wb-mesh-inverse-depth-write-1x", GpuBlendMode.InverseAlpha, 200f / 255f, true)]
|
||||||
[InlineData(SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, true, "wb-mesh-inverse-1x", GpuBlendMode.InverseAlpha, 100f / 255f, true)]
|
[InlineData(SurfaceType.InvAlpha | SurfaceType.Base1ClipMap, true, "wb-mesh-inverse-depth-write-1x", GpuBlendMode.InverseAlpha, 100f / 255f, true)]
|
||||||
[InlineData(SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-inverse-additive-1x", GpuBlendMode.InverseAdditive, 200f / 255f, false)]
|
[InlineData(SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, false, "wb-mesh-inverse-additive-depth-write-1x", GpuBlendMode.InverseAdditive, 200f / 255f, false)]
|
||||||
[InlineData(SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-inverse-additive-1x", GpuBlendMode.InverseAdditive, 100f / 255f, false)]
|
[InlineData(SurfaceType.InvAlpha | SurfaceType.Additive | SurfaceType.Base1ClipMap, true, "wb-mesh-inverse-additive-depth-write-1x", GpuBlendMode.InverseAdditive, 100f / 255f, false)]
|
||||||
[InlineData(SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive,
|
[InlineData(SurfaceType.Translucent | SurfaceType.Base1ClipMap | SurfaceType.Additive,
|
||||||
true, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 0f, false)]
|
true, "wb-mesh-alpha-1x", GpuBlendMode.StraightAlpha, 0f, false)]
|
||||||
public void ImmediateBuildingDetail_UsesExactResolvedSetSurfaceState(
|
public void ImmediateBuildingDetail_UsesExactResolvedSetSurfaceState(
|
||||||
|
|
@ -1294,7 +1294,7 @@ public sealed class WalkStaticStreamPopulatorTests
|
||||||
Assert.Equal(expectedBlend, selected.Blend);
|
Assert.Equal(expectedBlend, selected.Blend);
|
||||||
Assert.True(selected.Depth.Test);
|
Assert.True(selected.Depth.Test);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
resolved.Blend is RetailSetSurfaceBlend.Opaque or RetailSetSurfaceBlend.Clip,
|
resolved.Blend == RetailSetSurfaceBlend.Opaque || resolved.AlphaTestEnabled,
|
||||||
selected.Depth.Write);
|
selected.Depth.Write);
|
||||||
Assert.Equal(WorldDepthContract.WorldCompare, selected.Depth.Compare);
|
Assert.Equal(WorldDepthContract.WorldCompare, selected.Depth.Compare);
|
||||||
Vector4 source = RetailDetailTextureContract.Combine(
|
Vector4 source = RetailDetailTextureContract.Combine(
|
||||||
|
|
|
||||||
|
|
@ -252,11 +252,51 @@ public class EnvCellRendererTests
|
||||||
meshManager,
|
meshManager,
|
||||||
new WbFrustum());
|
new WbFrustum());
|
||||||
|
|
||||||
Assert.Equal(7, device.CreatedPipelines.Count);
|
Assert.Equal(12, device.CreatedPipelines.Count);
|
||||||
Assert.DoesNotContain(device.CreatedPipelines,
|
Assert.DoesNotContain(device.CreatedPipelines,
|
||||||
pipeline => pipeline.Description.Name.Contains("detail", StringComparison.Ordinal));
|
pipeline => pipeline.Description.Name.Contains("detail", StringComparison.Ordinal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetSurfacePipelineConstructionFailureDisposesEveryCompletedVariant()
|
||||||
|
{
|
||||||
|
using var device = new RecordingGpuDevice();
|
||||||
|
using var meshManager = CreateMeshManager(device);
|
||||||
|
device.PipelineFailure = description =>
|
||||||
|
description.Name == "envcell-inverse-depth-write"
|
||||||
|
? new InvalidOperationException("injected pipeline failure")
|
||||||
|
: null;
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => new EnvCellRenderer(
|
||||||
|
device,
|
||||||
|
new GpuDeviceFrameLifetime(device),
|
||||||
|
new VulkanWorldPassScope(sampleCount: 1),
|
||||||
|
meshManager,
|
||||||
|
new WbFrustum()));
|
||||||
|
|
||||||
|
Assert.Equal(9, device.CreatedPipelines.Count);
|
||||||
|
Assert.All(device.CreatedPipelines, static pipeline => Assert.True(pipeline.IsDisposed));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DisposeReleasesEverySetSurfacePipelineVariant()
|
||||||
|
{
|
||||||
|
using var device = new RecordingGpuDevice();
|
||||||
|
using var meshManager = CreateMeshManager(device);
|
||||||
|
var renderer = new EnvCellRenderer(
|
||||||
|
device,
|
||||||
|
new GpuDeviceFrameLifetime(device),
|
||||||
|
new VulkanWorldPassScope(sampleCount: 1),
|
||||||
|
meshManager,
|
||||||
|
new WbFrustum());
|
||||||
|
RecordingGpuPipeline[] pipelines = device.CreatedPipelines.ToArray();
|
||||||
|
|
||||||
|
renderer.Dispose();
|
||||||
|
|
||||||
|
Assert.Equal(12, pipelines.Length);
|
||||||
|
Assert.All(pipelines, static pipeline => Assert.True(pipeline.IsDisposed));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OrderedMdiRanges_CoalesceAdjacentCellsWithIdenticalState()
|
public void OrderedMdiRanges_CoalesceAdjacentCellsWithIdenticalState()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue