Skip to content

console: per-value platform gating for enum cvars + cross-cvar dependency warnings #161

Description

@havokentity

Context

Follow-up to PR #159 (cvar UX: CVAR_PLATFORM_MAC / CVAR_PLATFORM_WIN flag bits + 0-as-off enum alias). That PR added platform gating at the CVAR level. This issue adds two missing dimensions of UX hygiene to the same code area:

  1. Per-value platform gating inside enum cvars — the cvar itself is cross-platform but specific allowed-values aren't.
  2. Cross-cvar dependency warnings — when the user sets a cvar whose prerequisite condition isn't met, print a clear hint instead of silently no-op'ing.

Part 1: per-value platform gating

The cvar is cross-platform but its enum has platform-only values:

  • r_denoiser:
    • Mac: none, svgf_basic, svgf_atrous, metalfx, svgf_basic_metalfx, svgf_atrous_metalfx
    • Win/Linux: none, svgf_basic, svgf_atrous, nrd_relax, nrd_sigma, optix_hdr, optix_temporal_hdr, optix_hdr_aov, optix_temporal_hdr_aov
  • r_backend:
    • Mac: metal, vulkan, software
    • Win/Linux: vulkan, software (no metal)
  • r_software_blit:
    • Win: vulkan, gdi
    • Mac/Linux: vulkan (gdi is Win-only)

Implementation sketch

Per-value platform tag in the allowed-values metadata. Concretely: where r_denoiser declares its enum in src/engine/Engine.cpp, each value gets an optional CVAR_VALUE_MAC / CVAR_VALUE_WIN / CVAR_VALUE_LINUX flag. At cvar_list / cvar autocomplete time, the console filters out values whose tag doesn't match the current platform. At cvar set time, picking a disallowed value errors with:

[error] r_denoiser=nrd_relax is Windows/Linux-only; not available on macOS.
        Available on this platform: none, svgf_basic, svgf_atrous, metalfx, svgf_basic_metalfx, svgf_atrous_metalfx

Part 2: cross-cvar dependency warnings

When the user sets a cvar whose effect requires another cvar to be in a specific state, print a clear warning + actionable hint. Currently those settings just silently no-op or produce surprising behavior.

Examples from the codebase

Cvar Prerequisite Hint when unmet
r_sun_elevation, r_sun_azimuth, r_sky_day r_sky_mode procedural r_sky_mode=astronomical: solar position derives from datetime/lat/lon, not these cvars
r_clouds_coverage, r_clouds_curl_amount, etc. r_clouds 1 r_clouds=0: cloud march disabled
r_svgf_atrous_passes, r_svgf_albedo_demod r_denoiser starts with svgf_ r_denoiser=none: SVGF inactive
r_smoke_max_emitters r_smoke_enabled 1 r_smoke_enabled=0: smoke loop disabled
r_water_ior, r_water_absorption_* scene has a MAT_WATER primitive (warn at primitive-list time, harder to detect at cvar-set time)
r_restir_k_candidates, r_restir_temporal r_restir 1 AND denoiser active r_restir=0 or no denoiser: ReSTIR dispatch skipped
r_light_tree_* (future tuning cvars) r_light_tree 1 r_light_tree=0: naive uniform NEE pick
r_voxel_size r_voxelize_demo 1 (to actually see the effect) r_voxelize_demo=0: voxel grids hidden
r_metalfx_* (any future MetalFX cvars) r_denoiser is MetalFX-family r_denoiser=svgf_atrous: MetalFX specular guidance inactive
r_optix_* (any future OptiX cvars) r_denoiser is OptiX-family r_denoiser=none: OptiX denoiser inactive

Implementation sketch

Extend PT_CVAR macro with an optional dependency predicate, e.g.:

PT_CVAR(r_sun_elevation, "45", "...", CVAR_ARCHIVE,
        CVAR_REQUIRES("r_sky_mode", "procedural"));

Or more generally a lambda for compound conditions:

CVAR_REQUIRES_PREDICATE([](){
    auto* m = C.FindCVar("r_sky_mode");
    return m && m->value == "procedural";
}, "r_sky_mode=procedural")

At cvar set time, after the value is written, evaluate the predicate. If false, print warning. Don't BLOCK the set — the cvar still takes the new value (so a single cfg-load script can set the dependency cvar second and have the first one apply correctly). The warning is informational.

At cvar_list time, append [inactive: requires <dep>] to the description if predicate fails.

Acceptance criteria

  • r_denoiser nrd_relax on Mac errors with the platform-mismatch message + lists available values
  • cvar_list r_denoiser on Mac shows only Mac values; on Win shows only Win values
  • cvar set r_sun_elevation 30 when r_sky_mode=astronomical prints the warning hint
  • All existing cfg files (cornell_csg.cfg, etc.) still load cleanly without spurious warnings; predicates are only evaluated after explicit user cvar set, not during cfg replay (configurable via a flag — the cfg might set the dep cvar after the dependent one)
  • r_denoiser=metalfx is still PARSED on Win for portability of demont.cfg (just warns + no-ops with the "this platform doesn't support that denoiser" reason); same pattern as PR feat(console): platform-filter cvar listing + accept "0" as off alias #159's flag-bit cvars

Scope estimate

~300-500 LoC across Console.cpp / Console.h + the PT_CVAR macro + the per-cvar dependency declarations in Engine.cpp. Doctest fixture in tests/cvar_ux_test.cpp extending PR #159's coverage with platform-value-gating cases + dep-warning cases.

Out of scope

  • Runtime predicate evaluation on EVERY cvar access — only at set time + list time.
  • Auto-correcting / cascading sets (e.g. "you set r_clouds_curl_amount, would you like to also enable r_clouds? [y/n]") — too prompt-heavy for a console UX. The warning + hint is enough.

Dependencies

Lands on top of PR #159 (already in integration). No conflicts expected — separate code areas inside the same files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions