Skip to content

feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer - #627

Open
qiin2333 wants to merge 4 commits into
masterfrom
feat/nvapi-stream-optimize
Open

feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer#627
qiin2333 wants to merge 4 commits into
masterfrom
feat/nvapi-stream-optimize

Conversation

@qiin2333

@qiin2333 qiin2333 commented May 6, 2026

Copy link
Copy Markdown
Collaborator

改了啥呢

这次把原本准备直接绑进 Sunshine core 的 NVIDIA Control Panel stream tuning,改成了一个生命周期插件方案:Sunshine 负责在关键 session 生命周期发 slot,插件负责可选的驱动 profile 调优。顺手也把 GitHub 驱动的插件市场第一层骨架搭起来了,杂鱼式手搓后端先退下,开源社区该用 PR、Release、Actions 和 Pages 来管生态。

  • 新增 Plugin Platform v1:扫描 assets/plugins / config plugins、读取 plugin.json、执行插件 exe、传入 JSON payload、读取 --result、记录 history。
  • 新增插件管理 API 和 Web UI 页面:展示插件、启用/禁用、schema-backed 配置、actions、capabilities、last run/history。
  • 新增 Marketplace tab 和只读 API:GET /api/plugins/marketplace 读取远程 registry index,并标注 installed/platform/installable 状态。
  • 新增 plugin-registry/ scaffold:listing schema、blocklist.json、生成后的 index.json、registry README。
  • 新增 registry 自动化:scripts/plugin-registry/build-index.jsnpm run plugin-registry:check、GitHub issue form、registry workflow。
  • 新增 docs/plugin_marketplace.md,说明 GitHub Releases / Pages / Actions / PR review 如何运营社区插件市场。
  • 新增官方 Windows 插件 sunshine-plugin-nvprefs.exe,随包安装到 assets/plugins/com.alkaidlab.nvidia-control-panel-optimizer/
  • Sunshine core 只发生命周期事件:startup recovery、first non-control session start、FPS dynamic params changed、last non-control session stop、shutdown restore。
  • NVIDIA 插件在这些 slot 内处理 NVCP profile recovery、Sunshine high power mode、OpenGL/Vulkan DXGI present path,以及 opt-in 的 per-game VSync/FRL/low latency tuning。
  • 保留 --restore-nvprefs-undo 作为手动恢复入口,迁移期更稳一点,坏状态这种杂鱼也有后路。

为啥要这样改

PR #627 的初衷还是对的:帧生成或 unlocked-FPS 游戏在串流时需要 driver-level VSync + FRL,才能减少 tearing、missed frames 和高 PCL latency。但这个能力本质上是可选、平台相关、可能随驱动生态变化的扩展,不适合继续长在 Sunshine 的核心生命周期里。

插件化之后:

  • core 只保留通用 lifecycle slot。
  • NVIDIA 调优可以独立升级、禁用、记录历史、暴露权限/capabilities。
  • GUI 能把官方插件、已安装插件和未来社区插件放在同一个管理页里。
  • marketplace registry 可以通过 GitHub PR review 上架/下架,通过 Releases 分发,通过 Pages 发布 index,通过 Actions 校验。
  • 非 NVIDIA 环境保持安全 no-op。

市场框架边界

这一版是 browse-first,不做一键安装:

  • registry index 默认指向 https://alkaidlab.github.io/sunshine-plugin-registry/index.json
  • 开发/预发可用 SUNSHINE_PLUGIN_MARKETPLACE_INDEX_URL 覆盖。
  • Marketplace tab 可以展示上架插件并打开 release 页面。
  • 直接 install/update 暂不开放,等 hash 校验、解包策略、签名/attestation、rollback 语义补齐后再做,不让半吊子安装器出来丢人。
  • registry workflow 的 Pages 发布 job 只会在 AlkaidLab/sunshine-plugin-registry 仓库运行;留在主仓时只做校验,不抢主仓 Pages。

安全和回滚

  • stream-time 优化默认关闭:nv_optimize_game = false
  • 写 BASE profile 默认关闭:nv_apply_to_base_profile = false
  • undo manifest 扩展为 opengl_swapchain / game_profile / base_extras 三段,旧 undo 文件仍可解析。
  • restore 只在当前值仍等于我们写入的值时回滚 setting。
  • 清理 application/profile 时只操作 undo 里记录的原始 profile,避免误删用户后来移动到的 profile。
  • NvAPI lookup 明确区分 not-found 和真实错误,不再把所有非 OK 都当作“可以创建”。
  • 恢复不完整或保存失败时保留 undo 文件,下一次启动可继续 retry。
  • 动态参数 payload 读取改为 memcpy + little_to_native,避免未对齐 reinterpret_cast

对外插件文档

新增/更新文档:

  • docs/plugin_development.md:插件 manifest、lifecycle slots、actions、调用协议、payload/result JSON、capabilities。
  • docs/plugin_marketplace.md:GitHub registry 运营模型、上架/下架状态、blocklist、安全审查和未来 install/update 边界。
  • docs/plugin_lifecycle_plan.md:同步 Phase 4 marketplace scaffold 状态。

验证

已在无 NVIDIA 环境完成这些检查:

  • npm run plugin-registry:check
  • Node JSON parse:registry、schema、locale、package.json
  • npm run build
  • git diff --check
  • cmake --build --preset dev --target sunshine --parallel 4
  • cmake --build --preset dev --target sunshine-plugin-nvprefs --parallel 4
  • Node parse 校验官方插件 plugin.json / config.schema.json
  • fake lifecycle payload smoke:stream.first_session.starting,无 NvAPI 时安全 skip 并写 success result
  • fake lifecycle payload smoke:stream.dynamic_params.changed no-op 配置路径
  • fake lifecycle payload smoke:stream.dynamic_params.changed + dynamic_stream_params=true,无 NvAPI 时安全 skip 并写 success result

已知现有 warning:src/nvhttp/display_scale.cpp:55 有未使用函数 warning,不是本 PR 引入。

还需要 NVIDIA 实机确认

当前环境没有真实 NVIDIA 驱动/profile DB,所以这些点需要在 N 卡 Windows 主机上验:

  1. 插件页开启 NVIDIA optimizer,并打开 nv_optimize_game
  2. 启动一次非 control-only 串流,使用 NVIDIA Profile Inspector 检查 per-game profile:
    • VSYNCMODE = ForceOn
    • FRL_FPS = client_fps + nv_frl_fps_offset,默认即 client fps - 2
    • 可选 PREFERRED_PSTATE / PRERENDERLIMIT 按配置生效
    • 当前游戏 EXE 被挂到 profile 下
  3. 停止最后一个非 control-only session 后,确认 setting/application/profile 被恢复/清理。
  4. kill Sunshine 模拟崩溃,再启动,确认 startup recovery 消费 nvprefs_undo.json 并恢复 profile。
  5. 开启 dynamic_stream_params 后调整 FPS,确认 FRL 随新的 client_fps 更新。

Closes none.

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

在 Windows 上新增按游戏的 NVIDIA 驱动流式优化与撤销(nvprefs)支持,扩展相关配置与 UI;在流处理路径加入平台钩子以应用/恢复优化;同时扩展 undo 数据模型并在流代码中加入麦克风加密生命周期、动态参数(分辨率/FPS 等)处理与会话快照接口;并对 Windows capture_target 做校验与告警。

Changes

NVIDIA 流优化功能

Layer / File(s) Summary
配置数据结构
src/config.h, src/config.cpp
config::video_t 中新增 NVENC 选项字段(nv_optimize_game、nv_force_vsync、nv_lock_frame_rate、nv_frl_fps_offset、nv_frl_fps_override、nv_prefer_max_performance、nv_low_latency_mode、nv_apply_to_base_profile),并在初始化与 apply_config 中赋默认值/读取(含范围约束)。
平台抽象接口
src/platform/common.h
添加平台钩子声明 platf::apply_stream_optimizations(const std::string&, int)platf::restore_stream_optimizations()(含文档注释)。
跨平台实现
src/platform/linux/misc.cpp, src/platform/macos/misc.mm, src/platform/windows/misc.cpp
Linux/macOS 提供空实现;Windows 实现包含 exe 名称提取、配置检查,并通过 nvprefs 实例委托应用/恢复优化;Windows misc.cpp 新增对 src/config.h 的包含。
nvprefs 配置传递
src/platform/windows/nvprefs/nvprefs_common.h, src/platform/windows/nvprefs/nvprefs_common.cpp
nvprefs_options 添加对应 nv_* 字段并在 get_nvprefs_options() 中从 config::video 复制这些选项。
撤销数据模型
src/platform/windows/nvprefs/undo_data.h, src/platform/windows/nvprefs/undo_data.cpp
新增 setting_undo_tgame_profile_tbase_extras_t 类型,扩展 undo_data_t 的序列化/反序列化与 set/get/clear 接口,merge 中支持新字段。
驱动设置应用逻辑
src/platform/windows/nvprefs/driver_settings.h, src/platform/windows/nvprefs/driver_settings.cpp
新增公有方法并实现:check_and_modify_game_profilerestore_game_profile_to_undocheck_and_modify_base_extrasrestore_base_extras_to_undo,内部包含 FRL 计算、desired_settings 生成、单项应用/恢复与完整写入。
NVPREFS 接口层
src/platform/windows/nvprefs/nvprefs_interface.h, src/platform/windows/nvprefs/nvprefs_interface.cpp
新增 apply_stream_optimizations(const std::wstring&, int)restore_stream_optimizations() 公共接口;新增 ensure_undo_dir_and_file() 辅助,改进撤销文件创建、合并、写盘与恢复流程,调整析构/恢复时序以保证一致性。
NVAPI Wrappers
src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
新增对若干 NvAPI DRS 函数的封装:NvAPI_DRS_FindApplicationByName、NvAPI_DRS_GetProfileInfo、NvAPI_DRS_DeleteProfile、NvAPI_DRS_DeleteApplication。
Web UI 与本地化
src_assets/.../useConfig.js, src_assets/.../NvidiaNvencEncoder.vue, src_assets/.../locale/en.json, src_assets/.../locale/zh.json
在默认配置、UI(Windows 条件渲染)及中/英本地化中新增 NVENC 优化的主开关与子选项文本与描述。

流媒体会话增强与动态参数

Layer / File(s) Summary
麦克风加密生命周期
src/stream.cpp
新增 per-client 麦克风管理 API:ensure_mic_sock_openreset_mic_encryptionremove_mic_encryptionsetup_mic_for_session,并在会话流中使用以管理 mic 套接字与加密上下文。
动态参数处理
src/stream.cpp
扩展 IDX_DYNAMIC_PARAM_CHANGE 解析:新增 RESOLUTION(宽/高 验证、旋转检测、显示重配/请求 IDR)、FPS(小端读、验证并应用)及若干单值参数的读取/验证;改用 read_le_u32/read_le_f32 以替代直接 reinterpret_cast。
会话信息查询
src/stream.cpp
新增 get_all_sessions_info(),返回当前活跃会话的快照信息(客户端/应用/端口/分辨率/帧率/码率/麦克风/HDR 等)。
头文件补充
src/stream.cpp
新增 <fstream><openssl/err.h> 的包含以支持文件操作与错误处理路径。
平台调用点
src/stream.cpp
在首次非控制会话启动时调用 platf::apply_stream_optimizations(game_cmd, fps),在最后一个非控制会话结束前调用 platf::restore_stream_optimizations()
Windows capture 校验
src/config.cpp
在 apply_config 中新增 Windows 专属校验:对 capture_target 默认/限制为 "display""window",并在选择 "window"window_title 为空时记录警告;对 FRL 偏移/覆盖值做范围夹紧。

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant StreamStart as Stream Start
    participant AppQuery as App Query
    participant PlatformHook as Platform Hook
    participant NVPrefs as NVIDIA Prefs
    participant DriverAPI as Driver API

    Client->>StreamStart: 启动第一个会话
    activate StreamStart
    StreamStart->>AppQuery: 获取当前运行的游戏命令
    AppQuery-->>StreamStart: 返回 game_cmd

    StreamStart->>PlatformHook: apply_stream_optimizations(game_cmd, fps)
    activate PlatformHook
    PlatformHook->>PlatformHook: 检查 config.nv_optimize_game
    alt 优化已启用
        PlatformHook->>NVPrefs: apply_stream_optimizations(exe_name, fps)
        activate NVPrefs
        NVPrefs->>DriverAPI: 应用游戏配置文件设置 / 应用 BASE 设置(可选)
        DriverAPI-->>NVPrefs: 返回撤销数据
        NVPrefs-->>PlatformHook: 返回成功
        deactivate NVPrefs
    end
    PlatformHook-->>StreamStart: 优化已应用
    deactivate PlatformHook
    StreamStart-->>Client: 会话已启动
    deactivate StreamStart

    Client->>StreamStart: 关闭最后一个会话
    activate StreamStart
    StreamStart->>PlatformHook: restore_stream_optimizations()
    activate PlatformHook
    PlatformHook->>NVPrefs: restore_stream_optimizations()
    NVPrefs->>DriverAPI: 从撤销数据恢复设置
    DriverAPI-->>NVPrefs: 恢复完成
    NVPrefs-->>PlatformHook: 恢复成功
    deactivate PlatformHook
    StreamStart-->>Client: 会话已关闭,优化已恢复
    deactivate StreamStart
Loading
sequenceDiagram
    participant Client
    participant ControlThread as Control Thread
    participant SessionMgr as Session Manager
    participant DisplayMgr as Display Manager
    participant Encoder as Encoder

    Client->>ControlThread: 发送 IDX_DYNAMIC_PARAM_CHANGE
    activate ControlThread
    ControlThread->>ControlThread: 解析参数载荷(小端读)

    alt 参数为 RESOLUTION
        ControlThread->>ControlThread: 验证 width/height(范围)
        ControlThread->>SessionMgr: 更新 session.config.monitor 分辨率
        SessionMgr-->>ControlThread: 已更新
        ControlThread->>DisplayMgr: 重新配置显示
        DisplayMgr-->>ControlThread: 配置完成
        ControlThread->>Encoder: 请求 IDR 帧
        Encoder-->>ControlThread: IDR 已请求
    else 参数为 FPS 或其他
        ControlThread->>ControlThread: 验证并应用新值,触发事件
    end

    ControlThread-->>Client: 参数更新已处理
    deactivate ControlThread
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.63% 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
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.
Title check ✅ Passed The title "feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer" accurately describes the PR's main scope: adding plugin infrastructure, a marketplace system, and NVIDIA optimization capabilities.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the plugin lifecycle system, marketplace scaffold, NVIDIA stream optimization, and security/rollback mechanisms.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/nvapi-stream-optimize

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/platform/windows/misc.cpp`:
- Around line 1398-1416: extract_exe_basename_w currently constructs
std::filesystem::path from a narrow std::string which on Windows is interpreted
using the ANSI code page; instead convert the extracted UTF‑8 token to a wide
string using the existing from_utf8 helper before creating a path and calling
filename(), e.g. use from_utf8(token) to produce a std::wstring path, then call
std::filesystem::path(wide_token).filename().wstring(), lowercase it as before
and return it (update function extract_exe_basename_w and keep usage consistent
with resolve_command_string and nvprefs_instance.apply_stream_optimizations).

In `@src/platform/windows/nvprefs/driver_settings.cpp`:
- Around line 615-649: The current undo flow returns immediately when any
restore_uint_setting (called for undo_data.vsync, undo_data.frl,
undo_data.pstate, undo_data.prerender) fails, which skips remaining setting
restores and the cleanup logic (NvAPI_DRS_DeleteApplication /
NvAPI_DRS_DeleteProfile); change the logic in the restore function so each
restore_uint_setting call is attempted regardless of previous failures, record
any failures (e.g., set a local bool had_error = true), continue executing the
remaining restores and then always run the application/profile cleanup block
(checking undo_data.application_was_added and undo_data.profile_was_created and
calling NvAPI_DRS_DeleteApplication / NvAPI_DRS_DeleteProfile), and finally
return success only if no individual restore or cleanup failed; apply the same
change to restore_base_extras_to_undo to ensure both paths attempt all restores
and cleanups before returning an aggregated result.
- Around line 565-569: Replace the lossy wchar_t->char iterator-based
conversions when populating undo_data_t::data_t::game_profile_t (set
pending.profile_name and pending.exe_path from profile_name_used and exe_name)
with UTF-8 safe conversions using platf::to_utf8(), and likewise when reading
back from JSON before calling NvAPI_DRS_FindApplicationByName() and
NvAPI_DRS_FindProfileByName() use platf::from_utf8()/platf::to_utf8() as
appropriate so non-ASCII characters are preserved; specifically, swap the
std::string(profile_name_used.begin(), profile_name_used.end()) and
std::string(exe_name.begin(), exe_name.end()) uses for
platf::to_utf8(profile_name_used) / platf::to_utf8(exe_name) and apply the
inverse conversions in the restore paths that prepare names for the NvAPI_*
lookup calls.
🪄 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: 787bb4cc-87cc-4400-abf5-d15839080de6

📥 Commits

Reviewing files that changed from the base of the PR and between ed1c794 and 01f72a726bac6ad0c428bc8b8f9ca2ba333c090e.

📒 Files selected for processing (19)
  • src/config.cpp
  • src/config.h
  • src/platform/common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/stream.cpp
  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/public/assets/locale/zh.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Windows
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/config.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/driver_settings.h
  • src/config.cpp
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/stream.cpp
src/platform/**

⚙️ CodeRabbit configuration file

src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

Files:

  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
src_assets/**/*.{vue,js,html}

⚙️ CodeRabbit configuration file

src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

Files:

  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
🔇 Additional comments (20)
src_assets/common/assets/web/composables/useConfig.js (1)

145-153: 新增 NVENC 默认配置项设计合理。

这 8 个配置键的默认值与“总开关默认关闭、子项可预设”的策略一致,且不会引入前端侧安全风险。

src/config.h (1)

42-54: video_t 扩展字段与注释质量良好。

新增字段覆盖了功能开关、参数和作用范围,注释对回滚语义解释清晰,便于后续维护。

src/config.cpp (2)

408-415: 新增默认值策略正确。

nv_optimize_game 默认关闭,同时保留其余参数默认值,整体符合“显式启用后生效”的安全路径。


1138-1145: 配置读取链路接入完整。

8 个 nvenc_* 配置项都已映射到对应 video 字段,和结构体扩展保持一致。

src/platform/windows/nvprefs/undo_data.h (1)

23-61: Undo 数据模型与接口设计清晰、可扩展。

分层结构(setting/game/base)和配套访问器完整,适合实现保守回滚与崩溃恢复。

Also applies to: 70-87

src_assets/common/assets/web/public/assets/locale/zh.json (1)

384-400: 本地化键新增完整且语义一致。

文案覆盖面足够,能支撑新功能在中文 UI 中的可理解性与可配置性。

src/platform/windows/nvprefs/nvprefs_common.cpp (1)

39-46: nvprefs_options 映射补充完整。

新增字段与 config::video 命名一致,透传逻辑清晰,便于后续平台实现读取。

src/platform/linux/misc.cpp (1)

313-321: Linux 侧 no-op 实现合理。

该实现保持了平台接口一致性,同时避免在 Linux 上引入无效副作用。

src/platform/common.h (1)

742-763: 平台抽象接口定义清晰。

apply/restore 的职责边界和参数语义明确,便于各平台实现保持一致行为。

src/platform/macos/misc.mm (1)

241-249: LGTM!

macOS 上提供空实现作为平台抽象层的占位符是合适的,与 Linux 端的处理方式一致。

src/platform/windows/nvprefs/nvprefs_interface.h (1)

39-58: LGTM!

接口声明清晰,文档注释充分说明了语义(包括在崩溃恢复场景下的行为以及 exe_name 为空时静默跳过的约定)。

src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue (1)

196-285: LGTM!

新增的 NV 控制面板自动优化区块结构清晰:

  • 通过 platform === 'windows' 正确隐藏在非 Windows 平台。
  • 使用 <template v-if> 包裹依赖项,主开关关闭时不渲染从属控件,避免无意义的状态写入。
  • FRL offset/override 仅在 nvenc_lock_frame_rate === 'enabled' 时显示,与后端 compute_frl_fps 的判断一致。
  • 数值输入有合理的 min/max 约束。
  • 折叠面板结构与现有 NVENC Misc 节保持一致,保留了键盘可访问性。
src/platform/windows/misc.cpp (1)

1419-1443: LGTM!

入口的开关检查、nvprefs_instance.load() 失败时的静默跳过、以及 apply/restore 对称的 load/unload 配对都是合理的。Linux/macOS 端有等价的 no-op 实现,无需 #ifdef 来包裹调用方逻辑。

src/platform/windows/nvprefs/nvprefs_interface.cpp (2)

254-300: LGTM

即便 check_and_modify_game_profile 失败也继续走 base 路径,并把已写入的部分 undo 持久化,这与 driver_settings.cpp 中"失败时仍设置 undo_out"的契约相符,可以让后续 restore 尽力回滚。pimpl->undo_data->merge(fresh) 也保证了之前 modify_global_profile() 留下的 OpenGL swapchain undo 不会被覆盖。


302-338: LGTM

按 game_profile/base_extras 分别 restore 并清空对应字段,最后判断 undo_data 是否完全为空再决定删除还是改写 undo 文件,避免了把 modify_global_profile() 留下的 OpenGL swapchain 信息误删。

src/platform/windows/nvprefs/nvprefs_common.h (1)

56-71: LGTM!

主开关 nv_optimize_game = false 默认关闭,符合 PR 描述的 opt-in 策略;从属选项的默认值(强制 VSync/锁帧 = true,最大性能/低延迟/写 BASE = false)在主开关启用后是合理的"安全推荐配置"。注释中标注了每个字段对应的 NVAPI setting ID/value,可读性好。

src/platform/windows/nvprefs/driver_settings.h (1)

64-105: LGTM!

接口分组合理:check_and_modify_*restore_*_to_undo 成对出现,签名与 undo_data_t::data_t::game_profile_t / base_extras_t 类型保持一致,文档清楚说明了"应用 → 写 undo → 还原"的整个流程以及 SunshineStreamGame 配置文件按需创建的语义。

src/platform/windows/nvprefs/undo_data.cpp (1)

19-153: JSON 序列化扩展实现稳健,向后兼容性处理得当。

data_t::from_json 对新增的 game_profile / base_extras 使用 contains() 守卫读取,保证旧版 undo 文件能正常解析;game_profile_t::from_json 对结构性字段(profile_name/exe_path/...)使用 at()、对可选 setting 字段使用 contains(),划分合理。to_json 始终输出全部字段,配合现有的 adl_serializer<std::optional<T>> 让 nullopt → JSON null 可正确往返。

src/stream.cpp (2)

3030-3031: LGTM — 与 apply 路径配对正确。

restore_stream_optimizations()--running_non_control_only_sessions == 0 分支内、紧接显示设备状态恢复之后、streaming_will_stop() 之前调用,构成 "apply after start / restore before stop" 的镜像顺序,并且独立于 restore_display_state 决策——即便 app 仍在运行也会回滚 NV 控制面板,这与 PR 中 "stream 结束即回滚" 的语义一致。


3127-3136: ⚡ Quick win

生命周期挂载和边界情形处理妥当。

挂载位置正确:apply_stream_optimizationsstreaming_will_start() 之后、并且只在第一条非控制会话起来时(++running_non_control_only_sessions == 1)调用一次,与 Line 3030 的 restore_stream_optimizations 形成对称。if (auto app_id = proc::proc.running()) 的 if-init 用法干净,确保 game_cmd 在没有前台应用时保持空字符串。

Windows 端的 nvprefs 接口在 header 中明确文档化:"Empty string skips the per-game profile leg silently"(空字符串静默跳过逐游戏 profile 步骤),因此不会生成无效的 profile 条目。该安全合约由上层 apply_stream_optimizations 实现遵守,不存在副作用风险。

Comment thread src/platform/windows/misc.cpp Outdated
Comment thread src/platform/windows/nvprefs/driver_settings.cpp
Comment thread src/platform/windows/nvprefs/driver_settings.cpp
@qiin2333
qiin2333 force-pushed the feat/nvapi-stream-optimize branch from 01f72a7 to ead12a9 Compare May 6, 2026 06:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/platform/windows/nvprefs/undo_data.cpp (1)

226-238: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

merge() 现在无法删除已经写入的 undo 分支。

这里的语义有歧义:nullopt 同时表示“这次没有更新”和“这次明确清掉了该分支”,但 Line 231-238 只在 source 有值时覆盖。结果是旧文件里一旦写入 game_profile / base_extras,后续即使调用 clear_game_profile() / clear_base_extras(),再经过 merge() 也删不掉旧数据,残留的回滚项下次启动还会被再次回放。

建议让 merge 明确区分“保留旧值”和“显式删除”,或者不要用 merge 语义回写 restore 后的最新快照。

🤖 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/platform/windows/nvprefs/undo_data.cpp` around lines 226 - 238, merge
currently treats a missing optional the same as "no-op", so explicit clears in
newer_data are ignored; update undo_data_t::merge to detect explicit deletions
and call the corresponding clear_* methods instead of only overwriting when
get_* returns a value. Concretely, add or use explicit presence/cleared
indicators (e.g. is_game_profile_cleared/is_game_profile_set or a three-state
getter) and change merge to: if newer_data indicates "cleared" call
clear_game_profile(), else if newer_data provides a value call
set_game_profile(*game); do the same for get_base_extras/set_base_extras and for
get_opengl_swapchain (call set_opengl_swapchain or a clear_opengl_swapchain when
appropriate) so explicit deletes in newer_data remove previously written
branches.
src/stream.cpp (1)

1459-1518: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

使用 std::memcpy 替代 reinterpret_cast 进行网络 payload 反序列化

代码在多处直接将 std::string_view 缓冲区 reinterpret_cast 为 int*float* 指针:

  • 第 1459 行:*reinterpret_cast<const int *>(payload.data())
  • 第 1477、1492、1510 行:类似的 reinterpret_cast 操作

该缓冲区不保证 4 字节对齐,违反指针对齐要求,这在 C++ 中属于未定义行为(虽然 x86 可能容忍,但 ARM/PowerPC 等架构会导致崩溃或静默数据损坏)。建议改为:

std::uint32_t param_type_raw = 0;
std::memcpy(&param_type_raw, payload.data(), sizeof(param_type_raw));
const int param_type = static_cast<int>(param_type_raw);  // 需补充字节序转换

同时,网络协议通常使用固定字节序(如网络字节序),代码中其他地方使用了 boost::endian::little_uint16_at,建议在此处也显式处理字节序转换。

🤖 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/stream.cpp` around lines 1459 - 1518, Replace all unaligned
reinterpret_cast reads from payload.data() with safe memcpy-based
deserialization and explicit byte-order handling: read the initial parameter
type into a std::uint32_t via std::memcpy and convert to int for param_type
(used where param_type is currently computed), read width/height into
uint32_t/int values via std::memcpy before calling handle_resolution_change,
read the float FPS value into a float via std::memcpy before
validating/assigning session->config.monitor.framerate and building
video::dynamic_param_t, and read other integer params (param_value) via memcpy;
ensure you apply the appropriate endianness conversion (e.g. boost::endian
helpers or ntohl/ntohf equivalent) for each field.
♻️ Duplicate comments (1)
src/platform/windows/misc.cpp (1)

1398-1415: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

不要把 UTF-8 命令直接传给 std::filesystem::path(std::string)

这个问题前一轮已经提过,当前实现还在。Line 1411 在 Windows 上会按系统窄字符代码页而不是 UTF-8 解释 token,带中文/日文路径时 filename() 会被解码错,后续按 EXE 名匹配 NVIDIA profile 就会失败。

🛠️ 建议修改
-      auto fname = std::filesystem::path(token).filename().wstring();
+      auto fname = std::filesystem::path(from_utf8(token)).filename().wstring();
🤖 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/platform/windows/misc.cpp` around lines 1398 - 1415, The code currently
constructs std::filesystem::path from a narrow UTF-8 std::string (token) which
on Windows is interpreted using the ANSI code page; instead convert token from
UTF-8 to a wide string and build the path from that wide string. In function
extract_exe_basename_w, after extracting token, convert token to std::wstring
using a UTF-8→UTF-16 conversion (e.g. MultiByteToWideChar with CP_UTF8 or a
trusted UTF-8 conversion helper) and then call
std::filesystem::path(wide_token).filename().wstring(), keep the existing
lowercasing on the returned std::wstring, and preserve the early-empty checks
and quoting logic. Ensure the conversion handles errors/empty results
consistently.
🧹 Nitpick comments (1)
src/platform/windows/nvprefs/driver_settings.h (1)

73-79: ⚡ Quick win

修正文档参数名与函数签名不一致

@param undo_data 与实际参数 undo_out 不一致,建议统一为 undo_out,避免后续调用和维护时误读。

🤖 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/platform/windows/nvprefs/driver_settings.h` around lines 73 - 79, Doc
param name mismatches the function signature: change the Doxygen `@param` from
"undo_data" to "undo_out" in the comment for check_and_modify_game_profile so
the documented parameter matches the actual parameter undo_out; update the
comment text if needed to reflect that undo_out is an output parameter
containing the undo data (reference: function
check_and_modify_game_profile(const std::wstring &exe_name, int client_fps,
std::optional<undo_data_t::data_t::game_profile_t> &undo_out)).
🤖 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_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue`:
- Around line 197-205: 为新增的折叠面板补齐可访问性关联:给 header(当前 <h2
class="accordion-header">)加一个稳定 id(比如 panelsStayOpen-headingNvOptimize),在触发按钮(带
data-bs-target="#panelsStayOpen-collapseNvOptimize")上添加
aria-controls="panelsStayOpen-collapseNvOptimize" 并确保有 aria-expanded
绑定,且在折叠内容容器(id="panelsStayOpen-collapseNvOptimize")上添加
aria-labelledby="panelsStayOpen-headingNvOptimize";这样 button 与 collapse 通过 id
相互引用,便于屏幕阅读器识别。

In `@src/config.cpp`:
- Around line 1138-1145: The nvenc_frl_fps_override value is currently read via
int_f(vars, "nvenc_frl_fps_override", video.nv_frl_fps_override) and can be
negative; clamp negative values to 0 immediately after that call (e.g. if
(video.nv_frl_fps_override < 0) video.nv_frl_fps_override = 0) so no negative
sentinel propagates down into the encoder/driver paths; update the config
parsing in src/config.cpp around the int_f invocation for nv_frl_fps_override to
perform this normalization.

In `@src/platform/windows/nvprefs/driver_settings.cpp`:
- Around line 527-577: The code creates a profile/application
(NvAPI_DRS_CreateProfile / NvAPI_DRS_CreateApplication) but only populates
pending/undo_out later, so if a later write or a concurrent call (e.g.
check_and_modify_base_extras() / apply_stream_optimizations() which may call
save_settings()) persists the session, the created profile/app won't be
undoable; fix by populating the undo record immediately after any successful
side-effect: as soon as NvAPI_DRS_CreateProfile returns OK (and likewise after
NvAPI_DRS_CreateApplication) fill pending.profile_name, pending.exe_path,
pending.profile_was_created and pending.application_was_added and assign
undo_out = pending (or call the existing rollback helper) so the undo state
exists before calling apply_desired_to_profile; alternatively, if you prefer not
to set undo_out early, perform an immediate rollback (delete
profile/application) on any subsequent failure before returning false.

In `@src/platform/windows/nvprefs/nvprefs_interface.cpp`:
- Around line 254-337: Destructor currently calls restore_global_profile() which
deletes the shared undo file and thus can remove game_profile/base_extras undo
data; change the teardown to either call
nvprefs_interface::restore_stream_optimizations() (so full undo is applied and
the shared undo file is trimmed/deleted correctly) or modify
restore_global_profile() to only clear the global-specific fields in
pimpl->undo_data and update/write the undo file instead of deleting it; ensure
you update/delete pimpl->undo_file only when undo_data is empty and always call
pimpl->driver_settings.save_settings() after restoring/trimming so platform
state is consistent.

---

Outside diff comments:
In `@src/platform/windows/nvprefs/undo_data.cpp`:
- Around line 226-238: merge currently treats a missing optional the same as
"no-op", so explicit clears in newer_data are ignored; update undo_data_t::merge
to detect explicit deletions and call the corresponding clear_* methods instead
of only overwriting when get_* returns a value. Concretely, add or use explicit
presence/cleared indicators (e.g. is_game_profile_cleared/is_game_profile_set or
a three-state getter) and change merge to: if newer_data indicates "cleared"
call clear_game_profile(), else if newer_data provides a value call
set_game_profile(*game); do the same for get_base_extras/set_base_extras and for
get_opengl_swapchain (call set_opengl_swapchain or a clear_opengl_swapchain when
appropriate) so explicit deletes in newer_data remove previously written
branches.

In `@src/stream.cpp`:
- Around line 1459-1518: Replace all unaligned reinterpret_cast reads from
payload.data() with safe memcpy-based deserialization and explicit byte-order
handling: read the initial parameter type into a std::uint32_t via std::memcpy
and convert to int for param_type (used where param_type is currently computed),
read width/height into uint32_t/int values via std::memcpy before calling
handle_resolution_change, read the float FPS value into a float via std::memcpy
before validating/assigning session->config.monitor.framerate and building
video::dynamic_param_t, and read other integer params (param_value) via memcpy;
ensure you apply the appropriate endianness conversion (e.g. boost::endian
helpers or ntohl/ntohf equivalent) for each field.

---

Duplicate comments:
In `@src/platform/windows/misc.cpp`:
- Around line 1398-1415: The code currently constructs std::filesystem::path
from a narrow UTF-8 std::string (token) which on Windows is interpreted using
the ANSI code page; instead convert token from UTF-8 to a wide string and build
the path from that wide string. In function extract_exe_basename_w, after
extracting token, convert token to std::wstring using a UTF-8→UTF-16 conversion
(e.g. MultiByteToWideChar with CP_UTF8 or a trusted UTF-8 conversion helper) and
then call std::filesystem::path(wide_token).filename().wstring(), keep the
existing lowercasing on the returned std::wstring, and preserve the early-empty
checks and quoting logic. Ensure the conversion handles errors/empty results
consistently.

---

Nitpick comments:
In `@src/platform/windows/nvprefs/driver_settings.h`:
- Around line 73-79: Doc param name mismatches the function signature: change
the Doxygen `@param` from "undo_data" to "undo_out" in the comment for
check_and_modify_game_profile so the documented parameter matches the actual
parameter undo_out; update the comment text if needed to reflect that undo_out
is an output parameter containing the undo data (reference: function
check_and_modify_game_profile(const std::wstring &exe_name, int client_fps,
std::optional<undo_data_t::data_t::game_profile_t> &undo_out)).
🪄 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: a1951689-95ce-4b7f-8a89-aac176cf5208

📥 Commits

Reviewing files that changed from the base of the PR and between 01f72a726bac6ad0c428bc8b8f9ca2ba333c090e and ead12a90bf665510da570f34ebfc6d92d1a240b9.

📒 Files selected for processing (19)
  • src/config.cpp
  • src/config.h
  • src/platform/common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/stream.cpp
  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/public/assets/locale/zh.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/config.h
  • src_assets/common/assets/web/composables/useConfig.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Windows
🧰 Additional context used
📓 Path-based instructions (3)
src_assets/**/*.{vue,js,html}

⚙️ CodeRabbit configuration file

src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

Files:

  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/config.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/stream.cpp
src/platform/**

⚙️ CodeRabbit configuration file

src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

Files:

  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/undo_data.cpp

Comment thread src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue Outdated
Comment thread src/config.cpp Outdated
Comment thread src/platform/windows/nvprefs/driver_settings.cpp Outdated
Comment thread src/platform/windows/nvprefs/nvprefs_interface.cpp
@qiin2333
qiin2333 force-pushed the feat/nvapi-stream-optimize branch from ead12a9 to 8aedafd Compare May 6, 2026 09:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/config.cpp`:
- Around line 1141-1142: The config parsing currently trusts values set by int_f
for nvenc_frl_fps_offset and nvenc_frl_fps_override (video.nv_frl_fps_offset /
video.nv_frl_fps_override); clamp these immediately after parsing to the UI-safe
ranges (offset -> [-30, 30], override -> [0, 500]) to avoid signed overflow or
out-of-UI values, and emit a warning when a value is adjusted; update the code
around the int_f(...) calls to perform the clamp and call the existing
config/log warning helper (use the project's warning/log function) mentioning
the key name and the clamped value.

In `@src/platform/windows/nvprefs/nvprefs_interface.cpp`:
- Around line 307-334: The undo trimming and clears are happening even when
pimpl->driver_settings.save_settings() fails; move the calls that clear undo
state (pimpl->undo_data->clear_game_profile(),
pimpl->undo_data->clear_base_extras()) and the logic that deletes or rewrites
the undo file (pimpl->undo_file->delete_file(),
pimpl->undo_file->write_undo_data()) so they only run after save_settings()
returns true; keep the restore_* calls (restore_game_profile_to_undo,
restore_base_extras_to_undo) where they are, and on save_settings() failure do
not reset or delete undo_data/undo_file so crash-recovery can retry. Ensure
error_message calls remain for save_settings/delete_file/write_undo_data
failures.
🪄 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: 9fb46eaa-ce53-4a85-9ab9-818ca9896f7b

📥 Commits

Reviewing files that changed from the base of the PR and between ead12a90bf665510da570f34ebfc6d92d1a240b9 and 8aedafd4dac3eabf3f441526ae54002e0550df20.

📒 Files selected for processing (20)
  • src/config.cpp
  • src/config.h
  • src/platform/common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/stream.cpp
  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/public/assets/locale/zh.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/composables/useConfig.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
src/platform/**

⚙️ CodeRabbit configuration file

src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

Files:

  • src/platform/macos/misc.mm
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/common.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
src_assets/**/*.{vue,js,html}

⚙️ CodeRabbit configuration file

src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

Files:

  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/common.h
  • src/config.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/config.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/stream.cpp
🔇 Additional comments (11)
src/platform/windows/nvprefs/nvprefs_common.h (1)

61-63: ⚡ Quick win

FRL 下限保护已在 compute_frl_fps() 中实现,无需修改。

nvprefs_common.h 中的注释"clamped >= 1"是准确的。driver_settings.cpp 的 compute_frl_fps() 函数(第 ~331 行)已包含 if (v < 1) v = 1; 的下限保护,确保向驱动发送的 FRL 值始终 >= 1。同时 nv_frl_fps_override 也仅在 > 0 时才使用,无效值不会被应用。

src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue (1)

198-205: 给新折叠面板补齐 ARIA 关联。

Line 198-205 这组 accordion 仍然缺少稳定的 id / aria-controls / aria-labelledby 关联,屏幕阅读器无法把触发按钮和折叠内容正确配对。

As per coding guidelines, src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

src/platform/windows/misc.cpp (1)

1411-1423: 这里仍在用窄字符串路径解析 UTF-8 命令。

Line 1411-1423 先把 UTF-8 cmd 切成 std::string token,再直接传给 std::filesystem::path(token)。在 Windows 上这会按系统代码页而不是 UTF-8 解码,游戏路径里只要有中文/日文等非 ASCII 字符,提取出来的 basename 就可能损坏,后面的应用配置查找会 miss。这里应先 from_utf8() 再取 filename()

src/platform/windows/nvprefs/nvprefs_interface.cpp (1)

255-337: 共享 undo 清单已经承载 stream 项,但 teardown 仍只回滚全局项。

Line 255-337 这里把 game_profile / base_extras 合并进同一份 undo 清单后,析构路径仍然只走 restore_global_profile()。对象在持有 undo 文件时析构,会把整份文件删掉,而 stream-time 变更还没恢复,下一次启动就拿不到 crash recovery 信息了。

As per coding guidelines, src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

src/platform/windows/nvprefs/driver_settings.cpp (3)

527-577: 先建 profile/application,后记 undo,会让失败路径不可回滚。

Line 527-577 在 pending 生成之前就可能已经成功执行 NvAPI_DRS_CreateProfile() / NvAPI_DRS_CreateApplication()。如果后面某一步失败,而同一 session 的其他改动又被 save_settings() 持久化,这里新建的 profile/application 就会残留,但 undo_out 还是空的。请在第一次产生副作用后立即填充 pending/undo_out,或者在失败时就地回滚当前 session。

As per coding guidelines, src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。


567-610: 这里的 wstring/string 互转仍然是有损的。

Line 567-569、594-610 这些基于迭代器的拷贝会直接截断非 ASCII 字符。undo 文件里只要出现中文/日文 profile 名或 exe 名,恢复时就可能找不到对应的 profile/application。这里应统一改成 platf::to_utf8() / platf::from_utf8()


619-714: 还原阶段不要在第一个 setting 失败时就提前退出。

Line 619-714 当前任一 restore_uint_setting() 失败都会立刻 return false。game-profile 路径下这会把后续 setting 的恢复以及 NvAPI_DRS_DeleteApplication() / NvAPI_DRS_DeleteProfile() 清理一起跳过;BASE 路径也会停在半恢复状态。这里应该累计失败但继续执行剩余 restore/cleanup,最后再返回汇总结果。

As per coding guidelines, src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

src/platform/windows/nvprefs/undo_data.cpp (2)

50-152: ADL 序列化扩展实现稳健,向后兼容处理得当。

data_t::from_jsoncontains() 守卫新增的 game_profile / base_extras,旧 undo 文件能继续解析;game_profile_t::from_json 内对可选项(vsync / frl / pstate / prerender)也做了 contains() 检查,必填项缺失时由 undo_data_t::read() 的 try/catch 统一兜底,行为可预期。std::optional<T> 的现有 ADL 特化链路自然支持新增子类型,整体设计保持与 opengl_swapchain 一致。


170-238: 新增 API 与 merge 行为与既有模式一致,LGTM。

set_game_profile / get_game_profile / clear_game_profile(及对应的 base_extras 版本)与现有 opengl_swapchain 接口风格统一;merge 采用"newer 存在则覆写、否则保留"的语义,与原有 opengl_swapchain 的合并行为对称。结合 clear_* 提供显式清除入口,调用方可按需控制。

src/stream.cpp (2)

3026-3032: 生命周期顺序对称,restore 调用位置合理。

start 路径上 streaming_will_start()apply_stream_optimizations(),stop 路径上 restore_stream_optimizations()streaming_will_stop(),构成 LIFO 配对;即使本次会话中 apply 实际未写入任何撤销项(master switch 关闭、非 NVIDIA 主机等),restore 依据 undo 文件自身内容静默处理,外层无需额外条件分支。


3128-3136: ⚡ Quick win

The codebase handles both empty and parameterized game_cmd correctly:

  • Empty command: When app_id == 0, game_cmd remains empty and is explicitly designed to skip the per-game profile leg silently (documented in nvprefs_interface.h:45-46 and platform/common.h:753-754).
  • Parameterized command: The Windows implementation calls extract_exe_basename_w(game_cmd) in misc.cpp:1432 to extract the executable basename from the full command line before passing to the nvprefs interface.
  • Restoration path: The restore logic in driver_settings.cpp:595-597 explicitly validates empty exe_path and no-ops safely with a log message.

No robustness issues found. The platform layer is correctly designed to handle both cases.

Comment thread src/config.cpp Outdated
Comment thread src/platform/windows/nvprefs/nvprefs_interface.cpp Outdated
@qiin2333
qiin2333 force-pushed the feat/nvapi-stream-optimize branch 3 times, most recently from 140159a to ef92775 Compare May 6, 2026 11:12

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/stream.cpp (1)

1500-1526: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

动态 FPS 变更不会同步刷新 NVIDIA FRL 上限。

apply_stream_optimizationssession::start 里以 session.config.monitor.framerate(初始值)作为 FRL 依据写入驱动 profile(driver_settings.h 注释:client_fps … used to derive the FRL value)。当客户端通过 IDX_DYNAMIC_PARAM_CHANGE/FPS 把帧率改成例如 60→144 后,这里只更新了 session->config.monitor.framerate 与编码侧事件,但驱动端的 FRL 仍按旧帧率封顶,会反过来限制实际输出,与“串流期间动态 FPS”预期相悖。

建议要么在 FPS 变更分支里再次调用 apply_stream_optimizations 重新写 FRL,要么在文档/UI 中明确该优化只对会话启动时的 FPS 生效。

🤖 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/stream.cpp` around lines 1500 - 1526, Dynamic FPS changes via
IDX_DYNAMIC_PARAM_CHANGE (video::dynamic_param_type_e::FPS) only update
session->config.monitor.framerate and raise dynamic_param_change_events, but do
not re-apply driver FRL limits (client_fps used in driver_settings.h /
apply_stream_optimizations), causing the driver to remain capped at the original
FRL; fix by invoking apply_stream_optimizations (or the specific driver profile
update routine used in session::start) after updating
session->config.monitor.framerate so the new_fps is written to the driver
profile/FRL, ensuring the encoder/driver limits are updated to match the dynamic
FPS change.
♻️ Duplicate comments (1)
src/config.cpp (1)

1141-1142: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

请在配置解析处钳制 FRL 数值范围,避免异常值下传。

Line 1141 和 Line 1142 现在接受任意整数。手工配置负值/超大值会把越界参数继续传到后续驱动配置路径,增加异常配置与算术边界风险。建议在解析后立即按 UI 约束做钳制并打印 warning(offset: [-30, 30],override: [0, 500])。

🔧 建议修改
     int_f(vars, "nvenc_frl_fps_offset", video.nv_frl_fps_offset);
     int_f(vars, "nvenc_frl_fps_override", video.nv_frl_fps_override);
+    if (video.nv_frl_fps_offset < -30 || video.nv_frl_fps_offset > 30) {
+      BOOST_LOG(warning) << "Invalid nvenc_frl_fps_offset: ["sv << video.nv_frl_fps_offset << "], clamping to [-30, 30]"sv;
+      video.nv_frl_fps_offset = std::clamp(video.nv_frl_fps_offset, -30, 30);
+    }
+    if (video.nv_frl_fps_override < 0 || video.nv_frl_fps_override > 500) {
+      BOOST_LOG(warning) << "Invalid nvenc_frl_fps_override: ["sv << video.nv_frl_fps_override << "], clamping to [0, 500]"sv;
+      video.nv_frl_fps_override = std::clamp(video.nv_frl_fps_override, 0, 500);
+    }
🤖 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/config.cpp` around lines 1141 - 1142, nvenc FRL
参数在解析后未钳制,会把任意整数传到后续驱动路径;在解析完 int_f(vars, "nvenc_frl_fps_offset",
video.nv_frl_fps_offset) 和 int_f(vars, "nvenc_frl_fps_override",
video.nv_frl_fps_override) 后,立即对 video.nv_frl_fps_offset 做范围钳制到 [-30, 30],对
video.nv_frl_fps_override 做范围钳制到 [0, 500],并在发生钳制时输出一条
warning(包含原始值与被钳制后的值及字段名),以便定位配置异常。 Ensure this runs in the same
parsing/initialization scope where int_f is called so downstream code always
sees the clamped values.
🧹 Nitpick comments (1)
src/stream.cpp (1)

1543-1556: 💤 Low value

validate_and_raisebool 分支为不可达分支。

auto value 全部由 param_valueint)传入,decltype(value) 永远是 intif constexpr (std::is_same_v<decltype(value), bool>) 这一支永远不会被实例化使用,徒增阅读负担;同时第 1554 行失败日志固定打印 param_value,若以后真的传 bool 也会与 value 不一致。可以直接删掉 bool 分支保留 int_value 赋值,或者把日志改成打印 value

🤖 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/stream.cpp` around lines 1543 - 1556, The lambda validate_and_raise has
an unreachable bool branch; remove the constexpr bool branch and always assign
param.value.int_value = value, keep the call to
session->video.dynamic_param_change_events->raise(param) and the info log but
update both BOOST_LOG(warning) and BOOST_LOG(info) to print the actual variable
value (value) rather than param_value so logs stay consistent; ensure references
to param.value.bool_value are removed and only param.value.int_value is used in
validate_and_raise.
🤖 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_assets/common/assets/web/public/assets/locale/en.json`:
- Line 390: The string value for key "nvenc_lock_frame_rate_desc" contains the
awkward phrase "at exactly = refresh"; update that JSON entry to use natural
English (for example replace with "at exactly the refresh rate") and adjust the
sentence accordingly so it reads smoothly — e.g., "Use the driver's frame rate
limiter to cap the game slightly below the client refresh rate. Keeping in-game
FPS strictly below the streaming display's refresh rate avoids the high PCL
latency that occurs at exactly the refresh rate, and prevents stutter from going
above it." Ensure only the value for nvenc_lock_frame_rate_desc is changed and
the JSON remains valid.

In `@src/platform/windows/nvprefs/driver_settings.cpp`:
- Around line 603-652: The code currently uses the profile_handle from
NvAPI_DRS_FindApplicationByName (current owner) for both restoring settings and
for deleting the application/profile, which can delete a user’s unrelated
profile; keep using profile_handle for restore_uint_setting calls but when you
reach the deletion blocks use the original profile name stored in
undo_data.profile_name: call NvAPI_DRS_FindProfileByName(session_handle,
profile_name, &original_profile_handle) (where profile_name is filled from
undo_data.profile_name) and then call
NvAPI_DRS_DeleteApplication(session_handle, original_profile_handle, app_name)
and NvAPI_DRS_GetProfileInfo(session_handle, original_profile_handle, &info) /
NvAPI_DRS_DeleteProfile(session_handle, original_profile_handle) so you only
delete the profile that Sunshine created; preserve existing NVAPI_OK /
NVAPI_EXECUTABLE_NOT_FOUND checks and error logging.
- Around line 518-560: The handlers around NvAPI_DRS_FindApplicationByName,
NvAPI_DRS_FindProfileByName and NvAPI_DRS_GetApplicationInfo currently treat any
non-NVAPI_OK as "not found" and proceed to create profiles/applications; change
each to explicitly check for the API's "not found" status codes (e.g.
NVAPI_EXECUTABLE_NOT_FOUND, NVAPI_SETTING_NOT_FOUND or other documented
not-found codes) in an else if branch to trigger the creation logic, and add a
final else that logs nvapi_error_message(status) and returns false for all other
error codes; update the logic around NvAPI_DRS_FindApplicationByName,
NvAPI_DRS_FindProfileByName and NvAPI_DRS_GetApplicationInfo accordingly and
ensure profile_was_created/profile_name_used handling remains correct.

In `@src/platform/windows/nvprefs/nvprefs_interface.cpp`:
- Around line 83-95: The code currently deletes the undo file unconditionally;
change the logic in the block that calls
pimpl->driver_settings.restore_global_profile_to_undo,
restore_game_profile_to_undo, restore_base_extras_to_undo and save_settings so
the undo file is deleted only when the full restore succeeded (ok &&
pimpl->driver_settings.save_settings()); on any failure keep the undo file, emit
an appropriate error_message (including context) and return/propagate a failure
status to the caller so the caller can retry; locate the logic around the calls
to
restore_global_profile_to_undo/restore_game_profile_to_undo/restore_base_extras_to_undo/save_settings
and update the file-deletion path and error handling accordingly.

---

Outside diff comments:
In `@src/stream.cpp`:
- Around line 1500-1526: Dynamic FPS changes via IDX_DYNAMIC_PARAM_CHANGE
(video::dynamic_param_type_e::FPS) only update session->config.monitor.framerate
and raise dynamic_param_change_events, but do not re-apply driver FRL limits
(client_fps used in driver_settings.h / apply_stream_optimizations), causing the
driver to remain capped at the original FRL; fix by invoking
apply_stream_optimizations (or the specific driver profile update routine used
in session::start) after updating session->config.monitor.framerate so the
new_fps is written to the driver profile/FRL, ensuring the encoder/driver limits
are updated to match the dynamic FPS change.

---

Duplicate comments:
In `@src/config.cpp`:
- Around line 1141-1142: nvenc FRL 参数在解析后未钳制,会把任意整数传到后续驱动路径;在解析完 int_f(vars,
"nvenc_frl_fps_offset", video.nv_frl_fps_offset) 和 int_f(vars,
"nvenc_frl_fps_override", video.nv_frl_fps_override) 后,立即对
video.nv_frl_fps_offset 做范围钳制到 [-30, 30],对 video.nv_frl_fps_override 做范围钳制到 [0,
500],并在发生钳制时输出一条 warning(包含原始值与被钳制后的值及字段名),以便定位配置异常。 Ensure this runs in the
same parsing/initialization scope where int_f is called so downstream code
always sees the clamped values.

---

Nitpick comments:
In `@src/stream.cpp`:
- Around line 1543-1556: The lambda validate_and_raise has an unreachable bool
branch; remove the constexpr bool branch and always assign param.value.int_value
= value, keep the call to
session->video.dynamic_param_change_events->raise(param) and the info log but
update both BOOST_LOG(warning) and BOOST_LOG(info) to print the actual variable
value (value) rather than param_value so logs stay consistent; ensure references
to param.value.bool_value are removed and only param.value.int_value is used in
validate_and_raise.
🪄 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: 4201fb8f-b1f2-4e62-849a-d7fe16d4208e

📥 Commits

Reviewing files that changed from the base of the PR and between 8aedafd4dac3eabf3f441526ae54002e0550df20 and 45b2b0b9e0a9c39bbea609c06521710bbf42639f.

📒 Files selected for processing (20)
  • src/config.cpp
  • src/config.h
  • src/platform/common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/stream.cpp
  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/public/assets/locale/zh.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Windows
🧰 Additional context used
📓 Path-based instructions (3)
src_assets/**/*.{vue,js,html}

⚙️ CodeRabbit configuration file

src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

Files:

  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/driver_settings.h
  • src/config.h
  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/config.cpp
  • src/stream.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
src/platform/**

⚙️ CodeRabbit configuration file

src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

Files:

  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
🔇 Additional comments (13)
src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp (1)

139-157: 新增的 NvAPI DRS 封装接口实现方式一致且稳妥。

这几处转发与现有封装保持同一模式,错误处理路径也复用统一逻辑,便于维护。

src/config.h (1)

42-54: 新增配置字段定义清晰,语义完整。

字段命名、默认语义注释和回滚说明都比较明确,便于后续配置解析与 UI 映射。

src/platform/windows/nvprefs/nvprefs_common.h (1)

56-71: nvprefs_options 扩展设计合理,注释可读性高。

新增字段与业务目标对齐,默认值和行为说明也足够明确。

src/platform/linux/misc.cpp (1)

318-326: Linux 侧 no-op 钩子补齐得当。

接口对齐跨平台调用点,同时保持当前平台行为稳定,不会引入副作用。

src/platform/windows/nvprefs/driver_settings.h (1)

64-105: 接口声明清晰,文档充分。

新增的四个方法(check_and_modify_game_profile / restore_game_profile_to_undo / check_and_modify_base_extras / restore_base_extras_to_undo)成对出现且 Doxygen 注释完整地说明了 undo 语义、输入/输出参数与失败行为,与 check_and_modify_global_profile 已有风格一致,便于维护。

src/platform/windows/nvprefs/undo_data.cpp (3)

46-68: data_t 序列化扩展向后兼容性处理得当。

to_json 始终写入三个键(opengl_swapchain / game_profile / base_extras),且依赖前面已有的 adl_serializer<std::optional<T>>nullopt 序列化为 JSON nullfrom_json 对新加字段使用 j.contains(...) 先做存在性检查,确保旧版本 undo 文件(仅含 opengl_swapchain)仍可被解析,符合 PR 中“向后兼容”的设计目标。


104-152: game_profile_t / base_extras_t 序列化器实现一致且对未来扩展友好。

对四个可选设置(vsync/frl/pstate/prerender)都使用 if (j.contains(...)) 守护读取,使得后续新增字段或读取旧记录都不会抛 out_of_rangeprofile_was_created / application_was_added 这类必填字段则直接 get_to,语义合理。整体与 opengl_swapchain 的处理风格一致。


226-239: merge 正确扩展了新字段的合并语义。

合并逻辑沿用 opengl_swapchain 的“仅当较新数据存在时覆盖”策略,与 nvprefs_undo.json 跨会话合并、崩溃后回放的整体流程一致。建议在后续若再增字段时保持同一模式。

src/stream.cpp (3)

1459-1474: read_le_u32 / read_le_f32 解决对齐问题,写法稳健。

通过 std::memcpy + boost::endian::little_to_native 既避免了 ARM/PowerPC 上的非对齐访问 UB,也明确了线缆字节序为小端;read_le_f32 通过 uint32_t 中转再 memcpyfloat 也比 reinterpret_cast/*(float*) 更安全。注释把动机讲清楚了,建议保留。


3022-3050: 最后一个非仅控制流会话结束时的恢复顺序合理。

--running_non_control_only_sessions == 0 分支中先 restore_stream_optimizations()streaming_will_stop(),与 start 一侧 streaming_will_start()apply_stream_optimizations() 的入栈/出栈顺序对称;并且本路径已被 join 包裹的 10s 强杀任务覆盖,崩溃时也能依赖 nvprefs_undo.json 在下次启动回放,整体安全网较完整。

需要注意的一个已知行为:apply 仅在“首个非控制流会话”触发,restore 仅在“最后一个”触发——若中途有多 session 同时串流不同游戏,只会对第一个 game_cmd 写 profile,其他游戏不会获得优化;这与 PR 描述一致,但建议在用户文档里点明。


3145-3154: ⚡ Quick win

已在 Windows 平台层正确处理 game_cmd 的解析,无需修改。

所有提出的疑虑已在实现中得到妥善处理:

  1. 引号与参数剥离extract_exe_basename_w() (misc.cpp:1414-1436) 显式处理带引号的路径,使用 cmd.find('"', 1) 剥离引号,未引号路径则截断于首个空格/制表符,文档示例明确:"\"C:\\Games\\foo\\bar.exe\" --opt"L"bar.exe"

  2. Basename 提取与小写转换:使用 std::filesystem::path::filename() 提取文件名,再通过 towlower() 完成小写转换,符合 NvAPI 预期

  3. 空字符串处理:当 proc::proc.running() 返回 0 时,game_cmd 为空,extract_exe_basename_w() 在第 1415 行直接返回空 wstring,后续 driver_settings.cpp:494-496 明确检查 exe_name.empty() 并作为 no-op 返回 true,符合 nvprefs_interface.h:46 的文档说明

src/platform/windows/nvprefs/undo_data.h (2)

23-61: 新增类型设计良好,注释清晰。

setting_undo_tour_value/undo_value 二元组、game_profile_tprofile_was_created/application_was_added 默认初始化为 false,以及 base_extras_tgame_profile_t 的字段命名一致(vsync/frl/pstate/prerender),都让 restore_*_to_undo 实现可以采用统一模式。undo_value == nullopt → 还原即删除这一约定通过头注释表达,避免了语义歧义。


70-86: accessor API 与现有 opengl_swapchain 风格一致。

set/get/clear 三件套与已有 set_opengl_swapchain/get_opengl_swapchain 配套,便于 nvprefs_interface 在合并/写盘时统一处理;set_game_profile/set_base_extras 接收 const 引用、get_* 返回 std::optional<...> 的副本也避免了悬挂引用问题。

Comment thread src_assets/common/assets/web/public/assets/locale/en.json Outdated
Comment thread src/platform/windows/nvprefs/driver_settings.cpp Outdated
Comment thread src/platform/windows/nvprefs/driver_settings.cpp
Comment thread src/platform/windows/nvprefs/nvprefs_interface.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (1)
src/platform/windows/nvprefs/undo_data.cpp (1)

86-152: 💤 Low value

新 ADL serializer 实现正确,但 game_profile_t::from_json 对必填字段无兜底。

game_profile_t::from_jsonprofile_name / exe_path / profile_was_created / application_was_added 全部走 j.at(...).get_to(...),任一缺失即抛异常。当前由 to_json 保证这些字段总会写出,所以正常路径没问题;不过如果以后被人手改 nvprefs_undo.json,或部分写入后掉电,这一异常会冒到 read() 的 catch 把整个 data 清空,连带 opengl_swapchain 的撤销信息也丢失。可考虑沿用 base_extras_t::from_jsonj.contains 风格,对每个字段加一层 contains,缺失就走默认值,让恢复链路对部分损坏更鲁棒。

🤖 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/platform/windows/nvprefs/undo_data.cpp` around lines 86 - 152,
game_profile_t::from_json currently uses j.at(...).get_to(...) for profile_name,
exe_path, profile_was_created and application_was_added which will throw on
missing keys; change it to follow base_extras_t::from_json style by checking
j.contains("...") before calling j.at(...).get_to(...) so absent fields keep
their defaults instead of throwing and wiping data; update
game_profile_t::from_json only (leave to_json unchanged) and ensure the four
named fields are handled with contains checks.
🤖 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/platform/windows/nvprefs/driver_settings.cpp`:
- Around line 636-656: The cleanup currently logs failures from
NvAPI_DRS_DeleteApplication and NvAPI_DRS_DeleteProfile but still treats the
overall undo as successful, which causes restore_stream_optimizations() to drop
the undo; change the logic so that any non-OK return from
NvAPI_DRS_DeleteApplication (except NVAPI_EXECUTABLE_NOT_FOUND if that is
acceptable) or from NvAPI_DRS_DeleteProfile sets the function's overall result
to failure (e.g., return false or set ok=false) so the undo remains available
for retry; locate the checks around undo_data.application_was_added,
NvAPI_DRS_DeleteApplication, undo_data.profile_was_created,
NvAPI_DRS_GetProfileInfo and NvAPI_DRS_DeleteProfile and ensure they propagate
error status instead of only logging it.

In `@src/platform/windows/nvprefs/nvprefs_interface.cpp`:
- Around line 221-239: After restore_global_profile_to_undo succeeds but before
calling pimpl->undo_file->write_undo_data(*pimpl->undo_data), remove the
restored global-profile undo branch from pimpl->undo_data so the in-memory
manifest is trimmed; if that removal makes the manifest empty then call
pimpl->undo_file->delete_file(), clear pimpl->undo_data and pimpl->undo_file
(std::nullopt) and return appropriately instead of writing, otherwise proceed to
write the trimmed manifest via write_undo_data and handle any write error as
already done; use the existing symbols restore_global_profile_to_undo,
pimpl->undo_data, pimpl->undo_file, write_undo_data and delete_file to locate
the change.

---

Nitpick comments:
In `@src/platform/windows/nvprefs/undo_data.cpp`:
- Around line 86-152: game_profile_t::from_json currently uses
j.at(...).get_to(...) for profile_name, exe_path, profile_was_created and
application_was_added which will throw on missing keys; change it to follow
base_extras_t::from_json style by checking j.contains("...") before calling
j.at(...).get_to(...) so absent fields keep their defaults instead of throwing
and wiping data; update game_profile_t::from_json only (leave to_json unchanged)
and ensure the four named fields are handled with contains checks.
🪄 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: 6b40482e-4561-4f96-8fc0-8351e264391c

📥 Commits

Reviewing files that changed from the base of the PR and between 45b2b0b9e0a9c39bbea609c06521710bbf42639f and ef92775.

📒 Files selected for processing (20)
  • src/config.cpp
  • src/config.h
  • src/platform/common.h
  • src/platform/linux/misc.cpp
  • src/platform/macos/misc.mm
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/windows/nvprefs/undo_data.h
  • src/stream.cpp
  • src_assets/common/assets/web/composables/useConfig.js
  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/public/assets/locale/en.json
  • src_assets/common/assets/web/public/assets/locale/zh.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/platform/macos/misc.mm
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Windows
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{cpp,c,h}

⚙️ CodeRabbit configuration file

src/**/*.{cpp,c,h}: Sunshine 核心 C++ 源码,自托管游戏串流服务器。审查要点:内存安全、 线程安全、RAII 资源管理、安全漏洞。注意预处理宏控制的平台相关代码。

Files:

  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/linux/misc.cpp
  • src/config.h
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/config.cpp
  • src/stream.cpp
  • src/platform/windows/nvprefs/undo_data.h
src/platform/**

⚙️ CodeRabbit configuration file

src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

Files:

  • src/platform/common.h
  • src/platform/windows/nvprefs/nvprefs_interface.h
  • src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp
  • src/platform/windows/nvprefs/nvprefs_common.h
  • src/platform/windows/nvprefs/undo_data.cpp
  • src/platform/linux/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_common.cpp
  • src/platform/windows/misc.cpp
  • src/platform/windows/nvprefs/nvprefs_interface.cpp
  • src/platform/windows/nvprefs/driver_settings.h
  • src/platform/windows/nvprefs/driver_settings.cpp
  • src/platform/windows/nvprefs/undo_data.h
src_assets/**/*.{vue,js,html}

⚙️ CodeRabbit configuration file

src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

Files:

  • src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue
  • src_assets/common/assets/web/composables/useConfig.js
🔇 Additional comments (16)
src/config.cpp (2)

1138-1156: FRL 相关 clamp 已落实,吸收了前次审查关于负值 / 越界的反馈。

nv_frl_fps_offset 限定在 [-30, 30]nv_frl_fps_override 限定在 [0, 500],越界都会打 warning 日志再 clamp,正好与 UI slider 范围对齐,也避免了 client_fps + offset 之后被传到 NvAPI 路径上发生有符号溢出 / 非法 FRL 值。已对应历史反馈,无需新动作。


408-415: 默认值与字段顺序匹配 config.h,含义与注释一致。

nv_optimize_game = false(总开关默认关闭)、nv_apply_to_base_profile = false(避免无意中写全局 BASE 配置文件)符合 PR 中"opt-in、非 NVIDIA 系统静默 no-op"的安全策略;nv_frl_fps_offset = -2 为 FRL 留出 2fps 余量也符合实际串流体验。该聚合初始化器的字段顺序与 video_t 中插入位置(nv_sunshine_high_power_mode 之后、vdd_keep_enabled 之前)一致。

src/platform/common.h (1)

745-766: 接口声明清晰,文档完备。

apply_stream_optimizations/restore_stream_optimizations 的位置紧邻现有 streaming_will_start/streaming_will_stop,行为契约(NVIDIA-only、空字符串允许、无 #ifdef)以及 client_fps 用途都在 doxygen 中讲清楚。后续平台实现按此契约即可。

src/platform/windows/nvprefs/nvapi_opensource_wrapper.cpp (1)

138-157: 新增 NvAPI 包装函数与既有模式一致。

四个新 NvAPI_DRS_* 包装严格沿用 call_interface<decltype(...)>(name, args...) 的调度方式,未引入新的资源/线程语义,正常通过 nvapi_QueryInterface 表查找;与 NvAPI_DRS_GetBaseProfile 等老 wrapper 风格一致。

src/platform/windows/nvprefs/undo_data.cpp (1)

50-66: JSON schema 扩展处理向后兼容到位。

to_json 一并写入 opengl_swapchain / game_profile / base_extras(即便是 nullopt 也通过 adl_serializer<std::optional<T>> 序列化为 null),from_json 对新字段使用 j.contains 做兜底——读旧版崩溃残留的 undo 文件不会抛异常;写新版时三段字段始终齐全,未来版本读取也安全。

src/platform/windows/nvprefs/undo_data.h (1)

23-86: 类型与访问器设计对称、文档齐全。

setting_undo_t / game_profile_t / base_extras_t 的字段语义(our_value/undo_valuenullopt = 该设置先前不存在 = 恢复时删除)写得很清楚,三组 set/get/clear 也与 opengl_swapchain 既有对称。game_profile_t::profile_was_created / application_was_added 默认 false 也符合"未触动"的安全恢复语义。

src/platform/windows/nvprefs/driver_settings.h (1)

64-105: 接口签名与文档对齐 PR 设计。

四个方法的语义(按 EXE basename 路由、带 client_fps 派生 FRL、显式 out-param 撤销数据、并提示调用方需 merge 之前的 undo 数据)描述清晰;std::wstring 与 NvAPI NvAPI_UnicodeString 也匹配。后续审查 driver_settings.cpp(不在本次改动列表)时再核对实际语义是否与文档一致。

src/config.h (1)

41-54: 字段分组、命名与默认值(在 config.cpp 中)一致,opt-in 定位明确。

nv_optimize_game 作为总开关,且默认 false、与 nv_apply_to_base_profile 同样默认关闭,符合 PR 描述的"非 NVIDIA 系统快速 no-op、机器级写入显式 opt-in"目标。两个 int 字段(nv_frl_fps_offset / nv_frl_fps_override)也对应 config.cpp 中的解析与 clamp 路径。

src/platform/linux/misc.cpp (1)

318-326: ⚡ Quick win

Linux 端 no-op 实现合理。

参数命名留空(const std::string &, int)符合 no-op 语义,注释也明确说明 Linux 暂未提供等价能力。已确认 src/platform/macos/misc.mm 中存在对应的 no-op 实现(lines 247-249、252-254),其中 apply_stream_optimizationsrestore_stream_optimizations 均已实现,无未定义符号风险。

src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue (1)

197-205: 新的折叠面板仍缺少 ARIA 关联。

这个 accordion 的 button 和折叠内容区之间还没有补齐稳定的 header id、aria-controlsaria-labelledby,屏幕阅读器依然无法把触发器和内容区域正确关联起来。

As per coding guidelines, src_assets/**/*.{vue,js,html}: 基于 Vue.js 的 Web 配置面板。审查 XSS/CSRF 安全性、 组件设计、状态管理和可访问性。

src/platform/windows/nvprefs/driver_settings.cpp (1)

592-650: 清理 application/profile 时不要沿用当前 owner 的 profile_handle

这里先跟随 FindApplicationByName() 的当前 owner 来恢复 setting 没问题,但后面的 DeleteApplication() / DeleteProfile() 如果继续使用这个 handle,用户在串流期间把 exe 挪到别的 profile 时,就会误删那个 profile 上的记录,甚至删掉整个用户 profile。清理阶段应回到 undo_data.profile_name 记录的原始 profile 上执行。

As per coding guidelines, src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

src/platform/windows/nvprefs/nvprefs_interface.cpp (1)

85-107: 恢复不完整时不要删除 undo 文件。

现在只要任一 restore 或 save_settings() 失败,代码仍然会继续删除 undo 文件。这样下次启动就无法再重试回滚,用户可能永久保留一部分被 Sunshine 改过的驱动状态。只有完整恢复并成功保存后才应该删文件。

As per coding guidelines, src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。

src_assets/common/assets/web/public/assets/locale/en.json (1)

390-390: 文案语法问题仍存在(历史已提过)。

Line 390 的 at exactly = refresh 依然不自然,建议改为 at exactly the refresh rate

src/platform/windows/nvprefs/nvprefs_common.h (1)

56-71: 新增 NV 优化配置项设计清晰,默认策略稳妥。

Line 59-71 采用“主开关默认关闭、子项给出推荐默认值”的方式,且注释对作用域与回滚时机说明完整,可维护性不错。

src/stream.cpp (2)

1459-1474: 动态参数解析的未对齐读取风险处理得当。

这段改为 memcpy + little_to_native 读取 payload,规避了直接指针转换带来的未对齐访问 UB,跨平台内存安全性更好。

Also applies to: 1494-1496, 1509-1509, 1536-1536


3048-3049: 流开始/结束时的 GPU 优化钩子时机对称。

首个非控制流会话时应用优化、最后一个非控制流会话结束时恢复优化,生命周期闭环完整,行为边界清晰。

Also applies to: 3146-3154

Comment thread src/platform/windows/nvprefs/driver_settings.cpp Outdated
Comment thread src/platform/windows/nvprefs/nvprefs_interface.cpp Outdated
@qiin2333
qiin2333 force-pushed the master branch 2 times, most recently from 4db4aa3 to e5579b9 Compare June 4, 2026 07:31
@qiin2333
qiin2333 force-pushed the feat/nvapi-stream-optimize branch from 3f48cf3 to 2a0b3a9 Compare June 7, 2026 10:21
@qiin2333 qiin2333 changed the title feat: 串流时自动优化 NVIDIA 控制面板(V-Sync/FRL/低延迟) feat(plugins): add lifecycle host and NVIDIA optimizer Jun 7, 2026
@qiin2333 qiin2333 changed the title feat(plugins): add lifecycle host and NVIDIA optimizer feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer Jun 7, 2026
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.

1 participant