namespace AcDream.App.Rendering.Gpu;
///
/// Creation parameters for a GPU buffer. is not
/// cosmetic: the Vulkan backend publishes it through VK_EXT_debug_utils
/// so RenderDoc captures and validation-layer messages name our objects.
///
/// Stable identifier, e.g. "mesh-arena-vertex".
/// Allocation size. Growth is a create-copy-retire cycle, never a resize.
/// Every way the buffer will be consumed.
/// Where the memory lives and whether the CPU may write it directly.
internal readonly record struct GpuBufferDescription(
string Name,
long SizeBytes,
GpuBufferUsage Usage,
GpuMemoryResidency Residency);
/// Creation parameters for a sampled texture or a render-target image.
/// Stable identifier for debug tooling.
/// 2D, or the 2D array every world material uses.
/// Pixel format; BC formats are uploaded as compressed blocks.
/// Width in texels of mip level 0.
/// Height in texels of mip level 0.
/// Array layers; 1 for .
///
/// Levels to allocate. 1 disables mipping. The backend never silently generates
/// mips: is an explicit call, because
/// Vulkan cannot blit-generate compressed mips and must take a CPU-built chain.
///
internal readonly record struct GpuTextureDescription(
string Name,
GpuTextureKind Kind,
GpuTextureFormat Format,
int Width,
int Height,
int LayerCount,
int MipLevelCount);
///
/// Sampler state. The set of distinct samplers acdream uses is tiny (wrap/clamp
/// × nearest/linear), which is what makes a combined image-sampler descriptor
/// table practical: a texture registered twice with different samplers simply
/// occupies two table slots, exactly as it holds two bindless handles today.
///
internal readonly record struct GpuSamplerDescription(
GpuFilter MinFilter,
GpuFilter MagFilter,
GpuMipFilter MipFilter,
GpuAddressMode AddressU,
GpuAddressMode AddressV,
float MaxAnisotropy)
{
/// Trilinear repeat — the default for world materials.
public static GpuSamplerDescription WorldRepeat { get; } = new(
GpuFilter.Linear,
GpuFilter.Linear,
GpuMipFilter.Linear,
GpuAddressMode.Repeat,
GpuAddressMode.Repeat,
MaxAnisotropy: 1f);
/// Trilinear clamped — atlas pages and anything whose edges must not wrap.
public static GpuSamplerDescription WorldClamp { get; } = new(
GpuFilter.Linear,
GpuFilter.Linear,
GpuMipFilter.Linear,
GpuAddressMode.ClampToEdge,
GpuAddressMode.ClampToEdge,
MaxAnisotropy: 1f);
/// Unfiltered clamped — retail UI icons and the composited 32×32 item art.
public static GpuSamplerDescription UiNearest { get; } = new(
GpuFilter.Nearest,
GpuFilter.Nearest,
GpuMipFilter.None,
GpuAddressMode.ClampToEdge,
GpuAddressMode.ClampToEdge,
MaxAnisotropy: 1f);
}
/// An offscreen colour(+depth) bundle: paperdoll, creature appraisal, portal masking.
/// Stable identifier for debug tooling.
/// Colour attachment width in pixels.
/// Colour attachment height in pixels.
/// Colour attachment format.
/// Depth/stencil format, or null for a colour-only target.
/// 1 for single-sampled. Offscreen targets stay single-sampled.
internal readonly record struct GpuRenderTargetDescription(
string Name,
int Width,
int Height,
GpuTextureFormat ColorFormat,
GpuTextureFormat? DepthFormat,
int SampleCount);
///
/// A slot in the device's global texture table — the backend-neutral replacement
/// for a 64-bit ARB_bindless_texture handle. Renderers write
/// into batch data; the shader indexes the descriptor array
/// (Vulkan) or the uvec2 handle buffer (GL) with it.
///
/// is a loud sentinel, never a usable slot. It exists so
/// an unset index is an assertable programming error rather than a silent
/// resolve to slot 0 — the failure mode that produced the magenta 1×1 UI
/// placeholder bug. Renderers that genuinely need a fallback ask the device for
/// , which is a real registered texture.
///
internal readonly record struct GpuTextureSlot(uint Index)
{
/// Sentinel for "no texture assigned". Must never reach a shader.
public static GpuTextureSlot Unassigned { get; } = new(uint.MaxValue);
public bool IsAssigned => Index != uint.MaxValue;
public override string ToString() =>
IsAssigned ? $"slot#{Index}" : "slot#unassigned";
}