Skip to content

Commit

Permalink
feat(display): add display mode remapping option (#3529)
Browse files Browse the repository at this point in the history
Co-authored-by: ReenigneArcher <[email protected]>
  • Loading branch information
FrogTheFrog and ReenigneArcher authored Jan 12, 2025
1 parent 012a99c commit 1b94e93
Show file tree
Hide file tree
Showing 11 changed files with 701 additions and 35 deletions.
86 changes: 86 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,92 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>

### dd_mode_remapping

<table>
<tr>
<td>Description</td>
<td colspan="2">
Remap the requested resolution and FPS to another display mode.<br>
Depending on the [dd_resolution_option](#dd_resolution_option) and
[dd_refresh_rate_option](#dd_refresh_rate_option) values, the following mapping
groups are available:
<ul>
<li>`mixed` - both options are set to `auto`.</li>
<li>
`resolution_only` - only [dd_resolution_option](#dd_resolution_option) is set to `auto`.
</li>
<li>
`refresh_rate_only` - only [dd_refresh_rate_option](#dd_refresh_rate_option) is set to `auto`.
</li>
</ul>
For each of those groups, a list of fields can be configured to perform remapping:
<ul>
<li>
`requested_resolution` - resolution that needs to be matched in order to use this remapping entry.
</li>
<li>`requested_fps` - FPS that needs to be matched in order to use this remapping entry.</li>
<li>`final_resolution` - resolution value to be used if the entry was matched.</li>
<li>`final_refresh_rate` - refresh rate value to be used if the entry was matched.</li>
</ul>
If `requested_*` field is left empty, it will match <b>everything</b>.<br>
If `final_*` field is left empty, the original value will not be remapped and either a requested, manual
or current value is used. However, at least one `final_*` must be set, otherwise the entry is considered
invalid.<br>
@note{"Optimize game settings" must be enabled on client side for ANY entry with `resolution`
field to be considered.}
@note{First entry to be matched in the list is the one that will be used.}
@tip{`requested_resolution` and `final_resolution` can be omitted for `refresh_rate_only` group.}
@tip{`requested_fps` and `final_refresh_rate` can be omitted for `resolution_only` group.}
@note{Applies to Windows only.}
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
dd_mode_remapping = {
"mixed": [],
"resolution_only": [],
"refresh_rate_only": []
}
@endcode
</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
dd_mode_remapping = {
"mixed": [
{
"requested_fps": "60",
"final_refresh_rate": "119.95",
"requested_resolution": "1920x1080",
"final_resolution": "2560x1440"
},
{
"requested_fps": "60",
"final_refresh_rate": "120",
"requested_resolution": "",
"final_resolution": ""
}
],
"resolution_only": [
{
"requested_resolution": "1920x1080",
"final_resolution": "2560x1440"
}
],
"refresh_rate_only": [
{
"requested_fps": "60",
"final_refresh_rate": "119.95"
}
]
}@endcode
</td>
</tr>
</table>

### min_fps_factor

<table>
Expand Down
34 changes: 34 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,38 @@ namespace config {
#undef _CONVERT_2_ARG_
return video_t::dd_t::hdr_option_e::disabled; // Default to this if value is invalid
}

video_t::dd_t::mode_remapping_t
mode_remapping_from_view(const std::string_view value) {
const auto parse_entry_list { [](const auto &entry_list, auto &output_field) {
for (auto &[_, entry] : entry_list) {
auto requested_resolution = entry.template get_optional<std::string>("requested_resolution"s);
auto requested_fps = entry.template get_optional<std::string>("requested_fps"s);
auto final_resolution = entry.template get_optional<std::string>("final_resolution"s);
auto final_refresh_rate = entry.template get_optional<std::string>("final_refresh_rate"s);

output_field.push_back(video_t::dd_t::mode_remapping_entry_t {
requested_resolution.value_or(""),
requested_fps.value_or(""),
final_resolution.value_or(""),
final_refresh_rate.value_or("") });
}
} };

// We need to add a wrapping object to make it valid JSON, otherwise ptree cannot parse it.
std::stringstream json_stream;
json_stream << "{\"dd_mode_remapping\":" << value << "}";

boost::property_tree::ptree json_tree;
boost::property_tree::read_json(json_stream, json_tree);

video_t::dd_t::mode_remapping_t output;
parse_entry_list(json_tree.get_child("dd_mode_remapping.mixed"), output.mixed);
parse_entry_list(json_tree.get_child("dd_mode_remapping.resolution_only"), output.resolution_only);
parse_entry_list(json_tree.get_child("dd_mode_remapping.refresh_rate_only"), output.refresh_rate_only);

return output;
}
} // namespace dd

video_t video {
Expand Down Expand Up @@ -447,6 +479,7 @@ namespace config {
{}, // manual_refresh_rate
video_t::dd_t::hdr_option_e::automatic, // hdr_option
3s, // config_revert_delay
{}, // mode_remapping
{} // wa
}, // display_device

Expand Down Expand Up @@ -1105,6 +1138,7 @@ namespace config {
video.dd.config_revert_delay = std::chrono::milliseconds { value };
}
}
generic_f(vars, "dd_mode_remapping", video.dd.mode_remapping, dd::mode_remapping_from_view);
bool_f(vars, "dd_wa_hdr_toggle", video.dd.wa.hdr_toggle);

int_between_f(vars, "min_fps_factor", video.min_fps_factor, { 1, 3 });
Expand Down
14 changes: 14 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,27 @@ namespace config {
automatic ///< Change HDR settings and use the state requested by Moonlight.
};

struct mode_remapping_entry_t {
std::string requested_resolution;
std::string requested_fps;
std::string final_resolution;
std::string final_refresh_rate;
};

struct mode_remapping_t {
std::vector<mode_remapping_entry_t> mixed; ///< To be used when `resolution_option` and `refresh_rate_option` is set to `automatic`.
std::vector<mode_remapping_entry_t> resolution_only; ///< To be use when only `resolution_option` is set to `automatic`.
std::vector<mode_remapping_entry_t> refresh_rate_only; ///< To be use when only `refresh_rate_option` is set to `automatic`.
};

config_option_e configuration_option;
resolution_option_e resolution_option;
std::string manual_resolution; ///< Manual resolution in case `resolution_option == resolution_option_e::manual`.
refresh_rate_option_e refresh_rate_option;
std::string manual_refresh_rate; ///< Manual refresh rate in case `refresh_rate_option == refresh_rate_option_e::manual`.
hdr_option_e hdr_option;
std::chrono::milliseconds config_revert_delay; ///< Time to wait until settings are reverted (after stream ends/app exists).
mode_remapping_t mode_remapping;
workarounds_t wa;
} dd;

Expand Down
Loading

0 comments on commit 1b94e93

Please sign in to comment.