Skip to content

refactor(utils): add stereo support to Util::Subrect::Controller#23

Merged
alandtse merged 8 commits into
devfrom
pr1-stereo-subrect
May 22, 2026
Merged

refactor(utils): add stereo support to Util::Subrect::Controller#23
alandtse merged 8 commits into
devfrom
pr1-stereo-subrect

Conversation

@alandtse
Copy link
Copy Markdown
Owner

@alandtse alandtse commented May 19, 2026

Summary

Opt-in stereo extension to the screenshot subrect controller so future stereo-aware consumers (the DLSS Enhancer foveated subrect framework decomposed from community-shaders#2096 upstream) can track a mirrored right-eye UV without forking the util that ScreenshotFeature already ships.

Mono callers (ScreenshotFeature) are unaffected: SaveSettings emits bit-identical JSON, LoadSettings round-trips the legacy schema, and the DrawEditor signature is unchanged.

What changes

New API on Util::Subrect::Controller:

  • SetStereoEnabled(bool) / IsStereoEnabled() — opt-in toggle (default off)
  • GetRightEyeUV() — folds onto the primary UV in mono mode so callers can stay agnostic of stereo state
  • GetStereoPixelRegions(fullW, fullH) — resolves both eyes against per-eye half-width for SBS textures
  • Preset gains an optional rightUV{} field (default-init when designated initializers omit it)

Behavior:

  • In stereo mode, drag/slider edits in DrawEditor auto-mirror the primary UV to the right eye around x=0.5 (HMD nose-side overlap symmetry)
  • SaveSettings only emits the new CropRight* and preset right_uv keys when stereo is enabled — preserves existing on-disk shape
  • LoadSettings mirrors left → right only for the legacy upgrade case (CropX/Y/W/H present, no CropRight*), so a seeded preset's explicit right-eye UV survives a fresh load
  • Save Preset captures currentRightUV (fixed during the upstream review cycle — CodeRabbit Major)

The header is now self-contained (forward-declares D3D11 types, includes nlohmann/json directly, declares its own using json = nlohmann::json;). This lets a unit-test target compile it without the plugin PCH.

Tests

Adds a new tests/cpp/ target with a Catch2 unit test executable (cpp_tests). Reuses Catch2 via FetchContent dedup with tests/shaders. New CMake target run_cpp_tests.

10 test cases, 35 assertions, covering:

  • Mono back-compat: LoadSettings round-trips legacy JSON unchanged; SaveSettings emits no right-eye keys
  • Stereo round-trip: explicit asymmetric right-eye preserved through save/load
  • Stereo Save Preset captures rightUV (regression test for the upstream CodeRabbit Major)
  • Legacy upgrade: stereo mode mirrors CropX/Y/W/H to right eye when no CropRight* keys present
  • GetStereoPixelRegions SBS half-width split + mono-mode fallback (identical eyes)
  • MirrorUVHorizontal math via SetStereoEnabled

Tests caught a real bug in my initial LoadSettings logic — an unconditional post-load SyncRightUV was stomping on a preset's explicit right-eye value when JSON had no top-level Crop* keys. Now correctly gated on hasExplicitLeft && !hasExplicitRight.

Why this PR exists

Decomposed from @YtzyFvra's upstream community-shaders#2096 — the original PR forked this util into its own Subrect:: namespace, which conflicted with community-shaders#2092's later landing of Util::Subrect::Controller for screenshot. This PR establishes the shared API so the DLSS Enhancer subrect work (PR-3 of the decomposition) can consume it cleanly without a second fork.

See DLSS-PR-PLAN.md for the full decomposition strategy. PR-2 (DLSSperf) is also open on this repo; PR-3 + PR-3b (DlssEnhancer foveated subrect) are on the fork awaiting VR validation.

Test plan

  • Unit tests pass (35 assertions / 10 cases, including Save Preset regression)
  • Mono-mode behavior verified by reading every ScreenshotFeature call site against the new code paths — identical observable behavior
  • Manual smoke test: launch SkyrimVR, take a cropped screenshot via each preset (Left Eye / Right Eye / Full Frame), reload, verify crop persisted

Credits

Decomposed from @YtzyFvra's community-shaders#2096 (PR-1 of 4). Stereo API design is theirs; this PR adapts it to extend dev's existing Util::Subrect rather than fork it. Co-authored on commit.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Stereo-aware cropping: independent left/right-eye UVs, preset storage, UI sync, backward-compatible load/save, and per-eye pixel-region computation.
  • Tests

    • Added comprehensive C++ unit tests validating mono/stereo behavior, migration/edge cases, pixel-region splitting, and regression scenarios; includes a custom test runner.
  • Chores

    • Build updated to optionally integrate and run the C++ test suite with conditional test targets and a compact reporter.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

Adds stereo (side-by-side) per-eye UV support to Subrect: header/API and internal state, load/save with backward compatibility, editor/runtime sync and clamping, per-eye pixel-region resolution, and comprehensive Catch2 tests plus optional CMake integration for running C++ tests.

Changes

Stereo UV Support

Layer / File(s) Summary
Stereo data model and API contract
src/Utils/Subrect.h, src/Utils/Subrect.cpp
Header defines StereoPixelRegions, extends Preset with optional rightUV, adds Controller API (SetStereoEnabled, IsStereoEnabled, GetStereoPixelRegions, GetRightEyeUV). Implementation adds includes, MirrorUVHorizontal, and internal state (currentRightUV, stereoEnabled, rightUVLoadedFromJson).
Settings persistence and legacy upgrade
src/Utils/Subrect.cpp
LoadSettings reads CropRight* and per-preset right_uv, marks explicit load to suppress auto-mirroring, and performs legacy mirroring only when appropriate. SaveSettings conditionally emits/removes CropRight* and per-preset right_uv based on stereo state.
Runtime syncing and interactive editing
src/Utils/Subrect.cpp
SetStereoEnabled mirrors left→right only when enabling and right-eye data was not explicitly loaded. Editor SavePreset, slider, and drag/clamp paths call SyncRightUV. ClampCurrentUV and ApplyPreset updated to maintain currentRightUV.
Stereo SBS pixel-region resolution
src/Utils/Subrect.cpp
GetStereoPixelRegions returns left/right PixelRegion using currentUV/currentRightUV, splits SBS textures appropriately, and guards degenerate dimensions. EnsureDefaultPreset initializes currentRightUV from seeded preset or mirror.
CMake and C++ test integration
CMakeLists.txt, tests/cpp/CMakeLists.txt, tests/cpp/test_main.cpp
Main CMakeLists.txt conditionally adds tests/cpp and re-enters BUILD_SHADER_TESTS afterwards. tests/cpp/CMakeLists.txt introduces BUILD_CPP_TESTS, fetches Catch2, builds cpp_tests, and registers CppUtilTests. test_main.cpp provides custom Catch2 session main.
Catch2 test suite
tests/cpp/test_subrect.cpp
Extensive tests covering mono defaults, legacy back-compat load/save, stereo enable/disable and idempotency, explicit right_uv round-trips, SBS pixel-region splitting, mirroring math, call-order regressions, partial/malformed JSON handling, and degenerate-edge cases.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Stereo crops are born with one good eye,
Mirrored and clamped as the other draws nigh,
Tests guard the sync and the JSON persist—
No right-eye data shall ever be missed!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main change: adding stereo support to Util::Subrect::Controller, which is the primary focus across all modified files in the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr1-stereo-subrect

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.21.0)

OpenGrep fatal error (exit code 2): [00.14][ERROR]: Error: exception Unix_error: No such file or directory stat src/Utils/Subrect.cpp
Raised by primitive operation at UTmp.replace_named_pipe_by_regular_file_if_needed in file "libs/commons/UTmp.ml", line 145, characters 8-27
Called from Scan_CLI.replace_target_roots_by_regular_files_where_needed.(fun) in file "src/osemgrep/cli_scan/Scan_CLI.ml", lines 1086-1087, characters 19-65
Called from List_.fast_map in file "libs/commons/List_.ml", line 81, characters 17-20
Called from Scan_C


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

No actionable suggestions for changed features.

@alandtse alandtse changed the title feat(utils): add stereo support to Util::Subrect::Controller refactor(utils): add stereo support to Util::Subrect::Controller May 19, 2026
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from 499ce35 to ff27e7a Compare May 19, 2026 03:31
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

✅ A pre-release build is available for this PR:
Download

@alandtse alandtse closed this May 20, 2026
@alandtse alandtse reopened this May 20, 2026
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from f5f4712 to 7eeec46 Compare May 20, 2026 08:37
Copilot AI review requested due to automatic review settings May 20, 2026 08:37
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from 7eeec46 to 348166e Compare May 20, 2026 08:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in stereo extension to Util::Subrect::Controller so future stereo-aware consumers can track a mirrored right-eye crop UV while preserving the existing mono JSON schema used by ScreenshotFeature. Also introduces a new Catch2-based C++ unit test target to validate serialization and stereo behaviors independently of the full plugin build.

Changes:

  • Extend Util::Subrect::Controller with stereo state, right-eye UV tracking/accessors, and SBS-aware pixel region resolution.
  • Update JSON load/save to conditionally persist right-eye crop keys/preset fields only when stereo is enabled, with a legacy upgrade path.
  • Add tests/cpp Catch2 unit test executable + CMake plumbing and a run_cpp_tests target.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Utils/Subrect.h Adds stereo-facing types/APIs (StereoPixelRegions, right-eye UV accessors, stereo enable toggle) and makes the header more standalone.
src/Utils/Subrect.cpp Implements stereo mirroring logic, conditional JSON persistence for right-eye fields, and SBS pixel-region helper.
tests/cpp/test_subrect.cpp Adds unit tests for mono back-compat and stereo save/load/mirroring behaviors.
tests/cpp/test_main.cpp Provides an explicit Catch2 main() for the new C++ test executable.
tests/cpp/CMakeLists.txt Adds a new Catch2-based cpp_tests target that compiles Subrect.cpp directly.
CMakeLists.txt Wires tests/cpp into the top-level build and adds a run_cpp_tests custom target.

Comment thread src/Utils/Subrect.cpp
Comment thread tests/cpp/test_subrect.cpp Outdated
Comment thread src/Utils/Subrect.h
alandtse added a commit that referenced this pull request May 21, 2026
…y regions

Three Copilot findings on PR #23:

- SetStereoEnabled(true) unconditionally called SyncRightUV(), so a
  caller that LoadSettings first (with stereo off) then enabled
  stereo would silently overwrite an explicit JSON CropRight* value
  with the mirror of the left eye. Track whether the right UV was
  loaded explicitly and skip the auto-mirror in that case. Add a
  regression test for the call order.
- The "Stereo preset save captures right-eye UV" test only validated
  that SaveSettings emits right_uv for existing presets — it didn't
  exercise the round-trip semantics it claimed to cover. Rewrite to
  stage an asymmetric right UV (one that doesn't equal MirrorUVHorizontal
  of left), save, reload into a fresh controller, and assert the
  right eye survived. That actually pins the regression.
- GetStereoPixelRegions returns regions in per-eye coordinate space
  (right eye x in [0, fullWidth/2), NOT pre-offset). Document this
  in the header so callers don't double-offset or place the right
  eye on top of the left.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
CMakeLists.txt (2)

1317-1332: ⚡ Quick win

Tighten PR metadata for traceability.

Consider shortening the PR title to stay within the 50-char conventional-commit guidance (e.g., feat(subrect): add stereo uv support) and add an issue keyword like Implements #<id> if this maps to a tracked issue.

As per coding guidelines, **/*: "When reviewing PRs, please provide suggestions for: 1. Conventional Commit Titles ... 2. Issue References ...".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CMakeLists.txt` around lines 1317 - 1332, Shorten the PR title to follow the
50-char conventional-commit guideline (e.g., "feat(subrect): add stereo uv
support") and add an issue reference like "Implements #<id>" in the PR
description or body for traceability; update the PR title and description fields
accordingly and include the issue keyword so reviewers can easily map this
change to the tracked issue (no code changes needed in CMakeLists.txt, just
update the pull request metadata).

1317-1332: ⚡ Quick win

Wire run_cpp_tests into release-critical targets.

run_cpp_tests is created, but unlike shader tests it does not gate package/deploy targets, so stereo regressions can slip through release flows.

Suggested wiring
 if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/cpp/CMakeLists.txt")
     enable_testing()
     add_subdirectory(tests/cpp)
     if(TARGET cpp_tests)
         add_custom_target(
             run_cpp_tests
             COMMAND $<TARGET_FILE:cpp_tests> --reporter compact
             DEPENDS cpp_tests
             WORKING_DIRECTORY $<TARGET_FILE_DIR:cpp_tests>
             COMMENT "Running C++ unit tests..."
             VERBATIM
         )
+        if(TARGET "Package-Core")
+            add_dependencies("Package-Core" run_cpp_tests)
+        endif()
+        if(TARGET "Package-AIO-Manual")
+            add_dependencies("Package-AIO-Manual" run_cpp_tests)
+        endif()
+        if(TARGET DEPLOY_ALL)
+            add_dependencies(DEPLOY_ALL run_cpp_tests)
+        endif()
     endif()
 endif()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CMakeLists.txt` around lines 1317 - 1332, The run_cpp_tests custom target is
not currently required by release packaging/deploy flows, so add it as a
dependency of the release-critical targets (the packaging and deploy targets
used in this project) to ensure cpp_tests must pass before those targets run;
locate the created custom target run_cpp_tests (and cpp_tests) in the CMakeLists
snippet and call add_dependencies(<release_target> run_cpp_tests) for each
relevant release target (e.g., package, deploy, or any targets analogous to
shader-test gating) so the packaging/deploy targets depend on run_cpp_tests and
will fail if the tests do.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Utils/Subrect.cpp`:
- Around line 150-155: SaveSettings() currently only writes CropRightX/Y/W/H
when stereoEnabled is true, leaving stale right-eye keys in the caller-owned
JSON a_json when stereo is later turned off; update SaveSettings() to explicitly
remove/erase the "CropRightX", "CropRightY", "CropRightW", and "CropRightH"
entries from a_json whenever stereoEnabled is false (use a_json.erase(...) or
clearing API provided by your JSON type) and keep references to stereoEnabled
and currentRightUV to locate the block to modify.
- Around line 336-344: Controller::GetStereoPixelRegions must guard against
zero/one fullWidth that makes eyeWidth = fullWidth/2 == 0; detect when eyeWidth
== 0 or fullHeight == 0 and early-return a safe/empty StereoPixelRegions instead
of calling UVToPixelRegion with invalid dimensions. Update
Controller::GetStereoPixelRegions to validate fullWidth and fullHeight (e.g.,
require fullWidth >= 2 and fullHeight >= 1), and when invalid, set
regions.leftEye/rightEye to a zero-sized or clamped region (or return a
default-constructed StereoPixelRegions) rather than invoking UVToPixelRegion
with currentUV/currentRightUV; keep the stereoEnabled logic but only call
UVToPixelRegion when dimensions are valid.
- Around line 85-100: The bug is that rightUVLoadedFromJson is only ever set
true and never reset, causing stale state across LoadSettings() calls; in
Subrect.cpp inside the settings load routine (where hasExplicitRight is computed
and currentRightUV is assigned) reset rightUVLoadedFromJson to false at the
start of each load (e.g., at the top of LoadSettings() or immediately before
reading CropRight*), then keep the existing logic that sets it to true when
hasExplicitRight is detected so left→right auto-mirroring works correctly when
CropRight* keys are absent.

In `@src/Utils/Subrect.h`:
- Around line 43-48: The Preset struct's rightUV currently default-initializes
to a full-frame UV (rightUV{}) which hides "not provided" and causes ApplyPreset
to use a full-frame right-eye crop; change Preset::rightUV to
std::optional<UVRegion> (or add a bool hasRightUV) so callers like
SeedDefaultPresets({ .name, .uv }) remain treated as "no right UV", then update
loading/seed/apply code paths (e.g., ApplyPreset, SeedDefaultPresets, and any
loaders) to use preset.rightUV.value_or(MirrorUVHorizontal(preset.uv)) (or the
equivalent hasRightUV check) when resolving the right-eye UV.

In `@tests/cpp/test_subrect.cpp`:
- Around line 24-27: The test uses std::abs in the function UVApprox (which
compares UVRegion members) but the file is missing an explicit `#include` <cmath>;
add an explicit include of <cmath> at the top of tests/cpp/test_subrect.cpp so
std::abs is defined (or use std::fabs if preferred) to avoid relying on
transitive includes and ensure correct overload resolution for floating-point
comparisons in UVApprox.

---

Nitpick comments:
In `@CMakeLists.txt`:
- Around line 1317-1332: Shorten the PR title to follow the 50-char
conventional-commit guideline (e.g., "feat(subrect): add stereo uv support") and
add an issue reference like "Implements #<id>" in the PR description or body for
traceability; update the PR title and description fields accordingly and include
the issue keyword so reviewers can easily map this change to the tracked issue
(no code changes needed in CMakeLists.txt, just update the pull request
metadata).
- Around line 1317-1332: The run_cpp_tests custom target is not currently
required by release packaging/deploy flows, so add it as a dependency of the
release-critical targets (the packaging and deploy targets used in this project)
to ensure cpp_tests must pass before those targets run; locate the created
custom target run_cpp_tests (and cpp_tests) in the CMakeLists snippet and call
add_dependencies(<release_target> run_cpp_tests) for each relevant release
target (e.g., package, deploy, or any targets analogous to shader-test gating)
so the packaging/deploy targets depend on run_cpp_tests and will fail if the
tests do.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d5015d26-fd02-4cd3-aa59-4aeb0fd5a1dc

📥 Commits

Reviewing files that changed from the base of the PR and between 20a38a1 and 170f368.

📒 Files selected for processing (6)
  • CMakeLists.txt
  • src/Utils/Subrect.cpp
  • src/Utils/Subrect.h
  • tests/cpp/CMakeLists.txt
  • tests/cpp/test_main.cpp
  • tests/cpp/test_subrect.cpp

Comment thread src/Utils/Subrect.cpp Outdated
Comment thread src/Utils/Subrect.cpp
Comment thread src/Utils/Subrect.cpp
Comment thread src/Utils/Subrect.h
Comment thread tests/cpp/test_subrect.cpp
alandtse added a commit that referenced this pull request May 21, 2026
Five CodeRabbit findings on PR #23:

- rightUVLoadedFromJson was only ever set to true. A later LoadSettings
  without CropRight* keys would inherit the stale `true` and SetStereoEnabled
  would no longer auto-mirror as intended. Set the flag to hasExplicitRight
  unconditionally so each load owns the state. Regression test added.
- SaveSettings updated a caller-owned JSON in place but skipped clearing
  CropRight* keys when stereo was disabled. If a host re-saved into the
  same object the keys lingered and the next load looked like explicit
  stereo data. Erase the four keys in the mono branch. Regression test
  added.
- GetStereoPixelRegions divided fullWidth by 2 unconditionally; for
  widths 0 or 1 the per-eye width was 0 and UVToPixelRegion's `width - 1`
  underflowed. Guard `fullWidth < 2 || fullHeight == 0` with an empty
  region pair so callers can detect via .w == 0. Edge test added.
- Preset::rightUV defaulted to UVRegion{} (full frame), which conflated
  "no explicit right eye supplied" with "user wants full frame". The
  SeedDefaultPresets caller in ScreenshotFeature only sets .name + .uv,
  so in a stereo-consumer host the right eye would silently land on
  full frame instead of mirroring left. Make rightUV a
  std::optional<UVRegion>: nullopt means "auto-mirror at apply time".
  ApplyPreset and EnsureDefaultPreset fall back to MirrorUVHorizontal
  when nullopt; SaveSettings only persists right_uv when both stereo
  is enabled and an explicit value exists. Existing in-fork callers
  (ScreenshotFeature, in-tree tests, Save Preset button via implicit
  T->optional<T>) work unchanged. Regression test added.
- test_subrect.cpp used std::abs via transitive includes. Add an
  explicit #include <cmath>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 21, 2026 06:40
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/Utils/Subrect.cpp Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
tests/cpp/test_subrect.cpp (2)

19-19: 💤 Low value

Unused import: WithinAbs matcher is never used.

The WithinAbs matcher is imported but the tests use the custom UVApprox helper instead. Consider removing the unused import or refactoring the tests to use Catch2's built-in matcher for consistency.

🧹 Suggested cleanup
-using Catch::Matchers::WithinAbs;
 using Util::Subrect::Controller;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/cpp/test_subrect.cpp` at line 19, The import Using
Catch::Matchers::WithinAbs in tests/cpp/test_subrect.cpp is unused because the
test suite uses the custom UVApprox helper; remove the unused import or replace
usages of UVApprox with Catch2's WithinAbs matcher. Locate the top-level using
Catch::Matchers::WithinAbs statement and either delete that line, or refactor
tests that currently call UVApprox to use Catch::Matchers::WithinAbs (and update
any EXPECT/REQUIRE calls accordingly) so the import is actually used.

344-348: 💤 Low value

Consider extracting test data for clarity.

The inline initialization of test pairs within the range-based for-loop is functional but slightly dense. For improved readability, consider extracting the degenerate dimension test cases to a named constant.

💡 Optional refactor for clarity
+	const std::vector<std::pair<uint32_t, uint32_t>> degenerateDimensions = {
+		{ 0, 100 }, { 1, 100 }, { 100, 0 }
+	};
-	for (auto [w, h] : std::vector<std::pair<uint32_t, uint32_t>>{ { 0, 100 }, { 1, 100 }, { 100, 0 } }) {
+	for (auto [w, h] : degenerateDimensions) {
 		const auto regions = c.GetStereoPixelRegions(w, h);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/cpp/test_subrect.cpp` around lines 344 - 348, Extract the inline test
data used in the range-based for loop into a named constant (e.g., const
std::vector<std::pair<uint32_t,uint32_t>> degenerateCases = { {0,100}, {1,100},
{100,0} }) and then iterate over degenerateCases when calling
c.GetStereoPixelRegions(w,h); keep the assertions on regions.leftEye.w and
regions.rightEye.w unchanged so the test behavior is identical but the test data
is clearer to readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Utils/Subrect.cpp`:
- Around line 99-102: The code sets rightUVLoadedFromJson = hasExplicitRight
even when only a subset of the CropRight* fields were present, which lets
partial configs override stale values and disable left→right mirroring; change
this so rightUVLoadedFromJson is only set true when the full quartet of
CropRight* keys was provided. Update the LoadSettings logic around
hasExplicitRight/rightUVLoadedFromJson to require a complete set (e.g., require
hasCropRightX && hasCropRightY && hasCropRightW && hasCropRightH or track
per-field presence flags) before marking rightUVLoadedFromJson true; if any of
the four are missing, leave rightUVLoadedFromJson false so
SetStereoEnabled(true) can auto-mirror. Ensure the new check references the same
symbols (hasExplicitRight, rightUVLoadedFromJson, and the per-field presence
flags used when parsing CropRight*).
- Around line 112-116: The current code assigns preset.rightUV =
LoadUVArray(entry["right_uv"]) whenever entry.contains("right_uv"), but
LoadUVArray returns a default full-frame UV on malformed input which incorrectly
suppresses auto-mirroring and applies a full-frame crop; change the logic in
Subrect.cpp so that when entry.contains("right_uv") you validate the payload
before assigning: either use a LoadUVArray variant that returns std::optional
(or validate entry["right_uv"] shape/size/types) and only set preset.rightUV
when the parsed value is valid, otherwise leave preset.rightUV as nullopt so
ApplyPreset can still auto-mirror the left eye; reference LoadUVArray,
preset.rightUV, ApplyPreset, and entry["right_uv"] when making the change.

---

Nitpick comments:
In `@tests/cpp/test_subrect.cpp`:
- Line 19: The import Using Catch::Matchers::WithinAbs in
tests/cpp/test_subrect.cpp is unused because the test suite uses the custom
UVApprox helper; remove the unused import or replace usages of UVApprox with
Catch2's WithinAbs matcher. Locate the top-level using
Catch::Matchers::WithinAbs statement and either delete that line, or refactor
tests that currently call UVApprox to use Catch::Matchers::WithinAbs (and update
any EXPECT/REQUIRE calls accordingly) so the import is actually used.
- Around line 344-348: Extract the inline test data used in the range-based for
loop into a named constant (e.g., const
std::vector<std::pair<uint32_t,uint32_t>> degenerateCases = { {0,100}, {1,100},
{100,0} }) and then iterate over degenerateCases when calling
c.GetStereoPixelRegions(w,h); keep the assertions on regions.leftEye.w and
regions.rightEye.w unchanged so the test behavior is identical but the test data
is clearer to readers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e0595b7d-33d7-4850-bbb2-0f9ff6d9b05a

📥 Commits

Reviewing files that changed from the base of the PR and between 170f368 and b58a8e2.

📒 Files selected for processing (3)
  • src/Utils/Subrect.cpp
  • src/Utils/Subrect.h
  • tests/cpp/test_subrect.cpp

Comment thread src/Utils/Subrect.cpp
Comment thread src/Utils/Subrect.cpp
alandtse added a commit that referenced this pull request May 21, 2026
…y regions

Three Copilot findings on PR #23:

- SetStereoEnabled(true) unconditionally called SyncRightUV(), so a
  caller that LoadSettings first (with stereo off) then enabled
  stereo would silently overwrite an explicit JSON CropRight* value
  with the mirror of the left eye. Track whether the right UV was
  loaded explicitly and skip the auto-mirror in that case. Add a
  regression test for the call order.
- The "Stereo preset save captures right-eye UV" test only validated
  that SaveSettings emits right_uv for existing presets — it didn't
  exercise the round-trip semantics it claimed to cover. Rewrite to
  stage an asymmetric right UV (one that doesn't equal MirrorUVHorizontal
  of left), save, reload into a fresh controller, and assert the
  right eye survived. That actually pins the regression.
- GetStereoPixelRegions returns regions in per-eye coordinate space
  (right eye x in [0, fullWidth/2), NOT pre-offset). Document this
  in the header so callers don't double-offset or place the right
  eye on top of the left.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 21, 2026 07:19
alandtse added a commit that referenced this pull request May 21, 2026
Five CodeRabbit findings on PR #23:

- rightUVLoadedFromJson was only ever set to true. A later LoadSettings
  without CropRight* keys would inherit the stale `true` and SetStereoEnabled
  would no longer auto-mirror as intended. Set the flag to hasExplicitRight
  unconditionally so each load owns the state. Regression test added.
- SaveSettings updated a caller-owned JSON in place but skipped clearing
  CropRight* keys when stereo was disabled. If a host re-saved into the
  same object the keys lingered and the next load looked like explicit
  stereo data. Erase the four keys in the mono branch. Regression test
  added.
- GetStereoPixelRegions divided fullWidth by 2 unconditionally; for
  widths 0 or 1 the per-eye width was 0 and UVToPixelRegion's `width - 1`
  underflowed. Guard `fullWidth < 2 || fullHeight == 0` with an empty
  region pair so callers can detect via .w == 0. Edge test added.
- Preset::rightUV defaulted to UVRegion{} (full frame), which conflated
  "no explicit right eye supplied" with "user wants full frame". The
  SeedDefaultPresets caller in ScreenshotFeature only sets .name + .uv,
  so in a stereo-consumer host the right eye would silently land on
  full frame instead of mirroring left. Make rightUV a
  std::optional<UVRegion>: nullopt means "auto-mirror at apply time".
  ApplyPreset and EnsureDefaultPreset fall back to MirrorUVHorizontal
  when nullopt; SaveSettings only persists right_uv when both stereo
  is enabled and an explicit value exists. Existing in-fork callers
  (ScreenshotFeature, in-tree tests, Save Preset button via implicit
  T->optional<T>) work unchanged. Regression test added.
- test_subrect.cpp used std::abs via transitive includes. Add an
  explicit #include <cmath>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from 5cc98f9 to f6eb4b8 Compare May 21, 2026 07:19
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread tests/cpp/test_subrect.cpp Outdated
Comment thread tests/cpp/test_subrect.cpp Outdated
alandtse added a commit that referenced this pull request May 21, 2026
…y regions

Three Copilot findings on PR #23:

- SetStereoEnabled(true) unconditionally called SyncRightUV(), so a
  caller that LoadSettings first (with stereo off) then enabled
  stereo would silently overwrite an explicit JSON CropRight* value
  with the mirror of the left eye. Track whether the right UV was
  loaded explicitly and skip the auto-mirror in that case. Add a
  regression test for the call order.
- The "Stereo preset save captures right-eye UV" test only validated
  that SaveSettings emits right_uv for existing presets — it didn't
  exercise the round-trip semantics it claimed to cover. Rewrite to
  stage an asymmetric right UV (one that doesn't equal MirrorUVHorizontal
  of left), save, reload into a fresh controller, and assert the
  right eye survived. That actually pins the regression.
- GetStereoPixelRegions returns regions in per-eye coordinate space
  (right eye x in [0, fullWidth/2), NOT pre-offset). Document this
  in the header so callers don't double-offset or place the right
  eye on top of the left.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
alandtse added a commit that referenced this pull request May 21, 2026
Five CodeRabbit findings on PR #23:

- rightUVLoadedFromJson was only ever set to true. A later LoadSettings
  without CropRight* keys would inherit the stale `true` and SetStereoEnabled
  would no longer auto-mirror as intended. Set the flag to hasExplicitRight
  unconditionally so each load owns the state. Regression test added.
- SaveSettings updated a caller-owned JSON in place but skipped clearing
  CropRight* keys when stereo was disabled. If a host re-saved into the
  same object the keys lingered and the next load looked like explicit
  stereo data. Erase the four keys in the mono branch. Regression test
  added.
- GetStereoPixelRegions divided fullWidth by 2 unconditionally; for
  widths 0 or 1 the per-eye width was 0 and UVToPixelRegion's `width - 1`
  underflowed. Guard `fullWidth < 2 || fullHeight == 0` with an empty
  region pair so callers can detect via .w == 0. Edge test added.
- Preset::rightUV defaulted to UVRegion{} (full frame), which conflated
  "no explicit right eye supplied" with "user wants full frame". The
  SeedDefaultPresets caller in ScreenshotFeature only sets .name + .uv,
  so in a stereo-consumer host the right eye would silently land on
  full frame instead of mirroring left. Make rightUV a
  std::optional<UVRegion>: nullopt means "auto-mirror at apply time".
  ApplyPreset and EnsureDefaultPreset fall back to MirrorUVHorizontal
  when nullopt; SaveSettings only persists right_uv when both stereo
  is enabled and an explicit value exists. Existing in-fork callers
  (ScreenshotFeature, in-tree tests, Save Preset button via implicit
  T->optional<T>) work unchanged. Regression test added.
- test_subrect.cpp used std::abs via transitive includes. Add an
  explicit #include <cmath>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from f6eb4b8 to f0c6520 Compare May 21, 2026 07:52
alandtse added a commit that referenced this pull request May 22, 2026
Address remaining Copilot nits on PR #23 test file:
- WithinAbs matcher and the floating-point matcher header were
  imported but never referenced; UVApprox uses std::abs directly.
  Drop both to keep the warnings-as-errors path clean.
- The degenerate-dimensions test enumerates uint32 pairs via
  std::vector<std::pair<...>>; include <vector> and <utility>
  explicitly instead of relying on transitive headers.
Copilot AI review requested due to automatic review settings May 22, 2026 05:22
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/Utils/Subrect.cpp
alandtse and others added 8 commits May 22, 2026 06:42
Adds an opt-in stereo extension to the screenshot's subrect controller
so stereo-aware consumers (the DLSS Enhancer subrect framework) can
track a mirrored right-eye UV alongside the existing primary UV without
forking the util. Mono callers (ScreenshotFeature) are unaffected:
SaveSettings emits bit-identical JSON, LoadSettings round-trips the
legacy schema, and the DrawEditor signature is unchanged.

New API:
- SetStereoEnabled(bool) / IsStereoEnabled()
- GetRightEyeUV() — folds onto primary UV in mono mode
- GetStereoPixelRegions(fullW, fullH) — resolves both eyes against
  per-eye half-width for SBS textures
- Preset gains an optional rightUV{} field

In stereo mode, drag/slider edits auto-mirror the primary UV to the
right eye around x=0.5 (HMD nose-side overlap symmetry). LoadSettings
mirrors left → right only for the legacy upgrade case (CropX/Y/W/H
present, no CropRight*), so a seeded preset's explicit right-eye UV
survives a fresh load.

The header is now self-contained (forward-declares D3D11 types,
includes nlohmann/json), so a test target can compile it without the
plugin PCH.

Adds a C++ unit test target (tests/cpp) covering mono back-compat,
stereo round-trip, legacy upgrade mirror, and per-eye pixel-region
math. 9 test cases, 33 assertions. Reuses Catch2 via FetchContent
dedup with tests/shaders. New CMake target run_cpp_tests.

Decomposed from community-shaders#2096 (PR-1 of 4); see DLSS-PR-PLAN.md.

Co-Authored-By: YtzyFvra <59631290+YtzyFvra@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CodeRabbit Major @ scs#2356: the Save Preset button only stored
currentUV, so a saved preset's rightUV was default-initialized.
Re-applying that preset would zero out the user's right-eye crop
in stereo mode.

Fix by extending the Preset constructor at the push site to capture
both eyes. In mono mode currentRightUV stays at default; in stereo
mode the user's actual right-eye UV is now persisted.

Adds a regression test guarding that SaveSettings emits right_uv
keys in CropPresets when stereo is enabled. Bumps the suite to
35 assertions / 10 test cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Empty commit to trigger CodeQL on this PR. The default-setup CodeQL
workflow only fires on synchronize events, not reopened, so a push
is required to gate the PR on the new code scan.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…y regions

Three Copilot findings on PR #23:

- SetStereoEnabled(true) unconditionally called SyncRightUV(), so a
  caller that LoadSettings first (with stereo off) then enabled
  stereo would silently overwrite an explicit JSON CropRight* value
  with the mirror of the left eye. Track whether the right UV was
  loaded explicitly and skip the auto-mirror in that case. Add a
  regression test for the call order.
- The "Stereo preset save captures right-eye UV" test only validated
  that SaveSettings emits right_uv for existing presets — it didn't
  exercise the round-trip semantics it claimed to cover. Rewrite to
  stage an asymmetric right UV (one that doesn't equal MirrorUVHorizontal
  of left), save, reload into a fresh controller, and assert the
  right eye survived. That actually pins the regression.
- GetStereoPixelRegions returns regions in per-eye coordinate space
  (right eye x in [0, fullWidth/2), NOT pre-offset). Document this
  in the header so callers don't double-offset or place the right
  eye on top of the left.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Five CodeRabbit findings on PR #23:

- rightUVLoadedFromJson was only ever set to true. A later LoadSettings
  without CropRight* keys would inherit the stale `true` and SetStereoEnabled
  would no longer auto-mirror as intended. Set the flag to hasExplicitRight
  unconditionally so each load owns the state. Regression test added.
- SaveSettings updated a caller-owned JSON in place but skipped clearing
  CropRight* keys when stereo was disabled. If a host re-saved into the
  same object the keys lingered and the next load looked like explicit
  stereo data. Erase the four keys in the mono branch. Regression test
  added.
- GetStereoPixelRegions divided fullWidth by 2 unconditionally; for
  widths 0 or 1 the per-eye width was 0 and UVToPixelRegion's `width - 1`
  underflowed. Guard `fullWidth < 2 || fullHeight == 0` with an empty
  region pair so callers can detect via .w == 0. Edge test added.
- Preset::rightUV defaulted to UVRegion{} (full frame), which conflated
  "no explicit right eye supplied" with "user wants full frame". The
  SeedDefaultPresets caller in ScreenshotFeature only sets .name + .uv,
  so in a stereo-consumer host the right eye would silently land on
  full frame instead of mirroring left. Make rightUV a
  std::optional<UVRegion>: nullopt means "auto-mirror at apply time".
  ApplyPreset and EnsureDefaultPreset fall back to MirrorUVHorizontal
  when nullopt; SaveSettings only persists right_uv when both stereo
  is enabled and an explicit value exists. Existing in-fork callers
  (ScreenshotFeature, in-tree tests, Save Preset button via implicit
  T->optional<T>) work unchanged. Regression test added.
- test_subrect.cpp used std::abs via transitive includes. Add an
  explicit #include <cmath>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- LoadSettings flagged hasExplicitRight if ANY single CropRight* key was
  present. A partial config (e.g. only CropRightW) then reused stale
  values for the missing components AND suppressed the mirror fallback.
  Require the full quartet via AND semantics so partial loads behave as
  "not explicit" and the auto-mirror runs.
- The preset-loop also accepted `right_uv` of any type and silently
  full-framed it via LoadUVArray's default. Validate is_array() + size()
  == 4 before treating it as explicit, otherwise leave the preset's
  rightUV as nullopt so ApplyPreset mirrors at apply time.
- "Save Preset" in mono mode snapshotted currentRightUV into the new
  preset's rightUV (now std::optional<UVRegion>), which falsely marked
  the preset as having an explicit right-eye crop. When stereo was later
  enabled and the preset re-applied, the auto-mirror was suppressed by
  the .has_value() check and the right eye landed on a stale UV. Only
  copy currentRightUV when stereoEnabled; otherwise leave rightUV as
  nullopt.

Three regression tests added covering each branch.
Empty commit to trigger CodeQL on this PR. The default-setup CodeQL
workflow only fires on synchronize events, not reopened, so a push
is required to gate the PR on the new code scan.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address remaining Copilot nits on PR #23 test file:
- WithinAbs matcher and the floating-point matcher header were
  imported but never referenced; UVApprox uses std::abs directly.
  Drop both to keep the warnings-as-errors path clean.
- The degenerate-dimensions test enumerates uint32 pairs via
  std::vector<std::pair<...>>; include <vector> and <utility>
  explicitly instead of relying on transitive headers.
@alandtse alandtse force-pushed the pr1-stereo-subrect branch from 1d34f35 to 84e9901 Compare May 22, 2026 06:42
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
CMakeLists.txt (1)

1319-1334: Consider tightening PR metadata for merge hygiene.

Current PR title is descriptive and conventional, but likely over the 50-char title guideline. A shorter variant like refactor(utils): add subrect stereo support would fit better.
If this maps to a tracking issue, add a keyword line such as Implements #<issue-id> in the PR description.

As per coding guidelines, "Format: type(scope): description", "Length: 50 characters limit for title", and "Suggest adding appropriate GitHub keywords: 'Implements #123' or 'Addresses #123' for features."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CMakeLists.txt` around lines 1319 - 1334, The PR metadata needs tightening:
shorten the PR title to the recommended "type(scope): description" format under
50 chars (for example use "refactor(utils): add subrect stereo support" instead
of the long title) and add a tracking keyword line in the PR description like
"Implements #<issue-id>" or "Addresses #<issue-id>"; update the repository PR
(the change affects the CMakeLists-related work such as targets cpp_tests and
run_cpp_tests) so the title follows the guideline and include the appropriate
issue reference in the description.
src/Utils/Subrect.h (1)

15-18: 💤 Low value

Consider scoping the json alias inside the namespace.

Placing using json = ... at global scope pollutes the namespace for all consumers of this header. Moving it inside namespace Util::Subrect would limit exposure while still allowing standalone compilation for unit tests.

💡 Alternative placement
-// Mirrors the global `using json = nlohmann::json;` from the plugin PCH so
-// the header builds standalone (e.g. in unit-test targets that don't
-// precompile PCH). Identical aliases in the same scope are well-defined.
-using json = nlohmann::json;
-
 namespace Util::Subrect
 {
+	// Mirrors the global `using json = nlohmann::json;` from the plugin PCH so
+	// the header builds standalone (e.g. in unit-test targets that don't
+	// precompile PCH).
+	using json = nlohmann::json;
+
 	struct UVRegion
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Utils/Subrect.h` around lines 15 - 18, The global using alias "using json
= nlohmann::json;" in Subrect.h pollutes global scope; move the alias into the
header's namespace block (e.g., inside "namespace Util::Subrect { ... }") so
tests and header users still get the alias when including this header but it is
not leaked to all consumers; locate the declaration of the alias in Subrect.h
and wrap or relocate it into the "Util::Subrect" namespace so that other code
outside that namespace is unaffected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@CMakeLists.txt`:
- Around line 1319-1334: The PR metadata needs tightening: shorten the PR title
to the recommended "type(scope): description" format under 50 chars (for example
use "refactor(utils): add subrect stereo support" instead of the long title) and
add a tracking keyword line in the PR description like "Implements #<issue-id>"
or "Addresses #<issue-id>"; update the repository PR (the change affects the
CMakeLists-related work such as targets cpp_tests and run_cpp_tests) so the
title follows the guideline and include the appropriate issue reference in the
description.

In `@src/Utils/Subrect.h`:
- Around line 15-18: The global using alias "using json = nlohmann::json;" in
Subrect.h pollutes global scope; move the alias into the header's namespace
block (e.g., inside "namespace Util::Subrect { ... }") so tests and header users
still get the alias when including this header but it is not leaked to all
consumers; locate the declaration of the alias in Subrect.h and wrap or relocate
it into the "Util::Subrect" namespace so that other code outside that namespace
is unaffected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ba7ff56e-7ba2-44da-bafd-5e2be58ba817

📥 Commits

Reviewing files that changed from the base of the PR and between b58a8e2 and 84e9901.

📒 Files selected for processing (6)
  • CMakeLists.txt
  • src/Utils/Subrect.cpp
  • src/Utils/Subrect.h
  • tests/cpp/CMakeLists.txt
  • tests/cpp/test_main.cpp
  • tests/cpp/test_subrect.cpp

@alandtse alandtse merged commit 97556f0 into dev May 22, 2026
20 checks passed
@alandtse alandtse deleted the pr1-stereo-subrect branch May 22, 2026 07:37
alandtse added a commit that referenced this pull request May 22, 2026
Mirrors the shader_tests pattern so cpp_tests is built and run only
when relevant files change (and always on push / workflow_dispatch /
release events).

pr-checks.yaml:
- New `cpp_tests` files_yaml category: `tests/cpp/**`
- New `cpp-tests-should-build` output combining cpp_tests +
  cpp (since the target compiles src/Utils/Subrect.cpp directly per
  tests/cpp/CMakeLists.txt — conservative-but-correct) + cmake +
  build_ci. Falls through to true on changed-files failure.
- New `run-cpp-tests` and `cpp-tests-should-build` inputs passed
  into _shared-build.yaml.

_shared-build.yaml:
- New `run-cpp-tests` (boolean, default true) and
  `cpp-tests-should-build` (string, default "true") inputs.
- New `cpp-unit-tests` job parallel to `shader-unit-tests`. Builds
  the `cpp_tests` target and runs `ctest -R CppUtilTests`. Gated
  inline (no composite action — the single branch is too small for
  the indirection).

Without this gate, the PR #23 stereo Subrect tests broke the cpp
build but CI stayed green because `--target shader_tests` never
touched the cpp_tests source files. Next time a cpp_tests test
fails to compile, this gate catches it at PR-check time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants