feat(render): Vulkan campaign V11 step 2 — delete the OpenGL backend
Vulkan is the sole, user-signed-off backend (V10 landed) and step 1 already removed ImGui/Studio/DevTools. This step deletes the GL rendering backend itself: every Gpu/Gl/** implementation, the Wb ManagedGL*/GLHelpers/GLSLShader/GLStateScope/RenderStateCache/ BindlessSupport family, Shader/ShaderProgramConstruction/SamplerCache, RenderBootstrap, and RenderFrameGlStateController. GameWindow.cs's Run()/CreateGraphics()/CreateBackbufferReader()/ OnLoad() collapse to their Vulkan-only arm; GameWindowGraphics loses its OpenGlGameWindowGraphics subclass. RuntimeOptions.RenderBackend and RenderBackendKind (incl. the Gl member of GpuBackendKind) are gone — there is nothing left to select between. The five world-draw dual-arm renderers (WbDrawDispatcher, EnvCellRenderer, TerrainModernRenderer, ParticleRenderer, SkyRenderer) and the composition roots (WorldRenderComposition, HostInputCameraComposition, LivePresentationComposition, FrameRootComposition) collapse to their RHI-only arm. GL-only diagnostic properties with a live external reader (DynamicBufferCount and friends) simplify to a documented `=> 0`/no-op rather than disappearing, since the reader is out of this commit's scope. A few GL-flavored mechanisms turned out to be backend-neutral once isolated: GlConstructionCleanupLedger is renamed ResourceConstructionCleanupLedger (exception-chain walking has nothing to do with GL), and GlfwNativePlatformProbe moved out of the otherwise GL-only GraphicalCapabilityRecord.cs into GraphicalWindowBackendSelection.cs before the rest of that file was deleted. Test files with no surviving subject are deleted outright (GraphicalCapabilityRequirementsTests, ShaderProgramConstructionTests, PortalDepthShaderParityTests, TextureCacheBindlessTests, TextRendererFailureSafetyTests, ClipFrameUploadTests, every Gpu/Gl/*Tests, GlTextureOwnershipTests, RenderFrameGlStateControllerTests); others get their dead GL-only members trimmed while their live assertions stay (ClipFrameLayoutTests' MeshClipSsboBinding check now reads GpuBindingModel.StorageClipRegions, the same binding index under its new backend-neutral name; GpuResourceRetirementTransactionTests drops its OpenGLGraphicsDevice-subclassing test double and the two GL queue tests it existed for). EnvCellRendererTests' construction helper now builds a real ObjectMeshManager via VulkanMeshPipelineDevice instead of passing null through a null-forgiving operator, since the RHI constructor never tolerated a null mesh manager and the old GL constructor (which did) is gone. Deferred to the next two steps, deliberately not touched here: the Silk.NET.OpenGL/.Extensions.ARB package references, IMeshPipelineDevice.Gl (WbMeshAdapter's GL? threading stays in place), Chorizite.Core's stale csproj comment (the package itself is still load-bearing — TextureFormat and friends are used well beyond the deleted ManagedGLUniformBuffer), and the CI/gate scripts. Build: `dotnet build AcDream.slnx -c Release` — 0 warnings, 0 errors. Tests: full-solution `dotnet test` green across every project (App.Tests 3937/3940 + 3 skips, Core.Tests 3296/3298 + 2 skips, all others 100%); the 2 App.Tests names that flake under full-suite parallel execution (#250-family, documented pre-existing) pass in isolation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b70b9832ff
commit
8a7a0837e1
121 changed files with 1243 additions and 19840 deletions
|
|
@ -14,7 +14,6 @@ using DatReaderWriter.DBObjs;
|
|||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Silk.NET.Input;
|
||||
using Silk.NET.OpenGL;
|
||||
using Shader = AcDream.App.Rendering.Shader;
|
||||
|
||||
namespace AcDream.App.Composition;
|
||||
|
||||
|
|
@ -31,27 +30,21 @@ internal sealed record WorldTerrainBuildContext(
|
|||
/// <summary>
|
||||
/// The render foundation the later phases build on.
|
||||
///
|
||||
/// <para>Campaign V slice V6h made every raw-GL member nullable. They are all
|
||||
/// present on GL and all absent on Vulkan, because the world renderers that own
|
||||
/// them are still raw GL until slices V4t/V4c/V4d land the Vulkan world arm.
|
||||
/// What survives on both backends is exactly the RHI-ported set — the texture
|
||||
/// cache's UI path, the debug font, the text renderer and the debug lines — plus
|
||||
/// the backend-neutral residency ledger and shader directory.</para>
|
||||
/// <para>Every member here is backend-neutral. The raw-GL-only members this
|
||||
/// record used to carry (<c>Bindless</c>, <c>TerrainShader</c>, <c>MeshShader</c>,
|
||||
/// <c>Samplers</c>) were deleted at Campaign V slice V11 along with the GL arm
|
||||
/// that was their only producer.</para>
|
||||
/// </summary>
|
||||
internal sealed record WorldRenderFoundation(
|
||||
string ShadersDirectory,
|
||||
BindlessSupport? Bindless,
|
||||
TerrainAtlas? TerrainAtlas,
|
||||
Shader? TerrainShader,
|
||||
SceneLightingUboBinding? SceneLighting,
|
||||
DebugLineRenderer DebugLines,
|
||||
BitmapFont? DebugFont,
|
||||
TextRenderer? TextRenderer,
|
||||
TerrainModernRenderer? Terrain,
|
||||
Shader? MeshShader,
|
||||
WbMeshAdapter? MeshAdapter,
|
||||
TextureCache TextureCache,
|
||||
SamplerCache? Samplers,
|
||||
ResidencyManager Residency);
|
||||
|
||||
internal sealed record WorldRenderResult(
|
||||
|
|
@ -71,8 +64,6 @@ internal sealed record WorldRenderDependencies(
|
|||
|
||||
internal interface IGameWindowWorldRenderPublication
|
||||
{
|
||||
void PublishBindlessSupport(BindlessSupport value);
|
||||
void PublishTerrainShader(Shader value);
|
||||
void PublishSceneLighting(SceneLightingUboBinding value);
|
||||
void PublishDebugLines(DebugLineRenderer value);
|
||||
void PublishHudResources(BitmapFont font, TextRenderer text);
|
||||
|
|
@ -81,27 +72,20 @@ internal interface IGameWindowWorldRenderPublication
|
|||
float[] heightTable,
|
||||
TerrainBlendingContext blending,
|
||||
ConcurrentDictionary<uint, SurfaceInfo> surfaceCache);
|
||||
void PublishMeshShader(Shader value);
|
||||
void PublishWbMeshAdapter(WbMeshAdapter value);
|
||||
void PublishTextureCache(TextureCache value);
|
||||
void PublishSamplerCache(SamplerCache value);
|
||||
}
|
||||
|
||||
internal interface IWorldRenderCompositionFactory
|
||||
{
|
||||
void InitializeGlState(GL gl);
|
||||
WorldRegionData LoadRegion(IDatReaderWriter dats);
|
||||
void InitializeEnvironment(WorldEnvironmentController environment, Region region);
|
||||
BindlessSupport RequireBindless(GL gl, Action<string> log);
|
||||
TerrainAtlas AcquireTerrainAtlas(
|
||||
IGameRenderResourceLifetime lifetime,
|
||||
GL gl,
|
||||
IDatReaderWriter dats,
|
||||
BindlessSupport bindless);
|
||||
/// <summary>
|
||||
/// Campaign V slice V6i-2: the terrain atlas built through
|
||||
/// <see cref="AcDream.App.Rendering.Gpu.IGpuDevice"/> rather than raw GL.
|
||||
/// Same DATs, same decode, same layer ordering — only the upload differs.
|
||||
/// <see cref="AcDream.App.Rendering.Gpu.IGpuDevice"/>. The raw-GL arm this
|
||||
/// used to fork from (<c>AcquireTerrainAtlas</c>) was deleted at slice V11;
|
||||
/// the name keeps its "BackendNeutral" suffix rather than being renamed, to
|
||||
/// avoid touching every call site for a purely cosmetic change.
|
||||
/// </summary>
|
||||
TerrainAtlas AcquireBackendNeutralTerrainAtlas(
|
||||
IGameRenderResourceLifetime lifetime,
|
||||
|
|
@ -120,12 +104,11 @@ internal interface IWorldRenderCompositionFactory
|
|||
Action<string> log);
|
||||
|
||||
void SetTerrainAnisotropic(TerrainAtlas atlas, int level);
|
||||
Shader CreateTerrainShader(GL gl, string shadersDirectory);
|
||||
SceneLightingUboBinding CreateSceneLighting(GL gl);
|
||||
/// <summary>
|
||||
/// Campaign V slice V6j: scene lighting on a backend with no global uniform
|
||||
/// binding point. It publishes a ring section on the world pass scope and
|
||||
/// each renderer binds it inside the pass.
|
||||
/// each renderer binds it inside the pass. The raw-GL global-uniform-binding
|
||||
/// arm (<c>CreateSceneLighting</c>) was deleted at slice V11.
|
||||
/// </summary>
|
||||
SceneLightingUboBinding CreateBackendNeutralSceneLighting(
|
||||
ICurrentGpuFrameSource frameSource,
|
||||
|
|
@ -140,17 +123,11 @@ internal interface IWorldRenderCompositionFactory
|
|||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
ICurrentGpuFrameSource frameSource,
|
||||
string shadersDirectory);
|
||||
TerrainModernRenderer CreateTerrain(
|
||||
GL gl,
|
||||
BindlessSupport bindless,
|
||||
Shader shader,
|
||||
TerrainAtlas atlas,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice gpuDevice,
|
||||
IGpuResourceRetirementQueue retirement);
|
||||
/// <summary>
|
||||
/// Campaign V slice V6j: terrain's RHI arm. No GL context, no linked
|
||||
/// program — the pipeline compiles <c>terrain_modern</c> from the committed
|
||||
/// SPIR-V and records into the world pass the scope publishes.
|
||||
/// SPIR-V and records into the world pass the scope publishes. The raw-GL
|
||||
/// arm (<c>CreateTerrain</c>) was deleted at slice V11.
|
||||
/// </summary>
|
||||
TerrainModernRenderer CreateBackendNeutralTerrain(
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice gpuDevice,
|
||||
|
|
@ -170,7 +147,6 @@ internal interface IWorldRenderCompositionFactory
|
|||
uint initialCenterLandblockId,
|
||||
float[] heightTable,
|
||||
TerrainAtlas? atlas);
|
||||
Shader CreateMeshShader(GL gl, string shadersDirectory);
|
||||
WbMeshAdapter CreateMeshAdapter(
|
||||
GL? gl,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
|
|
@ -179,10 +155,8 @@ internal interface IWorldRenderCompositionFactory
|
|||
IGpuResourceRetirementQueue retirement,
|
||||
ResidencyBudgetOptions budgets);
|
||||
TextureCache CreateTextureCache(
|
||||
GL? gl,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
IDatReaderWriter dats,
|
||||
BindlessSupport? bindless,
|
||||
IGpuResourceRetirementQueue retirement,
|
||||
string diagnosticsDirectory,
|
||||
ResidencyBudgetOptions budgets);
|
||||
|
|
@ -193,20 +167,12 @@ internal interface IWorldRenderCompositionFactory
|
|||
IPreparedAssetSource preparedAssets,
|
||||
IAnimationLoader animations,
|
||||
DatSoundCache? audio);
|
||||
SamplerCache CreateSamplerCache(GL gl);
|
||||
void Release(IDisposable resource);
|
||||
}
|
||||
|
||||
internal sealed class RetailWorldRenderCompositionFactory
|
||||
: IWorldRenderCompositionFactory
|
||||
{
|
||||
public void InitializeGlState(GL gl)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(gl);
|
||||
gl.ClearColor(0.05f, 0.10f, 0.18f, 1.0f);
|
||||
gl.Enable(EnableCap.DepthTest);
|
||||
}
|
||||
|
||||
public WorldRegionData LoadRegion(IDatReaderWriter dats)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dats);
|
||||
|
|
@ -231,46 +197,6 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
environment.Initialize(region);
|
||||
}
|
||||
|
||||
public BindlessSupport RequireBindless(GL gl, Action<string> log)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(gl);
|
||||
ArgumentNullException.ThrowIfNull(log);
|
||||
if (BindlessSupport.TryCreate(gl, out BindlessSupport? bindless))
|
||||
{
|
||||
if (bindless!.HasShaderDrawParameters(gl))
|
||||
{
|
||||
log("[N.5] modern path capabilities present " +
|
||||
"(bindless + ARB_shader_draw_parameters)");
|
||||
return bindless;
|
||||
}
|
||||
log("[N.5] GL_ARB_shader_draw_parameters not present — " +
|
||||
"modern path not available");
|
||||
}
|
||||
else
|
||||
{
|
||||
log("[N.5] GL_ARB_bindless_texture not present — " +
|
||||
"modern path not available");
|
||||
}
|
||||
|
||||
throw new NotSupportedException(
|
||||
"acdream requires GL_ARB_bindless_texture + " +
|
||||
"GL_ARB_shader_draw_parameters (GL 4.3+ with bindless support). " +
|
||||
"Your GPU/driver does not expose these extensions. If this is " +
|
||||
"unexpected, please file a bug report with your GPU vendor + " +
|
||||
"driver version.");
|
||||
}
|
||||
|
||||
public TerrainAtlas AcquireTerrainAtlas(
|
||||
IGameRenderResourceLifetime lifetime,
|
||||
GL gl,
|
||||
IDatReaderWriter dats,
|
||||
BindlessSupport bindless)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(lifetime);
|
||||
return lifetime.AcquireTerrainAtlas(
|
||||
() => TerrainAtlas.Build(gl, dats, bindless));
|
||||
}
|
||||
|
||||
public TerrainAtlas AcquireBackendNeutralTerrainAtlas(
|
||||
IGameRenderResourceLifetime lifetime,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
|
|
@ -289,15 +215,6 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
public void SetTerrainAnisotropic(TerrainAtlas atlas, int level) =>
|
||||
atlas.SetAnisotropic(level);
|
||||
|
||||
public Shader CreateTerrainShader(GL gl, string shadersDirectory) =>
|
||||
new(
|
||||
gl,
|
||||
Path.Combine(shadersDirectory, "terrain_modern.vert"),
|
||||
Path.Combine(shadersDirectory, "terrain_modern.frag"),
|
||||
includeCommonPreamble: true);
|
||||
|
||||
public SceneLightingUboBinding CreateSceneLighting(GL gl) => new(gl);
|
||||
|
||||
public SceneLightingUboBinding CreateBackendNeutralSceneLighting(
|
||||
ICurrentGpuFrameSource frameSource,
|
||||
IWorldPassScope scope) =>
|
||||
|
|
@ -321,25 +238,6 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
string shadersDirectory) =>
|
||||
new(device, frameSource, shadersDirectory);
|
||||
|
||||
public TerrainModernRenderer CreateTerrain(
|
||||
GL gl,
|
||||
BindlessSupport bindless,
|
||||
Shader shader,
|
||||
TerrainAtlas atlas,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice gpuDevice,
|
||||
IGpuResourceRetirementQueue retirement) =>
|
||||
// Campaign V slice V4t: terrain's atlas slots live in the device's one
|
||||
// texture table. This renderer only exists on GL — the `gl is not null`
|
||||
// gate at its call site is the same one — so the backend cast is a
|
||||
// statement of that fact rather than a narrowing.
|
||||
new(
|
||||
gl,
|
||||
bindless,
|
||||
shader,
|
||||
atlas,
|
||||
(AcDream.App.Rendering.Gpu.Gl.GlGpuDevice)gpuDevice,
|
||||
retirement);
|
||||
|
||||
public TerrainModernRenderer CreateBackendNeutralTerrain(
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice gpuDevice,
|
||||
ICurrentGpuFrameSource frameSource,
|
||||
|
|
@ -400,13 +298,6 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
new ConcurrentDictionary<uint, SurfaceInfo>());
|
||||
}
|
||||
|
||||
public Shader CreateMeshShader(GL gl, string shadersDirectory) =>
|
||||
new(
|
||||
gl,
|
||||
Path.Combine(shadersDirectory, "mesh_modern.vert"),
|
||||
Path.Combine(shadersDirectory, "mesh_modern.frag"),
|
||||
includeCommonPreamble: true);
|
||||
|
||||
public WbMeshAdapter CreateMeshAdapter(
|
||||
GL? gl,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
|
|
@ -424,18 +315,14 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
budgets);
|
||||
|
||||
public TextureCache CreateTextureCache(
|
||||
GL? gl,
|
||||
AcDream.App.Rendering.Gpu.IGpuDevice device,
|
||||
IDatReaderWriter dats,
|
||||
BindlessSupport? bindless,
|
||||
IGpuResourceRetirementQueue retirement,
|
||||
string diagnosticsDirectory,
|
||||
ResidencyBudgetOptions budgets) =>
|
||||
new(
|
||||
gl,
|
||||
device,
|
||||
dats,
|
||||
bindless,
|
||||
retirement,
|
||||
diagnosticsDirectory,
|
||||
budgets);
|
||||
|
|
@ -501,19 +388,14 @@ internal sealed class RetailWorldRenderCompositionFactory
|
|||
}
|
||||
}
|
||||
|
||||
public SamplerCache CreateSamplerCache(GL gl) => new(gl);
|
||||
|
||||
public void Release(IDisposable resource) => resource.Dispose();
|
||||
}
|
||||
|
||||
internal enum WorldRenderCompositionPoint
|
||||
{
|
||||
GlStateInitialized,
|
||||
RegionLoaded,
|
||||
EnvironmentInitialized,
|
||||
BindlessPublished,
|
||||
TerrainAtlasAcquired,
|
||||
TerrainShaderPublished,
|
||||
SceneLightingPublished,
|
||||
DebugLinesPublished,
|
||||
DebugFontCreated,
|
||||
|
|
@ -522,10 +404,8 @@ internal enum WorldRenderCompositionPoint
|
|||
HudResourcesCompleted,
|
||||
TerrainPublished,
|
||||
TerrainBuildStatePublished,
|
||||
MeshShaderPublished,
|
||||
MeshAdapterPublished,
|
||||
TextureCachePublished,
|
||||
SamplerCachePublished,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -571,91 +451,53 @@ internal sealed class WorldRenderCompositionPhase
|
|||
var scope = new CompositionAcquisitionScope();
|
||||
try
|
||||
{
|
||||
// Campaign V slice V6h: null on a backend with no GL context. Every
|
||||
// world renderer below is still raw GL, so the Vulkan arm composes
|
||||
// the RHI-ported subset only — the texture cache's UI path, the
|
||||
// debug font, the text renderer, the debug lines — and leaves the
|
||||
// world absent until slices V4t/V4c/V4d land it.
|
||||
GL? gl = platform.Graphics.Gl;
|
||||
var residency = new ResidencyManager(
|
||||
_dependencies.ResidencyBudgets);
|
||||
if (gl is not null)
|
||||
_factory.InitializeGlState(gl);
|
||||
Fault(WorldRenderCompositionPoint.GlStateInitialized);
|
||||
|
||||
WorldRegionData region = _factory.LoadRegion(content.Dats);
|
||||
Fault(WorldRenderCompositionPoint.RegionLoaded);
|
||||
_factory.InitializeEnvironment(_dependencies.Environment, region.Region);
|
||||
Fault(WorldRenderCompositionPoint.EnvironmentInitialized);
|
||||
|
||||
BindlessSupport? bindless = gl is null
|
||||
? null
|
||||
: _factory.RequireBindless(gl, _dependencies.Log);
|
||||
if (bindless is not null)
|
||||
_publication.PublishBindlessSupport(bindless);
|
||||
Fault(WorldRenderCompositionPoint.BindlessPublished);
|
||||
|
||||
// Campaign V slice V6i-2: the atlas exists on BOTH arms now. GL
|
||||
// builds it from raw texture names as before; a backend with no GL
|
||||
// context builds the same layers through IGpuDevice.CreateTexture.
|
||||
// That is what makes the blending/T-code tables below real on
|
||||
// Vulkan — and, more to the point, it is what puts the new creation
|
||||
// path under the validation layer instead of leaving it a claim.
|
||||
TerrainAtlas? terrainAtlas = gl is not null && bindless is not null
|
||||
? _factory.AcquireTerrainAtlas(
|
||||
_dependencies.RenderResources,
|
||||
gl,
|
||||
content.Dats,
|
||||
bindless)
|
||||
: _factory.AcquireBackendNeutralTerrainAtlas(
|
||||
_dependencies.RenderResources,
|
||||
_dependencies.GpuDevice,
|
||||
content.Dats);
|
||||
// Campaign V slice V6i-2: the atlas builds through IGpuDevice on
|
||||
// every remaining backend. The raw-GL arm that built it from raw
|
||||
// texture names was deleted at slice V11.
|
||||
TerrainAtlas terrainAtlas = _factory.AcquireBackendNeutralTerrainAtlas(
|
||||
_dependencies.RenderResources,
|
||||
_dependencies.GpuDevice,
|
||||
content.Dats);
|
||||
_factory.SetTerrainAnisotropic(
|
||||
terrainAtlas,
|
||||
settings.ResolvedQuality.AnisotropicLevel);
|
||||
Fault(WorldRenderCompositionPoint.TerrainAtlasAcquired);
|
||||
|
||||
// The rest of the world texture stack's creation path, exercised on
|
||||
// the arm that has no GL: one shared array of each format family and
|
||||
// one composite array, created and released here. Nothing draws
|
||||
// them; see the type's own documentation for why they are built
|
||||
// anyway. It claims no composition point and enters no acquisition
|
||||
// scope — the frozen publication order is a pinned assertion, and an
|
||||
// exercise that owns nothing past its own statement is not a
|
||||
// published owner.
|
||||
if (gl is null)
|
||||
{
|
||||
_factory.ExerciseBackendNeutralWorldTextures(
|
||||
_dependencies.GpuDevice,
|
||||
_dependencies.Log);
|
||||
}
|
||||
// The rest of the world texture stack's creation path: one shared
|
||||
// array of each format family and one composite array, created and
|
||||
// released here. Nothing draws them; see the type's own
|
||||
// documentation for why they are built anyway. It claims no
|
||||
// composition point and enters no acquisition scope — the frozen
|
||||
// publication order is a pinned assertion, and an exercise that
|
||||
// owns nothing past its own statement is not a published owner.
|
||||
_factory.ExerciseBackendNeutralWorldTextures(
|
||||
_dependencies.GpuDevice,
|
||||
_dependencies.Log);
|
||||
|
||||
string shadersDirectory = Path.Combine(
|
||||
AppContext.BaseDirectory,
|
||||
"Rendering",
|
||||
"Shaders");
|
||||
Shader? terrainShader = AcquireAndPublishIf(
|
||||
gl is not null,
|
||||
scope,
|
||||
"terrain shader",
|
||||
() => _factory.CreateTerrainShader(gl!, shadersDirectory),
|
||||
_publication.PublishTerrainShader,
|
||||
WorldRenderCompositionPoint.TerrainShaderPublished);
|
||||
// Campaign V slice V6j: scene lighting exists on BOTH arms — the
|
||||
// world renderers read it on both, and on the RHI arm it publishes a
|
||||
// ring section instead of holding a global binding point.
|
||||
IWorldPassScope? worldPassScope = platform.Graphics.WorldPassScope;
|
||||
SceneLightingUboBinding? sceneLighting = AcquireAndPublish(
|
||||
// Campaign V slice V6j: scene lighting publishes a ring section on
|
||||
// the world pass scope; the raw-GL global-uniform-binding arm was
|
||||
// deleted at slice V11.
|
||||
IWorldPassScope worldPassScope = platform.Graphics.WorldPassScope
|
||||
?? throw new InvalidOperationException(
|
||||
"The graphics backend must publish a world pass scope.");
|
||||
SceneLightingUboBinding sceneLighting = AcquireAndPublish(
|
||||
scope,
|
||||
"scene lighting",
|
||||
() => gl is not null
|
||||
? _factory.CreateSceneLighting(gl)
|
||||
: _factory.CreateBackendNeutralSceneLighting(
|
||||
_dependencies.GpuFrameSource,
|
||||
worldPassScope
|
||||
?? throw new InvalidOperationException(
|
||||
"A backend without a GL context must publish a world pass scope.")),
|
||||
() => _factory.CreateBackendNeutralSceneLighting(
|
||||
_dependencies.GpuFrameSource,
|
||||
worldPassScope),
|
||||
_publication.PublishSceneLighting,
|
||||
WorldRenderCompositionPoint.SceneLightingPublished);
|
||||
DebugLineRenderer debugLines = AcquireAndPublish(
|
||||
|
|
@ -671,28 +513,18 @@ internal sealed class WorldRenderCompositionPhase
|
|||
(BitmapFont? debugFont, TextRenderer? textRenderer) =
|
||||
ComposeOptionalHudResources(scope, shadersDirectory);
|
||||
|
||||
// Campaign V slice V6j: terrain exists on BOTH arms. The GL arm is
|
||||
// unchanged; the RHI arm records into the world pass and reads the
|
||||
// same backend-neutral atlas built above.
|
||||
TerrainModernRenderer? terrain = AcquireAndPublish(
|
||||
// Campaign V slice V6j: terrain records into the world pass and
|
||||
// reads the same backend-neutral atlas built above. The raw-GL arm
|
||||
// was deleted at slice V11.
|
||||
TerrainModernRenderer terrain = AcquireAndPublish(
|
||||
scope,
|
||||
"terrain renderer",
|
||||
() => gl is not null
|
||||
? _factory.CreateTerrain(
|
||||
gl,
|
||||
bindless!,
|
||||
terrainShader!,
|
||||
terrainAtlas!,
|
||||
_dependencies.GpuDevice,
|
||||
_dependencies.ResourceRetirement)
|
||||
: _factory.CreateBackendNeutralTerrain(
|
||||
_dependencies.GpuDevice,
|
||||
_dependencies.GpuFrameSource,
|
||||
worldPassScope
|
||||
?? throw new InvalidOperationException(
|
||||
"A backend without a GL context must publish a world pass scope."),
|
||||
terrainAtlas!,
|
||||
_dependencies.ResourceRetirement),
|
||||
() => _factory.CreateBackendNeutralTerrain(
|
||||
_dependencies.GpuDevice,
|
||||
_dependencies.GpuFrameSource,
|
||||
worldPassScope,
|
||||
terrainAtlas,
|
||||
_dependencies.ResourceRetirement),
|
||||
_publication.PublishTerrain,
|
||||
WorldRenderCompositionPoint.TerrainPublished);
|
||||
|
||||
|
|
@ -707,25 +539,17 @@ internal sealed class WorldRenderCompositionPhase
|
|||
terrainBuild.SurfaceCache);
|
||||
Fault(WorldRenderCompositionPoint.TerrainBuildStatePublished);
|
||||
|
||||
Shader? meshShader = AcquireAndPublishIf(
|
||||
gl is not null,
|
||||
scope,
|
||||
"mesh shader",
|
||||
() => _factory.CreateMeshShader(gl!, shadersDirectory),
|
||||
_publication.PublishMeshShader,
|
||||
WorldRenderCompositionPoint.MeshShaderPublished);
|
||||
if (meshShader is not null)
|
||||
_dependencies.Log("[N.5] mesh_modern shader loaded");
|
||||
// Campaign V slice V6i-3: the mesh pipeline exists on BOTH arms. Its
|
||||
// upload bodies reached IGpuBuffer, so a backend with no GL context
|
||||
// builds the same arena, the same atlases and the same render data —
|
||||
// which is what makes streaming's publication into GPU state real
|
||||
// there rather than a no-op.
|
||||
// Campaign V slice V6i-3: the mesh pipeline builds the same arena,
|
||||
// atlases and render data on every remaining backend, which is what
|
||||
// makes streaming's publication into GPU state real rather than a
|
||||
// no-op. gl is always null here — the raw-GL arm was deleted at
|
||||
// slice V11, and the constructor's GL? gl parameter is Commit 3's
|
||||
// (IMeshPipelineDevice.Gl) to remove.
|
||||
WbMeshAdapter meshAdapter = AcquireAndPublish(
|
||||
scope,
|
||||
"WB mesh adapter",
|
||||
() => _factory.CreateMeshAdapter(
|
||||
gl,
|
||||
gl: null,
|
||||
_dependencies.GpuDevice,
|
||||
content.Dats,
|
||||
content.PreparedAssets,
|
||||
|
|
@ -737,22 +561,13 @@ internal sealed class WorldRenderCompositionPhase
|
|||
scope,
|
||||
"texture cache",
|
||||
() => _factory.CreateTextureCache(
|
||||
gl,
|
||||
_dependencies.GpuDevice,
|
||||
content.Dats,
|
||||
bindless,
|
||||
_dependencies.ResourceRetirement,
|
||||
_dependencies.DiagnosticsDirectory,
|
||||
residency.Budgets),
|
||||
_publication.PublishTextureCache,
|
||||
WorldRenderCompositionPoint.TextureCachePublished);
|
||||
SamplerCache? samplers = AcquireAndPublishIf(
|
||||
gl is not null,
|
||||
scope,
|
||||
"sampler cache",
|
||||
() => _factory.CreateSamplerCache(gl!),
|
||||
_publication.PublishSamplerCache,
|
||||
WorldRenderCompositionPoint.SamplerCachePublished);
|
||||
_factory.RegisterResidencySources(
|
||||
residency,
|
||||
meshAdapter,
|
||||
|
|
@ -769,18 +584,14 @@ internal sealed class WorldRenderCompositionPhase
|
|||
terrainBuild,
|
||||
new WorldRenderFoundation(
|
||||
shadersDirectory,
|
||||
bindless,
|
||||
terrainAtlas,
|
||||
terrainShader,
|
||||
sceneLighting,
|
||||
debugLines,
|
||||
debugFont,
|
||||
textRenderer,
|
||||
terrain,
|
||||
meshShader,
|
||||
meshAdapter,
|
||||
textureCache,
|
||||
samplers,
|
||||
residency));
|
||||
}
|
||||
catch (Exception failure)
|
||||
|
|
@ -843,27 +654,6 @@ internal sealed class WorldRenderCompositionPhase
|
|||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign V slice V6h: acquires an owner the active backend may not have.
|
||||
/// The fault point still fires on both arms so a failure-injection test
|
||||
/// covers the same ordered sequence whichever backend composed it.
|
||||
/// </summary>
|
||||
private T? AcquireAndPublishIf<T>(
|
||||
bool supported,
|
||||
CompositionAcquisitionScope scope,
|
||||
string name,
|
||||
Func<T> factory,
|
||||
Action<T> publish,
|
||||
WorldRenderCompositionPoint point)
|
||||
where T : class, IDisposable
|
||||
{
|
||||
T? value = supported
|
||||
? scope.Acquire(name, factory, _factory.Release).Publish(publish)
|
||||
: null;
|
||||
Fault(point);
|
||||
return value;
|
||||
}
|
||||
|
||||
private void Fault(WorldRenderCompositionPoint point) =>
|
||||
_faultInjection?.Invoke(point);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue