acdream/src/AcDream.App/Rendering/Gpu/GpuPassDescription.cs
Erik 90f7c6f2f4 docs(render): drop the ambient-encoder relaxation from Campaign V
The transitional path for slices V4a-V4g needs no special API after all.
On GL, BeginPass binds the target framebuffer and applies load ops but
deliberately leaves viewport and scissor to the encoder, so a renderer
being ported mid-campaign opens a Load/Store pass against the backbuffer
and gets exactly today's behavior while the frame spine still owns clears.
One less contract concept, and one less thing for V4h to unwind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 14:28:06 +02:00

85 lines
3.8 KiB
C#

using System.Numerics;
namespace AcDream.App.Rendering.Gpu;
/// <summary>
/// The colour attachment for a pass.
/// </summary>
/// <param name="Target">
/// The offscreen target to render into, or null for the backbuffer. On GL null
/// means framebuffer 0; on Vulkan it means the acquired swapchain image (or the
/// multisampled scratch image that resolves into it when
/// <paramref name="Store"/> is <see cref="GpuStoreOp.Resolve"/>).
/// </param>
/// <param name="Load">What happens to existing contents on entry.</param>
/// <param name="Store">What happens to contents on exit.</param>
/// <param name="ClearColor">Clear value used when <paramref name="Load"/> is <see cref="GpuLoadOp.Clear"/>.</param>
internal readonly record struct GpuColorAttachment(
IGpuRenderTarget? Target,
GpuLoadOp Load,
GpuStoreOp Store,
Vector4 ClearColor);
/// <summary>
/// The depth/stencil attachment for a pass. Depth is transient in every acdream
/// pass — nothing reads it after the frame — so <see cref="Store"/> is normally
/// <see cref="GpuStoreOp.DontCare"/>, which lets Vulkan skip writing it back to
/// memory entirely.
/// </summary>
/// <param name="Load">What happens to existing contents on entry.</param>
/// <param name="Store">What happens to contents on exit.</param>
/// <param name="ClearDepth">Depth clear value. acdream renders with NDC z in [0,1], so far = 1.</param>
/// <param name="ClearStencil">Stencil clear value; #117's portal punch uses the stencil aspect.</param>
internal readonly record struct GpuDepthAttachment(
GpuLoadOp Load,
GpuStoreOp Store,
float ClearDepth,
uint ClearStencil);
/// <summary>
/// One rendering pass: a set of attachments, their load/store behaviour, and the
/// sample count every pipeline used inside must match.
///
/// GL has no such object — its "pass" is implicit in whatever framebuffer happens
/// to be bound — so making passes explicit is the single largest structural change
/// the RHI imposes on the existing renderers.
///
/// The transitional path needs no special API. On GL, <c>BeginPass</c> binds the
/// target framebuffer and applies load ops, and deliberately does NOT touch
/// viewport or scissor — encoders set those explicitly. A renderer being ported
/// during Campaign V slices V4a..V4g therefore opens a pass with
/// <see cref="GpuLoadOp.Load"/> / <see cref="GpuStoreOp.Store"/> against the
/// backbuffer and gets exactly today's behaviour, while the frame spine still
/// owns clears and framebuffer management. Slice V4h converts the spine itself.
/// </summary>
internal sealed record GpuPassDescription
{
/// <summary>Stable identifier, surfaced as a debug label in captures.</summary>
public required string Name { get; init; }
/// <summary>The colour attachment. Required — acdream has no colour-less passes.</summary>
public required GpuColorAttachment Color { get; init; }
/// <summary>Depth/stencil attachment, or null for 2-D passes that need no depth.</summary>
public GpuDepthAttachment? Depth { get; init; }
/// <summary>Samples per pixel. Must equal <see cref="GpuPipelineDescription.SampleCount"/> of every pipeline bound inside.</summary>
public int SampleCount { get; init; } = 1;
/// <summary>Clears colour and depth to the standard frame-start values against the backbuffer.</summary>
public static GpuPassDescription BackbufferClear(string name, Vector4 clearColor, int sampleCount) => new()
{
Name = name,
Color = new GpuColorAttachment(
Target: null,
Load: GpuLoadOp.Clear,
Store: sampleCount > 1 ? GpuStoreOp.Resolve : GpuStoreOp.Store,
ClearColor: clearColor),
Depth = new GpuDepthAttachment(
Load: GpuLoadOp.Clear,
Store: GpuStoreOp.DontCare,
ClearDepth: 1f,
ClearStencil: 0),
SampleCount = sampleCount,
};
}