namespace AcDream.App.Rendering.Packs; /// /// The one rule for a pack preset's effective resident-GPU ceiling. /// /// /// /// A preset's MaxResidentGpuBytes is the 1080p figure of the /// Campaign AR budget table (Low 64 / Medium 128 / High 256 MiB). The pack's /// resident set is dominated by screen-sized images — the HDR world colour + /// depth targets alone are 12 bytes per pixel, plus the ray/bloom /// intermediates — so a ceiling that does not scale with pixel count refuses /// the pack the moment the user picks a larger mode: at 2560×1440 the Low /// preset's screen targets are 44 MB of a 64 MiB budget, and live Holtburg's /// scene-dependent shadow command buffers pushed the total to 64.25 MiB. /// That refusal is what the owner hit at the Campaign VM VM7 gate /// (2026-08-23, #425): Apply → "needs 67368164 resident GPU bytes; the /// active pack budget is 67108864" → persisted back to the default path. /// /// /// The effective ceiling is therefore the declared 1080p figure scaled by /// the pixel-count ratio (never below 1, so smaller modes keep the declared /// ceiling), and still capped by the hardware's MaxPackResidentBytes. /// The parts of the resident set that do NOT scale with the screen (shadow /// depth maps, shadow command/transform buffers) are over-allowed by the same /// factor; that errs on the side of honouring the user's explicit resolution /// choice while keeping the bound proportional to what they asked the GPU to /// draw. tools/run-atmospheric-performance-matrix.ps1 judges its /// resident column with this same rule so the tool and the runtime cannot /// disagree. /// /// internal static class RenderPackResidentBudget { internal const long ReferencePixels = 1920L * 1080L; internal static long Effective( long declaredBytesAt1080p, int viewportWidth, int viewportHeight, long hardwareCapBytes) { ArgumentOutOfRangeException.ThrowIfNegative(declaredBytesAt1080p); ArgumentOutOfRangeException.ThrowIfNegativeOrZero(viewportWidth); ArgumentOutOfRangeException.ThrowIfNegativeOrZero(viewportHeight); ArgumentOutOfRangeException.ThrowIfNegative(hardwareCapBytes); long pixels = checked((long)viewportWidth * viewportHeight); long scaled = pixels <= ReferencePixels ? declaredBytesAt1080p : checked((long)Math.Ceiling( (double)declaredBytesAt1080p * pixels / ReferencePixels)); return Math.Min(scaled, hardwareCapBytes); } }