feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer - #627
feat(plugins): add lifecycle host, marketplace, and NVIDIA optimizer#627qiin2333 wants to merge 4 commits into
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough在 Windows 上新增按游戏的 NVIDIA 驱动流式优化与撤销(nvprefs)支持,扩展相关配置与 UI;在流处理路径加入平台钩子以应用/恢复优化;同时扩展 undo 数据模型并在流代码中加入麦克风加密生命周期、动态参数(分辨率/FPS 等)处理与会话快照接口;并对 Windows capture_target 做校验与告警。 ChangesNVIDIA 流优化功能
流媒体会话增强与动态参数
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
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
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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.cppsrc/config.hsrc/platform/common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/undo_data.hsrc/stream.cppsrc_assets/common/assets/web/composables/useConfig.jssrc_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vuesrc_assets/common/assets/web/public/assets/locale/en.jsonsrc_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.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/config.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/driver_settings.hsrc/config.cppsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/stream.cpp
src/platform/**
⚙️ CodeRabbit configuration file
src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。
Files:
src/platform/common.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/macos/misc.mmsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/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.jssrc_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_optimizations在streaming_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实现遵守,不存在副作用风险。
01f72a7 to
ead12a9
Compare
There was a problem hiding this comment.
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(¶m_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.cppsrc/config.hsrc/platform/common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/undo_data.hsrc/stream.cppsrc_assets/common/assets/web/composables/useConfig.jssrc_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vuesrc_assets/common/assets/web/public/assets/locale/en.jsonsrc_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.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/common.hsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/config.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/undo_data.cppsrc/stream.cpp
src/platform/**
⚙️ CodeRabbit configuration file
src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。
Files:
src/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/common.hsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/macos/misc.mmsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/undo_data.cpp
ead12a9 to
8aedafd
Compare
There was a problem hiding this comment.
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.cppsrc/config.hsrc/platform/common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/undo_data.hsrc/stream.cppsrc_assets/common/assets/web/composables/useConfig.jssrc_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vuesrc_assets/common/assets/web/public/assets/locale/en.jsonsrc_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.mmsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/common.hsrc/platform/windows/nvprefs/undo_data.cppsrc/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.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/common.hsrc/config.hsrc/platform/windows/nvprefs/undo_data.cppsrc/config.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/stream.cpp
🔇 Additional comments (11)
src/platform/windows/nvprefs/nvprefs_common.h (1)
61-63: ⚡ Quick winFRL 下限保护已在 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_json用contains()守卫新增的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 winThe codebase handles both empty and parameterized
game_cmdcorrectly:
- Empty command: When
app_id == 0,game_cmdremains empty and is explicitly designed to skip the per-game profile leg silently (documented innvprefs_interface.h:45-46andplatform/common.h:753-754).- Parameterized command: The Windows implementation calls
extract_exe_basename_w(game_cmd)inmisc.cpp:1432to 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-597explicitly validates emptyexe_pathand no-ops safely with a log message.No robustness issues found. The platform layer is correctly designed to handle both cases.
140159a to
ef92775
Compare
There was a problem hiding this comment.
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_optimizations在session::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_raise中bool分支为不可达分支。
auto value全部由param_value(int)传入,decltype(value)永远是int,if 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.cppsrc/config.hsrc/platform/common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/undo_data.hsrc/stream.cppsrc_assets/common/assets/web/composables/useConfig.jssrc_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vuesrc_assets/common/assets/web/public/assets/locale/en.jsonsrc_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.jssrc_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.hsrc/platform/windows/nvprefs/driver_settings.hsrc/config.hsrc/platform/common.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/undo_data.cppsrc/config.cppsrc/stream.cppsrc/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.hsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/common.hsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/undo_data.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/undo_data.cppsrc/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序列化为 JSONnull;from_json对新加字段使用j.contains(...)先做存在性检查,确保旧版本 undo 文件(仅含opengl_swapchain)仍可被解析,符合 PR 中“向后兼容”的设计目标。
104-152:game_profile_t/base_extras_t序列化器实现一致且对未来扩展友好。对四个可选设置(vsync/frl/pstate/prerender)都使用
if (j.contains(...))守护读取,使得后续新增字段或读取旧记录都不会抛out_of_range;profile_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中转再memcpy到float也比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的解析,无需修改。所有提出的疑虑已在实现中得到妥善处理:
引号与参数剥离:
extract_exe_basename_w()(misc.cpp:1414-1436) 显式处理带引号的路径,使用cmd.find('"', 1)剥离引号,未引号路径则截断于首个空格/制表符,文档示例明确:"\"C:\\Games\\foo\\bar.exe\" --opt"→L"bar.exe"Basename 提取与小写转换:使用
std::filesystem::path::filename()提取文件名,再通过towlower()完成小写转换,符合 NvAPI 预期空字符串处理:当
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_t的our_value/undo_value二元组、game_profile_t中profile_was_created/application_was_added默认初始化为false,以及base_extras_t与game_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<...>的副本也避免了悬挂引用问题。
There was a problem hiding this comment.
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_json中profile_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_json的j.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.cppsrc/config.hsrc/platform/common.hsrc/platform/linux/misc.cppsrc/platform/macos/misc.mmsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/driver_settings.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/windows/nvprefs/undo_data.hsrc/stream.cppsrc_assets/common/assets/web/composables/useConfig.jssrc_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vuesrc_assets/common/assets/web/public/assets/locale/en.jsonsrc_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.hsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/linux/misc.cppsrc/config.hsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/config.cppsrc/stream.cppsrc/platform/windows/nvprefs/undo_data.h
src/platform/**
⚙️ CodeRabbit configuration file
src/platform/**: 平台抽象层代码(Windows/Linux/macOS)。确保各平台实现一致, 注意 Windows API 调用的错误处理和资源释放。
Files:
src/platform/common.hsrc/platform/windows/nvprefs/nvprefs_interface.hsrc/platform/windows/nvprefs/nvapi_opensource_wrapper.cppsrc/platform/windows/nvprefs/nvprefs_common.hsrc/platform/windows/nvprefs/undo_data.cppsrc/platform/linux/misc.cppsrc/platform/windows/nvprefs/nvprefs_common.cppsrc/platform/windows/misc.cppsrc/platform/windows/nvprefs/nvprefs_interface.cppsrc/platform/windows/nvprefs/driver_settings.hsrc/platform/windows/nvprefs/driver_settings.cppsrc/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.vuesrc_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_value中nullopt= 该设置先前不存在 = 恢复时删除)写得很清楚,三组 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与 NvAPINvAPI_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 winLinux 端 no-op 实现合理。
参数命名留空(
const std::string &, int)符合 no-op 语义,注释也明确说明 Linux 暂未提供等价能力。已确认src/platform/macos/misc.mm中存在对应的 no-op 实现(lines 247-249、252-254),其中apply_stream_optimizations和restore_stream_optimizations均已实现,无未定义符号风险。src_assets/common/assets/web/configs/tabs/encoders/NvidiaNvencEncoder.vue (1)
197-205: 新的折叠面板仍缺少 ARIA 关联。这个 accordion 的
button和折叠内容区之间还没有补齐稳定的 header id、aria-controls和aria-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
4db4aa3 to
e5579b9
Compare
3f48cf3 to
2a0b3a9
Compare
改了啥呢
这次把原本准备直接绑进 Sunshine core 的 NVIDIA Control Panel stream tuning,改成了一个生命周期插件方案:Sunshine 负责在关键 session 生命周期发 slot,插件负责可选的驱动 profile 调优。顺手也把 GitHub 驱动的插件市场第一层骨架搭起来了,杂鱼式手搓后端先退下,开源社区该用 PR、Release、Actions 和 Pages 来管生态。
assets/plugins/ config plugins、读取plugin.json、执行插件 exe、传入 JSON payload、读取--result、记录 history。GET /api/plugins/marketplace读取远程 registry index,并标注 installed/platform/installable 状态。plugin-registry/scaffold:listing schema、blocklist.json、生成后的index.json、registry README。scripts/plugin-registry/build-index.js、npm run plugin-registry:check、GitHub issue form、registry workflow。docs/plugin_marketplace.md,说明 GitHub Releases / Pages / Actions / PR review 如何运营社区插件市场。sunshine-plugin-nvprefs.exe,随包安装到assets/plugins/com.alkaidlab.nvidia-control-panel-optimizer/。--restore-nvprefs-undo作为手动恢复入口,迁移期更稳一点,坏状态这种杂鱼也有后路。为啥要这样改
PR #627 的初衷还是对的:帧生成或 unlocked-FPS 游戏在串流时需要 driver-level VSync + FRL,才能减少 tearing、missed frames 和高 PCL latency。但这个能力本质上是可选、平台相关、可能随驱动生态变化的扩展,不适合继续长在 Sunshine 的核心生命周期里。
插件化之后:
市场框架边界
这一版是 browse-first,不做一键安装:
https://alkaidlab.github.io/sunshine-plugin-registry/index.json。SUNSHINE_PLUGIN_MARKETPLACE_INDEX_URL覆盖。AlkaidLab/sunshine-plugin-registry仓库运行;留在主仓时只做校验,不抢主仓 Pages。安全和回滚
nv_optimize_game = false。nv_apply_to_base_profile = false。opengl_swapchain/game_profile/base_extras三段,旧 undo 文件仍可解析。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:checkpackage.jsonnpm run buildgit diff --checkcmake --build --preset dev --target sunshine --parallel 4cmake --build --preset dev --target sunshine-plugin-nvprefs --parallel 4plugin.json/config.schema.jsonstream.first_session.starting,无 NvAPI 时安全 skip 并写 success resultstream.dynamic_params.changedno-op 配置路径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 主机上验:
nv_optimize_game。VSYNCMODE = ForceOnFRL_FPS = client_fps + nv_frl_fps_offset,默认即 client fps - 2PREFERRED_PSTATE/PRERENDERLIMIT按配置生效nvprefs_undo.json并恢复 profile。dynamic_stream_params后调整 FPS,确认 FRL 随新的client_fps更新。Closes none.