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
|
|
@ -1,61 +1,39 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Rendering.Wb;
|
||||
using AcDream.Core.Lighting;
|
||||
using Silk.NET.OpenGL;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// GL wrapper that owns the SceneLighting UBO buffer, updates its
|
||||
/// contents each frame, and keeps it bound at binding=1 so every
|
||||
/// shader sampling <c>uLights[]</c> / <c>uFogColor</c> / etc reads
|
||||
/// consistent data without per-shader re-upload.
|
||||
/// Publishes the SceneLighting UBO each frame so every shader sampling
|
||||
/// <c>uLights[]</c> / <c>uFogColor</c> / etc reads consistent data without
|
||||
/// per-shader re-upload.
|
||||
///
|
||||
/// <para>
|
||||
/// Usage (r12 §13.2 + r13 §12.3):
|
||||
/// <list type="number">
|
||||
/// <item><description>Instantiate once at startup, after the GL context exists.</description></item>
|
||||
/// <item><description>Each frame, after <see cref="LightManager.Tick"/>, call <see cref="Upload"/> with a freshly-built <see cref="SceneLightingUbo"/>.</description></item>
|
||||
/// <item><description>Shader programs that declare <c>layout(std140, binding = 1) uniform SceneLighting { ... }</c> automatically pick up the data.</description></item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>The raw-GL arm this used to have alongside it — a global uniform
|
||||
/// binding point kept live by a per-flight-slot buffer pool — was deleted at
|
||||
/// Campaign V slice V11. Vulkan has no such global binding point: a
|
||||
/// descriptor set is bound per draw, so the upload is a frame ring slice
|
||||
/// PUBLISHED on <see cref="WorldFrameSections.SceneLighting"/>, and each world
|
||||
/// renderer binds it inside the pass after its own binds (plan §5.5.14 item
|
||||
/// 2). Every allocation within a frame is already distinct memory that lives
|
||||
/// until the frame retires, which is the property the deleted buffer pool
|
||||
/// existed to provide when the world, portal-space and paperdoll draws each
|
||||
/// upload different lighting.</para>
|
||||
/// </summary>
|
||||
public sealed unsafe class SceneLightingUboBinding : IDisposable
|
||||
{
|
||||
private readonly GL? _gl;
|
||||
private readonly ICurrentGpuFrameSource? _frames;
|
||||
private readonly WorldFrameSections? _sections;
|
||||
private uint _ubo;
|
||||
private readonly List<uint>[] _buffersByFrame = [[], [], []];
|
||||
private int _frameSlot;
|
||||
private int _bufferCursor;
|
||||
private readonly ICurrentGpuFrameSource _frames;
|
||||
private readonly WorldFrameSections _sections;
|
||||
private bool _frameStarted;
|
||||
private bool _disposed;
|
||||
|
||||
internal int DynamicBufferCount => _buffersByFrame.Sum(buffers => buffers.Count);
|
||||
|
||||
public SceneLightingUboBinding(GL gl)
|
||||
{
|
||||
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign V slice V6j: the RHI arm.
|
||||
///
|
||||
/// <para>GL keeps the block bound at a global uniform binding point and every
|
||||
/// shader inherits it. Vulkan has no such point — a descriptor set is bound
|
||||
/// per draw and the renderer's own binds select the scope this block has to
|
||||
/// land in — so the upload becomes a frame ring slice PUBLISHED on
|
||||
/// <see cref="WorldFrameSections.SceneLighting"/>, and each world renderer
|
||||
/// binds it inside the pass after its own binds (plan §5.5.14 item 2).</para>
|
||||
///
|
||||
/// <para>The per-flight-slot buffer pool disappears with it: every allocation
|
||||
/// within a frame is already distinct memory that lives until the frame
|
||||
/// retires, which is the property the pool existed to provide when the world,
|
||||
/// portal-space and paperdoll draws each upload different lighting.</para>
|
||||
/// The GL arm's per-flight-slot buffer pool this used to report on was
|
||||
/// deleted at Campaign V slice V11: every allocation now comes from a ring
|
||||
/// that lives until its frame retires, so there is no persistent
|
||||
/// dynamic-buffer pool left to size.
|
||||
/// </summary>
|
||||
internal int DynamicBufferCount => 0;
|
||||
|
||||
internal SceneLightingUboBinding(
|
||||
ICurrentGpuFrameSource frames,
|
||||
WorldFrameSections sections)
|
||||
|
|
@ -71,80 +49,20 @@ public sealed unsafe class SceneLightingUboBinding : IDisposable
|
|||
/// </summary>
|
||||
public void BeginFrame(int frameSlot)
|
||||
{
|
||||
if ((uint)frameSlot >= (uint)_buffersByFrame.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(frameSlot));
|
||||
|
||||
_frameSlot = frameSlot;
|
||||
_bufferCursor = 0;
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(frameSlot);
|
||||
_frameStarted = true;
|
||||
}
|
||||
|
||||
private void ActivateNextBuffer()
|
||||
{
|
||||
if (!_frameStarted)
|
||||
throw new InvalidOperationException("BeginFrame must be called before uploading scene lighting.");
|
||||
if (_gl is null)
|
||||
throw new InvalidOperationException("The RHI arm publishes a ring section rather than a buffer.");
|
||||
|
||||
List<uint> buffers = _buffersByFrame[_frameSlot];
|
||||
if (_bufferCursor == buffers.Count)
|
||||
{
|
||||
uint buffer = TrackedGlResource.CreateBuffer(
|
||||
_gl,
|
||||
"SceneLighting frame UBO creation");
|
||||
try
|
||||
{
|
||||
TrackedGlResource.AllocateBufferStorage(
|
||||
_gl,
|
||||
GLEnum.UniformBuffer,
|
||||
buffer,
|
||||
0,
|
||||
SceneLightingUbo.SizeInBytes,
|
||||
GLEnum.DynamicDraw,
|
||||
"SceneLighting frame UBO allocation");
|
||||
buffers.Add(buffer);
|
||||
}
|
||||
catch
|
||||
{
|
||||
TrackedGlResource.DeleteBuffer(
|
||||
_gl,
|
||||
buffer,
|
||||
0,
|
||||
"SceneLighting frame UBO rollback");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
_ubo = buffers[_bufferCursor++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Push the current frame's UBO contents to the GPU. Cheap (576 bytes)
|
||||
/// so fine to call unconditionally every frame.
|
||||
/// </summary>
|
||||
public void Upload(SceneLightingUbo data)
|
||||
{
|
||||
if (_gl is null)
|
||||
{
|
||||
PublishSection(data);
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateNextBuffer();
|
||||
_gl.BindBuffer(BufferTargetARB.UniformBuffer, _ubo);
|
||||
_gl.BufferSubData(BufferTargetARB.UniformBuffer,
|
||||
(nint)0, (nuint)SceneLightingUbo.SizeInBytes, &data);
|
||||
_gl.BindBufferBase(BufferTargetARB.UniformBuffer,
|
||||
SceneLightingUbo.BindingPoint, _ubo);
|
||||
_gl.BindBuffer(BufferTargetARB.UniformBuffer, 0);
|
||||
}
|
||||
|
||||
private void PublishSection(SceneLightingUbo data)
|
||||
{
|
||||
if (!_frameStarted)
|
||||
throw new InvalidOperationException("BeginFrame must be called before uploading scene lighting.");
|
||||
|
||||
IGpuFrame frame = _frames!.CurrentFrame
|
||||
IGpuFrame frame = _frames.CurrentFrame
|
||||
?? throw new InvalidOperationException(
|
||||
"Scene lighting requires an open IGpuFrame (see GpuDeviceFrameLifetime).");
|
||||
GpuRingAllocation allocation = frame.AllocateRing(
|
||||
|
|
@ -152,30 +70,19 @@ public sealed unsafe class SceneLightingUboBinding : IDisposable
|
|||
GpuRingUsage.Uniform);
|
||||
new ReadOnlySpan<byte>(&data, SceneLightingUbo.SizeInBytes)
|
||||
.CopyTo(allocation.Data);
|
||||
_sections!.SceneLighting = new GpuBufferSection(
|
||||
_sections.SceneLighting = new GpuBufferSection(
|
||||
allocation.Buffer,
|
||||
allocation.OffsetBytes,
|
||||
(uint)SceneLightingUbo.SizeInBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No-op: this binding owns no GPU resource of its own on the RHI arm — the
|
||||
/// deleted GL arm's per-flight buffer pool was the only thing to release.
|
||||
/// Kept as a method so callers that hold this behind an <see cref="IDisposable"/>
|
||||
/// reference (composition's acquisition scope) don't need a special case.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
if (_gl is not null)
|
||||
{
|
||||
foreach (List<uint> buffers in _buffersByFrame)
|
||||
{
|
||||
foreach (uint buffer in buffers)
|
||||
{
|
||||
TrackedGlResource.DeleteBuffer(
|
||||
_gl,
|
||||
buffer,
|
||||
SceneLightingUbo.SizeInBytes,
|
||||
"SceneLighting frame UBO disposal");
|
||||
}
|
||||
buffers.Clear();
|
||||
}
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue