Skip to content

FG-Legacy: frame generation levels (2×–4×), capability test, in-stream toggle and pacer fixes - #1300

Merged
capy-ai[bot] merged 18 commits into
OpenCloudGaming:devfrom
MONZikWasTaken:feature/fg-legacy-levels
Nov 3, 2026
Merged

capy-ai[bot] merged 18 commits into
OpenCloudGaming:devfrom
MONZikWasTaken:feature/fg-legacy-levels

Conversation

@MONZikWasTaken

Copy link
Copy Markdown
Contributor

Description

Reworks the native Qt frame generation so it can be tested, controlled and trusted on real hardware, and restores the attribution to the Framegen project the earlier Electron integration came from (#718 → #763). The feature is called FG-Legacy in the app and docs; it is a stepping stone until the FlyHigh model replaces the engine.

Experimental. The current engine (block matching on a ≤320×180 flow grid) was never designed for games: expect strong artifacts on thin edges and fast motion. The UI says so with an Experimental badge and notice. The FlyHigh model will fix this.

What changes

Levels and modes

  • 2×, 3× and 4× end to end: settings → pacer → presentation. The engine computes the pair's flow once and synthesises N − 1 frames at t = k / N (each with its own render target and uniform buffer); the presenter keeps five external texture slots so every frame of a 4× pair is selectable.
  • One mode selector: Off / Multiplier / Target FPS / Display (Display picks the largest level the detected refresh can show). Display refresh is detected from the window's screen, with a manual override.

Capability test (gates the feature)

  • FrameGenerationBenchmark measures the engine offscreen on a private QRhi at the stream resolution, timing 2×, 3× and 4× separately (p95Ms, p95Ms3, p95Ms4). Results are stored per engine|gpu|resolution in settings (Rust-normalised, bounded).
  • Frame generation stays unavailable until a measurement exists. Which levels fit is decided live from the selected FPS and display: cost(N) ≤ 0.6 × interval, refresh ≥ N × fps × 0.975.
  • Run test opens a dialog with the full table: one row per stream FPS, one cell per level, each with ✓ or the reason (display / GPU / engine) and numbers on hover. Apply writes FPS, mode and level together.

In-stream control

  • Ctrl+G stream menu gets a Frame generation tile while the feature is in use; new rebindable shortcut Ctrl+Shift+G toggles it and reports through the stream control message.
  • Frame generation choices now persist through the core (they were only applied to the local settings map).

Pacer, fixed against a live GFN session (CS2, 1080p "60" FPS, 240 Hz)

  • The "60 FPS" stream actually ran at 61.7 FPS, so 4× needed ~247 Hz and the 240 Hz panel flipped to display-refresh constantly. The interval is now the median of the last eight per-frame deltas; the gate tolerates 5 % and lowers the factor for a pair instead of switching generation off.
  • Bursty delivery (two frames ~2 ms apart) was treated as overload with a 2 s cooldown. A burst now just drops the stale schedule; the cooldown is reserved for a presenter that stopped swapping (renamed Paused in the overlay). A single skipped source frame no longer re-warms.
  • The stats overlay names the reason behind Discontinuity; every status change is logged to qt-native.log with the pacer's numbers, and a GUI-thread stall probe logs gui-stall ms=… (frames are requested from the GUI thread).

Attribution

  • third_party/framegen/README.md, WEIGHTS_LICENSE.md and a THIRD_PARTY_NOTICES entry restored; GitHub icon in the capability-test row opens the Framegen repository. Design notes in docs/fg-legacy.md.

Diagnostics (opt-in, no effect unless set)

  • OPENNOW_FG_CAPTURE_DIR=<dir> saves the source pair and every generated frame as PNG a few times per session.
  • OPENNOW_FG_DUMP=<prev.png>;<cur.png>;<outdir>;<factor> runs the engine on two images in tst_frameinterpolator.

Testing

Windows 11, RTX 4060 Ti, D3D11, Qt 6.8.3:

  • tst_framepacer 24/24, tst_frameinterpolator 32/32 plus the opt-in dump case skipped (new 3×/4× step test: generated frames land exactly at t = k/N on translated texture), tst_framegenerationbenchmark 5/5, tst_nativeframegeneration 13/13 (new 4× presenter test), cargo test for opennow-core, cargo fmt --check, translation and keyboard-layout checks.
  • QML smokes with a visible window: frame generation settings, stats (desktop/console), frame-rate settings, stream controllers menu, shortcuts, guide.
  • Live GFN session: generation runs at 4× on a 240 Hz panel (local output 170–214 FPS). Capability test on this GPU at 640×360: 0.23 / 0.27 / 0.23 ms per source frame for 2× / 3× / 4×.

Known limitations

  • Visual quality is bounded by the block-matching engine: where flow is unreliable it copies the current frame (motion still reads as 60) and thin edges sparkle. This PR does not change the synthesis quality heuristics.
  • Stream-route QML smokes fail under QT_QPA_PLATFORM=offscreen on Windows ("Could not select the graphics adapter") with or without this change; they pass with a visible window.

🤖 Generated with Claude Code

MONZikWasTaken and others added 12 commits October 23, 2026 22:35
…splay refresh

Frame generation grows from a single 2x switch into a measured feature set:

- Levels off/2x/3x/4x (`frameGeneration`), a target output rate
  (`frameGenerationTargetFps`, 0 = follow the level; the level is derived
  as round(target / stream fps)) and a display refresh override
  (`frameGenerationDisplayHz`, 0 = the screen OpenNOW is on). The core
  validates all of them plus a bounded `frameGenerationProfiles` map.
- StreamFramePacer schedules N-1 generated frames per source interval
  (`generated()` / `takeNext()`), the display gate scales with the factor
  and the fixed 120 FPS ceiling is replaced by a 4 ms source floor. The
  interpolator contract reports how many frames it can synthesise
  (`generatedCount()` / `generatedTexture()`); the block-matching engine
  stays midpoint-only, so 3x/4x need the FG-Legacy engine.
- FrameGenerationBenchmark runs the engine offscreen on a private QRhi
  at the selected stream resolution with procedural frames and reports
  p50/p95 per generated frame (GPU timestamps when the backend delivers
  them, wall time around the blocking offscreen frame otherwise);
  `evaluate()` allows a level when p95 * (N-1) fits 60 % of a source
  interval, the display shows fps * N and the engine supports N.
  Results are saved per preset (engine|gpu|WxH|fps). Levels and targets
  stay locked in Settings until a passing profile exists; a selection the
  test rules out resets to Off. SettingsState owns the logic; desktop and
  console screens share it.
- Settings rows: level segments, Run test, a GitHub link to the Framegen
  repository, Target FPS and Display refresh; stats badge FRAME GEN Nx;
  "Source rate too high" replaces the 120 FPS limit label.
- FG-Legacy attribution: third_party/framegen notices and a
  THIRD_PARTY_NOTICES section; docs/fg-legacy.md describes the design.

Tests: framepacer (N-x schedule, display scaling, floor), a new
framegenerationbenchmark test (decision rules + a real measurement),
nativeframegeneration/streamvideo/frameinterpolator/localization, the
frame-generation QML acceptance (locked until tested, unlocked by a
profile) and the Rust settings tests. QML smoke tests that open the
stream route only run with a visible window on Windows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eature

- One mode control instead of three parallel settings: Off / Multiplier /
  Target FPS / Display (`frameGenerationMode`). Only the control the mode
  needs is shown: multiplier chips, or the output rates the display can
  show at 2x..4x the stream rate. Display mode takes the largest allowed
  multiplier for the detected refresh rate. Profiles saved before the
  mode existed with a level set read as multiplier mode.
- The capability test is its own row (status + Run test + Framegen on
  GitHub). Until it has passed for the current preset the feature is
  unavailable everywhere: mode controls are disabled and the stream
  surfaces ignore a stored level (`frameGenerationFactor()` is 0 unless
  the profile allows the requested factor). The stats acceptance seeds a
  passing profile; the QML acceptance checks the locked and unlocked
  states.
- Display refresh override moves under Advanced (Auto shows the
  detected rate); the first-run Boost hint mentions the test.
- Measurement falls back to wall time around the blocking offscreen
  frame when the backend reports no GPU timestamps (D3D11 does for
  offscreen frames); `gpuTimed` reflects it. New
  opennow-framegenerationbenchmark-tests covers the decision rules and a
  real measurement.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The capability test measured the GPU correctly but the verdict was frozen
at test time and every empty result read "Too slow", even when the display
was the limit. Profiles now store the measurement only, keyed by engine,
GPU and resolution (the cost does not depend on the frame rate); which
levels fit is recomputed from the selected frame rate and the current
display whenever either changes. The status names the actual reason:
the display cannot show fps x 2, the GPU exceeds the budget, or the engine
is midpoint-only; chip hints follow the same reasons. Measurements saved
with the old fps-suffixed key remain valid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…el table

Run test now opens a dialog that shows every option at once instead of one verdict for the current preset: the detected display rate with its override, the stream rate chips, the mode chips, and a table with one row per stream rate and one cell per level (2x, 3x, 4x). Each cell shows the output rate and a check mark or the reason it does not fit (display, GPU, engine); greyed cells explain the numbers on hover. Clicking a row picks the stream rate, clicking a cell the level or target, and Apply writes fps, mode and level together. The GPU is measured once when no profile exists.

SettingsState gains frameGenerationVerdictFor(fps) and frameGenerationMatrix(); --smoke-frame-generation-dialog seeds a 2 ms / 240 Hz measurement and opens the dialog for screenshots.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rant pacer; persisted choices

Ctrl+G gains a Frame generation tile while the feature is in use (on, or switched off from the menu this session); switching it off remembers mode, level and target in memory and switching it on restores them. The same toggle is bound to shortcutToggleFrameGeneration (default Ctrl+Shift+G) and reports through the stream control message. Frame generation choices now go through setSetting, so they persist across restarts (they were only applied to the local settings map before).

The presenter acquires the latest decoded frame, so a burst skips one source frame: StreamFramePacer now treats a single skipped frame as continuous once the cadence is known (per-frame deltas feed the cadence estimate) and only starts the two-second overload cooldown after four collisions within a second; a single early arrival just drops the stale schedule. The stats overlay names the reason behind a Discontinuity.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…times every level

The synthesize pass takes t: the previous frame travels t of its forward flow and the current frame (1 - t) of its backward flow, blended 1 - t : t, so one pair yields N - 1 frames at t = k / N. Each generated frame has its own render target and its own uniform buffer per slot, so the passes of one pair never overwrite each other's t inside a command buffer. MaximumFactor is 4; midpointTexture() keeps returning the frame nearest t = 0.5.

The capability test now times 2x, 3x and 4x in turn (one second each) and stores p95Ms, p95Ms3 and p95Ms4; evaluate() uses the measured per-level cost and falls back to p95 x (N - 1) for profiles from before. The engine maximum comes from the installed engine, not the stored profile, so an earlier measurement no longer caps the levels. On the RTX 4060 Ti the synthesis pass is nearly free next to the flow (0.23 / 0.27 / 0.23 ms per source frame at 640x360).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
StreamVideoTextureRenderer held three external texture slots (two history frames and the midpoint), so the second generated frame of a 3x or 4x pair failed selectTexture() and generation switched itself off with 'unavailable'. Five slots now cover the two history frames plus up to three generated frames. New tst_nativeframegeneration case drains 4x pairs through the production callback and asserts the status never drops to unavailable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ctors

The display gate used a stricter tolerance than the capability test and judged it on a single frame's timestamp delta, so 60 FPS x 4 on a 240 Hz panel flipped between active and display-refresh with every jittery frame. The pacer now smooths the source interval with the median of the last eight per-frame timestamp deltas (arrival deltas as the fallback) and applies the test's 0.975 tolerance.

A source frame that lands on an unfinished pair is a burst, not overload: the stale schedule is dropped and the newest pair wins. Overload is reserved for a stalled presenter, which the render callback reports when nothing new has been swapped for max(100 ms, 4 x interval). Every frame-generation status change is written to qt-native.log with the pacer's numbers, throttled to five lines a second, so flicker can be diagnosed from a real session.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The pacer's overload state means the display stopped taking frames, not GPU load; the stats overlay now says so instead of 'Overloaded'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ghtly short; log GUI stalls

A live '60 FPS' cloud stream ran at 61.7 FPS, so 4x needed ~247 Hz and the 240 Hz panel kept flipping generation into display-refresh. The display gate now tolerates 5 % overshoot and, when the display is still too slow, lowers the factor for the pair (the render callback ingests and schedules the pacer's effective factor); only when 2x does not fit is generation off.

The live log also showed a three-frame sequence gap every second. Frames are requested from the GUI thread, so StreamVideoItem now runs a 10 ms GUI-thread probe and logs stalls of 35 ms or more to qt-native.log. A wall-clock sensitive native test step was tightened so its arrival cadence stays inside the pacer's window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…live capture diagnostic

Settings rows can carry a status pill; frame generation shows an Experimental badge and, on desktop, console and in the capability dialog, a notice that the current engine was not designed for games and shows strong artifacts on thin edges and fast motion until the FlyHigh model replaces it.

Diagnostics: OPENNOW_FG_CAPTURE_DIR makes the render callback save the pair and every generated frame as PNG a few times per session, and OPENNOW_FG_DUMP runs the engine on two image files in tst_frameinterpolator (skipped otherwise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 10c2d36c-7a35-4e6d-bd46-c48108d9d225

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@zortos293

Copy link
Copy Markdown
Collaborator

@capyai give me screenshots how the settings looks

@capy-ai

capy-ai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Screenshots of the frame generation settings at this PR's head, from the desktop settings smoke harness (Linux, Xvfb, 1440×900, 1440p/120 FPS profile). The "tested" states use the PR's --smoke-frame-generation-dialog fixture, which seeds a measurement on a 240 Hz display override. The GPU name reads llvmpipe because this machine has no real GPU.

Before the capability test (frame generation locked)

Before the capability test

Capability test dialog

Capability test dialog

After the test: Multiplier mode

Multiplier mode

Target FPS mode

Target FPS mode

Display mode

Display mode

Advanced → Display refresh override

Display refresh override


Crash on Linux: on this branch the Stream settings page segfaults as soon as it opens, on every Vulkan (non-Windows, non-Metal) build. ShellStore.ensureFrameGenerationGpu() calls FrameGenerationBenchmark::gpuName(), and the temporary PrivateRhi it creates is destroyed in the wrong order. Members are destroyed in reverse declaration order, so instance (the QVulkanInstance) goes first and ~QRhi then calls vkDeviceWaitIdle through a dead instance:

#0 QVulkanDeviceFunctions::vkDeviceWaitIdle
#2 QRhi::~QRhi()
#5 PrivateRhi::~PrivateRhi  FrameGenerationBenchmark.cpp:80
#6 FrameGenerationBenchmark::gpuName  FrameGenerationBenchmark.cpp:179

Declaring instance before rhi fixes it. With that change applied locally, every page above renders:

 struct PrivateRhi {
-    std::unique_ptr<QRhi> rhi;
 #if !defined(Q_OS_WIN) && !QT_CONFIG(metal) && QT_CONFIG(vulkan) && __has_include(<vulkan/vulkan.h>)
     std::unique_ptr<QVulkanInstance> instance;
 #endif
+    std::unique_ptr<QRhi> rhi;
     QString error;
 };

Windows (D3D11) and macOS (Metal) don't take this path, which is why it didn't show up in the Windows testing.

@capy-ai

capy-ai Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Thanks for this. The design holds up: generation stays inside the existing presenter, it's off by default, storage is bounded, and sender timestamps are kept. Review on 17d01c04 (merges cleanly into dev) found a few bugs to fix before merge. All of them were reproduced on Linux/Qt 6.8.3; paths are relative to opennow-qt/.

Crash (P1)

  • src/streaming/rendering/FrameGenerationBenchmark.cpp:81-83 destroys the Vulkan instance before its QRhi, which then segfaults in QRhi::~QRhi → vkDeviceWaitIdle. Opening desktop Stream settings reaches this through gpuName(), so it crashes even with frame generation off.

Capability gate (P2)

  • qml/state/settings/SettingsState.qml:807 saves a finished measurement under the currently selected resolution instead of result.width/height. If you change resolution while the test runs, the result lands under the wrong key. A 640×360 run got stored as 3840×2160 and unlocked 4×.
  • SettingsState.qml:568 and FrameGenerationBenchmark.cpp:297-315 accept incomplete profiles. Rust turns missing timings into 0, QML passes ok:true, and evaluation never checks the sample count, so frames:0, p95Ms:0 enables 4×.
  • FrameGenerationBenchmark.cpp:92-93 benchmarks the default D3D11 adapter, not the stream adapter chosen in GraphicsDeviceSelection.cpp:266. On multi-GPU Windows systems it measures a different GPU than the one presenting.
  • SettingsState.qml:468,545-556 only fills in the GPU identity when Stream settings opens or a test runs. After a restart that goes straight into a game, a saved profile resolves to factor 0.

Pacer (P2)

  • src/streaming/rendering/StreamFramePacer.h:91,160: a skipped-frame pair (33.33 ms apart) gets scheduled at 16.67 ms cadence, so its motion plays at 2× speed. The arrival gap is also divided before it's checked against the 50 ms limit, so a 90 ms stall still gets interpolated.

Test

  • tests/tst_nativeframegeneration.cpp:531 lowers the fixture delay to 8 ms while timestamps still advance by 20 ms. The recovery check at :533 then gets display-refresh instead of active; putting the delay back to 20 ms makes it pass.

Full suite (ctest -LE interactive-desktop): 549/551 pass, and the two failures are the crash and that recovery test. Core Rust tests (845) and locales:check pass. Regression tests for the gate and pacer cases would be great.

@capy-ai

capy-ai Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

@MONZikWasTaken GitHub currently reports merge conflicts with dev, so this PR cannot be merged as it stands. Please update your branch from the latest dev, resolve the conflicts, and push the result here. Once updated, please rerun the relevant tests and make sure the PR's CI passes so we can reassess it for merge.

zortos293 and others added 2 commits November 3, 2026 19:42
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai

capy-ai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Pushed two separately reviewable repairs without merging this PR:

  • f75716b fixes the reproduced Vulkan teardown crash, rejects incomplete capability measurements, preserves measured GPU/resolution keys, hydrates saved-profile identity before direct launch, and prevents a result for another resolution from switching a valid current selection off. Both identity lookup and measurement now use the selected Windows adapter LUID and reject fallback to a different adapter.
  • 1d986da restores the recovery fixture's original 20 ms cadence to match its 20 ms sender timestamps. Its 8 ms sleep selected arrival cadence and exceeded the configured display gate. All recovery, ownership, release and active-state assertions remain unchanged; production pacing is untouched.

After the final edits, the application builds and all 551 noninteractive Qt CTests pass. The parent independently reran the benchmark, native frame-generation and orchestration targets successfully. Windows-only adapter tests still need Windows CI; Linux uses llvmpipe and does not establish physical hybrid-GPU acceptance.

This screenshot shows the real Qt dialog with seeded smoke timings, not measured GPU performance:

Qt capability dialog with seeded smoke timings

The seven existing dev-integration conflicts remain, so these passing checks do not make the feature merge-ready.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai

capy-ai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Published current-dev integration as merge commit 0cd994c6, retaining the separate benchmark/profile repairs f75716b2 and recovery-fixture correction 1d986da7. This updates the feature branch only; the PR has not been merged.

All seven real conflicts are resolved. The integration retains dev's sender-authored timing, sender-paced admission/deadlines, exact borrowed-handle release, and scene-graph/device teardown. Native streamer and NativeStreamRuntime remain byte-identical to dev's ABI18 implementations. The callback now combines those contracts with factor-based generation and drains pending generated frames on NO_FRAME/STALE_FRAME paths. Both the FG tile and pointer-lock row remain in the menu with coherent focus traversal.

New combined-contract tests cover sender-paced bypass at factors 0/2/4, borrowed NO_FRAME/STALE_FRAME handles while draining a 4× pair, and optional-control navigation in windowed/fullscreen modes. The benchmark is now included in dev's CI unit targets and Windows runtime/deployment lists; its registration regression failed before the fix.

Validation on the final integrated tree:

  • Complete application build passes.
  • All 591/591 noninteractive Qt CTests pass, including 41 CI unit targets, in 584.24 seconds.
  • Seven focused contract suites and 21 overlay/navigation checks pass. Parent independently reran six sender/benchmark/native/orchestration/menu targets successfully.
  • All 24 CI-workflow checks and staged/unstaged whitespace checks pass.

Fresh exact-head cross-platform CI/review is still required. Physical Windows D3D11/hybrid-GPU adapter selection and presentation feedback, macOS pointer confinement, and real GFN gameplay are not validated by this Linux/llvmpipe run.

The real Qt menu below uses synthetic acceptance telemetry and optional-control visibility, not gameplay or physical pointer-lock evidence.

Combined FG and pointer-lock menu, synthetic acceptance

zortos293 and others added 2 commits November 3, 2026 20:33
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai

capy-ai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Published two separately scoped follow-ups:

  • 81841299 fixes the two original pacing findings. The discontinuity gate now checks the raw arrival gap; generated slots use the accepted source pair's full span, while nominal cadence and display gates remain unchanged. Ten new regression rows failed before the fix: six skipped-pair timing cases across factors 2/3/4 and sender/arrival clocks, plus four over-limit raw-gap cases. The exact 50 ms boundary remains accepted, and the next consecutive pair returns to normal scheduling. All existing assertions remain intact.
  • 291fc6c4 corrects the Windows compile failure at the two new std::min calls by using (std::min)(...), without global header or build configuration changes. Macro-exposure syntax checks fail before and pass afterward; this host check is not an MSVC build.

The behavioral pacing patch passes all 591 Qt CTests and the 36-case pacer suite. After the final parentheses-only normalization, the app rebuild and all five affected native/pacer/sender/benchmark/stream-video targets pass; parent independently reran those same five targets. Fresh exact-head Windows CI is required to clear the reported failure. The prior Windows job did compile both the selected-adapter benchmark source and its tests, but stopped before executing them at the callback compile error.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@capy-ai

capy-ai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

All seven checks passed at 291fc6c4, including the unchanged-head macOS rerun. The SDP failure is independently reproducible as a pending MID collision, now isolated in #1406 rather than mixed into frame generation.

Published 92521905 to persist the benchmark's Qt JUnit result file in the existing CI diagnostics artifact. The prior Windows run executed the benchmark successfully but captured no per-case output, so it could not prove whether selected-adapter acceptance passed or skipped. No workload or assertion changed. Benchmark and orchestration checks pass; the parent independently reran both and inspected all 18 result cases. Linux correctly skips Windows D3D11 selection; software Vulkan timing is not physical-GPU acceptance. Fresh exact-head Windows CI must supply the missing case-level evidence. Hybrid-GPU selection/presentation feedback, Cocoa confinement and live gameplay remain unverified.

@capy-ai

capy-ai Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Exact-head verification at 92521905 is complete: all seven checks pass. The new Windows benchmark JUnit artifact contains 18 cases, zero failures and zero skips. selectedAdapterIsUsedAndMismatchesFailClosed, GPU identity lifecycle and measuresTheEngineOnThisGpu all passed, rather than being silently skipped.

The recorded adapter is Microsoft Basic Render Driver / D3D11, with gpuTimed: false. This confirms the selected-adapter and mismatch checks execute under Windows, not physical hybrid-GPU or production presentation-feedback acceptance. Those hardware checks, Cocoa confinement and live gameplay remain outstanding. No PR was merged.

@capy-ai
capy-ai Bot merged commit 503e927 into OpenCloudGaming:dev Nov 3, 2026
12 checks passed
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