server/src/display_device_policy.cpp
Rama main · réplica de lectura del repositorio original.
/** @file src/display_device_policy.cpp */
#include "display_device_policy.h"
#include <algorithm>
#include <cmath>
#include <limits>
#include <regex>
namespace display_device::policy {
namespace {
using dd_t = video_config_t::dd_t;
std::string trim(std::string value) {
const auto first = value.find_first_not_of(" \t\r\n");
if (first == std::string::npos) return {};
const auto last = value.find_last_not_of(" \t\r\n");
return value.substr(first, last - first + 1);
}
unsigned int stou(const std::string &value) {
const auto result = std::stoul(value);
if (result > std::numeric_limits<unsigned int>::max()) throw std::out_of_range("unsigned integer");
return static_cast<unsigned int>(result);
}
bool parse_resolution(const std::string &input, std::optional<resolution_t> &output) {
auto value = trim(input);
const std::string multiplication_sign = "\xC3\x97";
for (std::size_t pos {}; (pos = value.find(multiplication_sign, pos)) != std::string::npos; ++pos) value.replace(pos, multiplication_sign.size(), "x");
static const std::regex pattern {R"(^(\d+)x(\d+)$)"};
std::smatch match;
if (!std::regex_match(value, match, pattern)) {
if (value.empty()) { output.reset(); return true; }
return false;
}
try { output = resolution_t {stou(match[1].str()), stou(match[2].str())}; return true; }
catch (const std::exception &) { return false; }
}
bool parse_refresh_rate(const std::string &input, std::optional<rational_t> &output, bool decimal = true) {
const auto value = trim(input);
const std::regex pattern {decimal ? R"(^(\d+)(?:\.(\d+))?$)" : R"(^(\d+)$)"};
std::smatch match;
if (!std::regex_match(value, match, pattern)) {
if (value.empty()) { output.reset(); return true; }
return false;
}
try {
auto whole = match[1].str();
whole.erase(0, std::min(whole.find_first_not_of('0'), whole.size() - 1));
auto fraction = match[2].matched ? match[2].str() : std::string {};
fraction.erase(fraction.find_last_not_of('0') + 1);
if (fraction.empty()) output = rational_t {stou(whole), 1};
else output = rational_t {stou(whole + fraction), static_cast<unsigned int>(std::pow(10, fraction.size()))};
return true;
} catch (const std::exception &) { return false; }
}
std::optional<device_preparation_e> device_preparation(dd_t::config_option_e option) {
using enum dd_t::config_option_e;
switch (option) {
case verify_only: return device_preparation_e::VerifyOnly;
case ensure_active: return device_preparation_e::EnsureActive;
case ensure_primary: return device_preparation_e::EnsurePrimary;
case ensure_only_display: return device_preparation_e::EnsureOnlyDisplay;
case disabled: return std::nullopt;
}
return std::nullopt;
}
std::uint32_t effective_refresh_millihz(const session_t &session) {
if (session.framegen_refresh_millihz && *session.framegen_refresh_millihz > 0) return *session.framegen_refresh_millihz;
if (session.client_display_refresh_millihz > 0) return session.client_display_refresh_millihz;
if (session.framegen_refresh_rate && *session.framegen_refresh_rate > 0) return static_cast<std::uint32_t>(*session.framegen_refresh_rate) * 1000u;
return session.fps > 0 ? static_cast<std::uint32_t>(session.fps) * 1000u : 0;
}
bool parse_resolution_option(const video_config_t &video, const session_t &session, configuration_t &out) {
if (session.resolution_override) {
if (session.resolution_override->width <= 0 || session.resolution_override->height <= 0) return false;
out.m_resolution = resolution_t {static_cast<unsigned int>(session.resolution_override->width), static_cast<unsigned int>(session.resolution_override->height)};
return true;
}
if (session.client_display_mode_override) {
if (session.width < 0 || session.height < 0) return false;
out.m_resolution = resolution_t {static_cast<unsigned int>(session.width), static_cast<unsigned int>(session.height)};
return true;
}
using enum dd_t::resolution_option_e;
switch (video.dd.resolution_option) {
case automatic:
if (session.width < 0 || session.height < 0) return false;
out.m_resolution = resolution_t {static_cast<unsigned int>(session.width), static_cast<unsigned int>(session.height)};
break;
case manual:
if (!parse_resolution(video.dd.manual_resolution, out.m_resolution) || !out.m_resolution) return false;
break;
case disabled: break;
}
return true;
}
bool parse_refresh_option(const video_config_t &video, const session_t &session, configuration_t &out) {
if (session.client_display_mode_override) {
const auto value = effective_refresh_millihz(session);
if (!value) return false;
out.m_refresh_rate = rational_t {value, 1000};
return true;
}
using enum dd_t::refresh_rate_option_e;
switch (video.dd.refresh_rate_option) {
case automatic: {
const auto value = effective_refresh_millihz(session);
// A zero client FPS is a valid explicit value in the policy contract
// (and is represented as 0/1 by callers). A negative FPS, absent a
// valid higher-priority rate, remains invalid.
if (!value && session.fps < 0) return false;
out.m_refresh_rate = rational_t {value, 1000};
break;
}
case manual: if (!parse_refresh_rate(video.dd.manual_refresh_rate, out.m_refresh_rate) || !out.m_refresh_rate) return false; break;
case prefer_highest: out.m_refresh_rate = rational_t {10000, 1}; break;
case disabled: break;
}
return true;
}
enum class remapping_type_e { mixed, resolution_only, refresh_rate_only };
std::optional<remapping_type_e> remapping_type(const video_config_t &video) {
const bool res = video.dd.resolution_option == dd_t::resolution_option_e::automatic;
const bool fps = video.dd.refresh_rate_option == dd_t::refresh_rate_option_e::automatic;
if (res && fps) return remapping_type_e::mixed;
if (res) return remapping_type_e::resolution_only;
if (fps) return remapping_type_e::refresh_rate_only;
return std::nullopt;
}
bool remap(const video_config_t &video, const session_t &session, configuration_t &out) {
if (session.client_display_mode_override) return true;
const auto type = remapping_type(video); if (!type) return true;
const auto &entries = *type == remapping_type_e::mixed ? video.dd.mode_remapping.mixed : *type == remapping_type_e::resolution_only ? video.dd.mode_remapping.resolution_only : video.dd.mode_remapping.refresh_rate_only;
const bool map_res = *type != remapping_type_e::refresh_rate_only;
const bool map_fps = *type != remapping_type_e::resolution_only;
for (const auto &entry : entries) {
std::optional<resolution_t> request_res, final_res;
std::optional<rational_t> request_fps, final_fps;
if ((map_res && (!parse_resolution(entry.requested_resolution, request_res) || !parse_resolution(entry.final_resolution, final_res))) ||
// Requested FPS selects an integer client rate, while a remapped
// display mode may legitimately use a fractional refresh rate.
(map_fps && (!parse_refresh_rate(entry.requested_fps, request_fps, false) || !parse_refresh_rate(entry.final_refresh_rate, final_fps)))) return false;
if (!final_res && !final_fps) return false;
if ((request_res && request_res != out.m_resolution) || (request_fps && request_fps != out.m_refresh_rate)) continue;
if (final_res) out.m_resolution = final_res;
if (final_fps) out.m_refresh_rate = final_fps;
break;
}
return true;
}
} // namespace
bool effective_hdr_requested(const session_t &session) { return session.enable_hdr && !session.prefer_sdr_10bit && !session.force_sdr; }
bool effective_10bit_sdr_requested(const session_t &session) {
return session.prefer_sdr_10bit && session.enable_hdr && !session.force_sdr;
}
std::variant<failed_to_parse_tag_t, configuration_disabled_tag_t, configuration_t> parse_configuration(const video_config_t &video, const session_t &session) {
const auto preparation = device_preparation(video.dd.configuration_option);
if (!preparation) return configuration_disabled_tag_t {};
configuration_t out {.m_device_id = video.output_name, .m_device_prep = *preparation};
if (video.rtx_hdr_enabled) out.m_hdr_state = hdr_state_e::Disabled;
else if (video.dd.wa.dummy_plug_hdr10) out.m_hdr_state = hdr_state_e::Enabled;
else if (video.dd.hdr_option == dd_t::hdr_option_e::automatic) out.m_hdr_state = effective_hdr_requested(session) ? hdr_state_e::Enabled : hdr_state_e::Disabled;
if (!parse_resolution_option(video, session, out) || !parse_refresh_option(video, session, out) || !remap(video, session, out)) return failed_to_parse_tag_t {};
return out;
}
bool refresh_rate_override_active(const video_config_t &video, const session_t &session) {
if (video.dd.refresh_rate_option == dd_t::refresh_rate_option_e::manual) return true;
if (session.client_display_mode_override) return false;
const auto type = remapping_type(video); if (!type || *type == remapping_type_e::resolution_only) return false;
const auto &entries = *type == remapping_type_e::mixed ? video.dd.mode_remapping.mixed : video.dd.mode_remapping.refresh_rate_only;
const int fps = session.framegen_refresh_rate && *session.framegen_refresh_rate > 0 ? *session.framegen_refresh_rate : session.fps;
if (fps < 0) return false;
const rational_t requested {static_cast<unsigned int>(fps), 1};
for (const auto &entry : entries) {
std::optional<rational_t> request, final;
if (!parse_refresh_rate(entry.requested_fps, request, false) || !parse_refresh_rate(entry.final_refresh_rate, final, false)) return false;
if (final && (!request || *request == requested)) return true;
}
return false;
}
} // namespace display_device::policy