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,6 +1,6 @@
|
|||
using AcDream.App.Rendering.Gpu;
|
||||
using AcDream.App.Rendering.Gpu.Gl;
|
||||
using AcDream.App.Rendering.Gpu.Vk;
|
||||
using AcDream.Core.Rendering.Wb;
|
||||
using Chorizite.Core.Render.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Silk.NET.OpenGL;
|
||||
|
|
@ -15,21 +15,21 @@ namespace AcDream.App.Rendering.Wb;
|
|||
/// deliberately left CREATION with the caches — plan §5.5.11 records why, and
|
||||
/// §5.5.12 item 1 hands the remainder forward: "the missing piece is an
|
||||
/// <c>ITextureArray</c> implementation over <see cref="IGpuTexture"/>, not a
|
||||
/// codec." This is that interface. <see cref="ManagedGLTextureArray"/> and
|
||||
/// <see cref="RhiWorldTextureArray"/> implement it, and which one exists is
|
||||
/// decided once at composition by <see cref="IWorldTextureArrayFactory"/> —
|
||||
/// never per call, so the GL path executes exactly the statements it executed
|
||||
/// before.</para>
|
||||
/// codec." This is that interface. <c>ManagedGLTextureArray</c> used to be its
|
||||
/// GL implementation, alongside <see cref="RhiWorldTextureArray"/>; which one
|
||||
/// existed was decided once at composition by
|
||||
/// <see cref="IWorldTextureArrayFactory"/>, never per call. Campaign V slice
|
||||
/// V11 deleted <c>ManagedGLTextureArray</c> along with the rest of the raw-GL
|
||||
/// arm, so <see cref="RhiWorldTextureArray"/> is now the sole implementation.</para>
|
||||
///
|
||||
/// <para><b>The slot, not the handle, is the seam.</b> Before this slice
|
||||
/// <para><b>The slot, not the handle, is the seam.</b> Before V6i-2
|
||||
/// <c>ObjectMeshManager</c> read <c>BindlessWrapHandle</c>/
|
||||
/// <c>BindlessClampHandle</c> off the concrete GL array and interned them into
|
||||
/// the device table itself. A 64-bit <c>ARB_bindless_texture</c> handle is
|
||||
/// unspellable on Vulkan, so the array now answers the question the caller was
|
||||
/// really asking — <see cref="ResolveSlot"/> — and each implementation gets
|
||||
/// there its own way: the GL array interns its resident handle (the same
|
||||
/// idempotent call, one level down), while the RHI array registered its two
|
||||
/// (texture, sampler) pairs at construction and returns a field.</para>
|
||||
/// unspellable on Vulkan, so the array answers the question the caller was
|
||||
/// really asking — <see cref="ResolveSlot"/> — instead: the RHI array
|
||||
/// registered its two (texture, sampler) pairs at construction and returns a
|
||||
/// field.</para>
|
||||
/// </summary>
|
||||
internal interface IWorldTextureArray : IDisposable
|
||||
{
|
||||
|
|
@ -116,9 +116,9 @@ internal interface IWorldTextureArrayFactory
|
|||
ArgumentNullException.ThrowIfNull(graphicsDevice);
|
||||
ArgumentNullException.ThrowIfNull(gpuDevice);
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
return graphicsDevice is OpenGLGraphicsDevice gl && gpuDevice is GlGpuDevice table
|
||||
? new GlWorldTextureArrayFactory(gl, table, logger)
|
||||
: new RhiWorldTextureArrayFactory(gpuDevice);
|
||||
// The GL arm this used to select between was deleted at Campaign V
|
||||
// slice V11; the RHI arm is the only one left.
|
||||
return new RhiWorldTextureArrayFactory(gpuDevice);
|
||||
}
|
||||
|
||||
/// <summary>The retirement queue array layers and images are released through.</summary>
|
||||
|
|
@ -132,36 +132,6 @@ internal interface IWorldTextureArrayFactory
|
|||
IWorldTextureArray CreateClampedArray(TextureFormat format, int width, int height, int layers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GL arm. Delegates to the same <c>OpenGLGraphicsDevice</c> entry point
|
||||
/// <see cref="TextureAtlasManager"/> called directly before this slice, so the
|
||||
/// shipping backend's construction is textually unchanged.
|
||||
/// </summary>
|
||||
internal sealed class GlWorldTextureArrayFactory(
|
||||
OpenGLGraphicsDevice graphicsDevice,
|
||||
GlGpuDevice worldTextureTable,
|
||||
ILogger logger) : IWorldTextureArrayFactory
|
||||
{
|
||||
private readonly OpenGLGraphicsDevice _graphicsDevice = graphicsDevice
|
||||
?? throw new ArgumentNullException(nameof(graphicsDevice));
|
||||
private readonly GlGpuDevice _worldTextureTable = worldTextureTable
|
||||
?? throw new ArgumentNullException(nameof(worldTextureTable));
|
||||
private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
|
||||
public IGpuResourceRetirementQueue Retirement => _graphicsDevice.ResourceRetirement;
|
||||
|
||||
public IWorldTextureArray CreateClampedArray(TextureFormat format, int width, int height, int layers) =>
|
||||
new ManagedGLTextureArray(
|
||||
_graphicsDevice,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
layers,
|
||||
_logger,
|
||||
_worldTextureTable,
|
||||
TextureParameters.ClampToEdge);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The backend-neutral arm. Creates through <see cref="IGpuDevice.CreateTexture"/>
|
||||
/// and registers both address modes into the device's one texture table, so an
|
||||
|
|
@ -353,11 +323,7 @@ internal sealed class RhiWorldTextureArray : IWorldTextureArray
|
|||
ArgumentNullException.ThrowIfNull(data);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(layer);
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(layer, Size);
|
||||
// The GL array validates the payload against the format's expected byte
|
||||
// count and rejects transfer overrides that contradict it. Reusing that
|
||||
// validator rather than writing a second one keeps the two arms agreeing
|
||||
// on what a well-formed layer is.
|
||||
ManagedGLTextureArray.ValidateUploadPayload(
|
||||
ValidateUploadPayload(
|
||||
SourceFormat,
|
||||
_width,
|
||||
_height,
|
||||
|
|
@ -504,4 +470,65 @@ internal sealed class RhiWorldTextureArray : IWorldTextureArray
|
|||
+ "and is not part of GpuTextureDescription. Campaign V's world-draw slice owns "
|
||||
+ "extending the contract or proving no such atlas exists."),
|
||||
};
|
||||
|
||||
private static bool IsCompressedFormat(TextureFormat format) =>
|
||||
format is TextureFormat.DXT1 or TextureFormat.DXT3 or TextureFormat.DXT5;
|
||||
|
||||
/// <summary>
|
||||
/// The expected byte count for one uploaded layer of <paramref name="format"/>
|
||||
/// at <paramref name="width"/>x<paramref name="height"/>.
|
||||
/// </summary>
|
||||
internal static int CalculateExpectedDataSize(TextureFormat format, int width, int height)
|
||||
{
|
||||
if (IsCompressedFormat(format))
|
||||
return TextureHelpers.GetCompressedLayerSize(width, height, format);
|
||||
|
||||
return format switch
|
||||
{
|
||||
TextureFormat.RGBA8 => checked(width * height * 4),
|
||||
TextureFormat.RGB8 => checked(width * height * 3),
|
||||
TextureFormat.A8 => checked(width * height),
|
||||
TextureFormat.Rgba32f => checked(width * height * 16),
|
||||
_ => throw new NotSupportedException($"Unsupported format {format}"),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates an upload payload against the format's expected byte count and
|
||||
/// rejects transfer overrides that contradict it.
|
||||
/// </summary>
|
||||
internal static void ValidateUploadPayload(
|
||||
TextureFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int dataLength,
|
||||
PixelFormat? uploadPixelFormat,
|
||||
PixelType? uploadPixelType)
|
||||
{
|
||||
int expectedBytes = CalculateExpectedDataSize(format, width, height);
|
||||
if (dataLength != expectedBytes)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Texture-array layer payload has {dataLength} bytes; expected exactly {expectedBytes} "
|
||||
+ $"for {format} {width}x{height}.",
|
||||
nameof(dataLength));
|
||||
}
|
||||
|
||||
if (IsCompressedFormat(format))
|
||||
{
|
||||
if (uploadPixelFormat.HasValue || uploadPixelType.HasValue)
|
||||
throw new ArgumentException("Compressed texture uploads cannot specify pixel format/type overrides.");
|
||||
return;
|
||||
}
|
||||
|
||||
PixelFormat expectedFormat = format.ToPixelFormat();
|
||||
PixelType expectedType = format.ToPixelType();
|
||||
if ((uploadPixelFormat ?? expectedFormat) != expectedFormat
|
||||
|| (uploadPixelType ?? expectedType) != expectedType)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Upload descriptor {uploadPixelFormat}/{uploadPixelType} does not match "
|
||||
+ $"the {expectedFormat}/{expectedType} transfer required by {format}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue