界面美化

This commit is contained in:
2026-08-22 11:06:38 +08:00
parent b569af2f00
commit 945e8287d4
7 changed files with 449 additions and 106 deletions
+28 -7
View File
@@ -80,7 +80,7 @@ nlohmann::json Frame_Policy::schema() const {
fields.push_back({{"key", "pacing_mode"}, {"label", "帧刷新策略"}, {"editor", "select"}, {"editable", true}, {"description", "选择浏览器如何安排下一次 render 调用。"}, {"technical_description", "Controls client-side render cadence using end-to-end samples computed by the browser."}, {"value", pacing_mode_name(pacing.mode)}, {"options", nlohmann::json::array({{{"value", "manual"}, {"label", "手动刷新"}}, {{"value", "fixed_rate"}, {"label", "固定频率"}}, {{"value", "minimum_latency"}, {"label", "最低延迟"}}, {{"value", "maximum_rate"}, {"label", "最高频率"}}})}});
fields.push_back({{"key", "fixed_rate_fps"}, {"label", "固定目标帧率"}, {"editor", "number"}, {"editable", true}, {"description", "固定频率策略下每秒发起的 render 次数。"}, {"technical_description", "Target render request rate used by fixed_rate pacing, in frames per second."}, {"value", pacing.fixed_rate_fps}});
fields.push_back({{"key", "minimum_latency_headroom"}, {"label", "最低延迟余量"}, {"editor", "number"}, {"editable", true}, {"description", "最低延迟策略使用的浏览器端 P95 端到端耗时安全系数。"}, {"technical_description", "Multiplier applied to browser-computed P95 request-to-pixel latency before scheduling the next render request."}, {"value", pacing.minimum_latency_headroom}});
return {{"id", "frame-runtime"}, {"label", "帧策略与诊断"}, {"kind", "runtime"}, {"fields", std::move(fields)}, {"state", nlohmann::json::object()}};
return {{"id", "frame-analysis"}, {"label", "渲染性能实验室"}, {"kind", "analysis"}, {"fields", std::move(fields)}};
}
nlohmann::json Frame_Policy::write_prop(std::string_view key, const nlohmann::json& value) {
std::lock_guard lock(mutex);
@@ -89,21 +89,21 @@ nlohmann::json Frame_Policy::write_prop(std::string_view key, const nlohmann::js
const auto parsed = parse_pacing_mode(value.get_ref<const std::string&>());
if (!parsed) return {{"success", false}, {"error", "unknown frame pacing mode"}};
pacing.mode = *parsed;
return {{"success", true}, {"component", "frame-runtime"}, {"key", key}, {"value", pacing_mode_name(pacing.mode)}};
return {{"success", true}, {"component", "frame-analysis"}, {"key", key}, {"value", pacing_mode_name(pacing.mode)}};
}
if (key == "fixed_rate_fps") {
if (!value.is_number()) return {{"success", false}, {"error", "fixed_rate_fps requires a number"}};
const double next = value.get<double>();
if (!std::isfinite(next) || next < 0.1 || next > 240.0) return {{"success", false}, {"error", "fixed_rate_fps must be between 0.1 and 240"}};
pacing.fixed_rate_fps = next;
return {{"success", true}, {"component", "frame-runtime"}, {"key", key}, {"value", pacing.fixed_rate_fps}};
return {{"success", true}, {"component", "frame-analysis"}, {"key", key}, {"value", pacing.fixed_rate_fps}};
}
if (key == "minimum_latency_headroom") {
if (!value.is_number()) return {{"success", false}, {"error", "minimum_latency_headroom requires a number"}};
const double next = value.get<double>();
if (!std::isfinite(next) || next < 1.0 || next > 4.0) return {{"success", false}, {"error", "minimum_latency_headroom must be between 1 and 4"}};
pacing.minimum_latency_headroom = next;
return {{"success", true}, {"component", "frame-runtime"}, {"key", key}, {"value", pacing.minimum_latency_headroom}};
return {{"success", true}, {"component", "frame-analysis"}, {"key", key}, {"value", pacing.minimum_latency_headroom}};
}
return {{"success", false}, {"error", "unknown frame runtime property"}};
}
@@ -167,7 +167,13 @@ struct Prop_Write {
nlohmann::json value;
Plot::Json_Handler handler;
};
using Plot_Input = std::variant<Frame_Submission, Schema_Query, Prop_Write>;
struct Data_Generation {
std::size_t count{};
double minimum{};
double maximum{};
Plot::Json_Handler handler;
};
using Plot_Input = std::variant<Frame_Submission, Schema_Query, Prop_Write, Data_Generation>;
template <typename Scene_Object>
void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
const auto dispatch = [&](auto event) {
@@ -260,7 +266,10 @@ struct Plot::Private {
};
nlohmann::json Plot::Private::schema() const {
auto result = view->schema();
result["components"].push_back(frame_policy.schema());
auto analysis = frame_policy.schema();
const auto generator = view->data_generator_schema();
if (!generator.is_null()) analysis["data_generator"] = generator;
result["frame_analysis"] = std::move(analysis);
return result;
}
Plot::Private::Managed_Frame Plot::Private::make_frame(Frame_Submission submission) {
@@ -370,11 +379,16 @@ void Plot::ensure_started() {
continue;
}
if (auto* write = std::get_if<Prop_Write>(&input)) {
write->handler(write->component == "frame-runtime"
write->handler(write->component == "frame-analysis"
? self->d->frame_policy.write_prop(write->key, write->value)
: self->d->view->write_prop(write->component, write->key, write->value));
continue;
}
if (auto* generation = std::get_if<Data_Generation>(&input)) {
generation->handler(self->d->view->generate_data(
generation->count, generation->minimum, generation->maximum));
continue;
}
auto submission = std::get<Frame_Submission>(input);
self->d->request_frame(std::move(submission));
}
@@ -414,4 +428,11 @@ void Plot::async_write_prop(std::string component, std::string key, nlohmann::js
}))
throw std::runtime_error("plot input queue is unavailable");
}
void Plot::async_generate_data(std::size_t count, double minimum, double maximum, Json_Handler handler) {
ensure_started();
if (!d->inputs.try_send(asio::error_code{}, Plot_Input{
Data_Generation{count, minimum, maximum, std::move(handler)}
}))
throw std::runtime_error("plot input queue is unavailable");
}
}