延迟低了很多

This commit is contained in:
2026-08-24 17:28:17 +08:00
parent f463a756fc
commit c0d5a13350
14 changed files with 335 additions and 162 deletions
-5
View File
@@ -70,7 +70,6 @@ void Graph_WebSocket::deliver_frame(
}
void Graph_WebSocket::receive(std::string_view message) {
const auto received_time = std::chrono::steady_clock::now();
const auto json = nlohmann::json::parse(message, nullptr, false);
if (json.is_discarded() || !json.is_object()) return;
const auto kind = json.value("kind", std::string{});
@@ -107,11 +106,7 @@ void Graph_WebSocket::receive(std::string_view message) {
height = d->height;
}
Plot_Input_Event decoded;
decoded.coalesced_event_count = std::clamp(
input->value("coalesced_event_count", std::size_t{1}),
std::size_t{1}, std::size_t{1'000});
decoded.type = *type;
decoded.received_time = received_time;
const auto read_point = [&](std::string_view key,
render_2d::Point_F& point,
bool viewport_relative) {
+31 -34
View File
@@ -35,27 +35,6 @@ constexpr std::uint16_t plot_stream_protocol_version{9};
constexpr std::size_t diagnostic_window_capacity{600};
struct Web_Input_Metadata {
Plot_Input_Event input;
std::chrono::steady_clock::time_point scene_dispatched;
};
struct Web_Input_Event {
virtual ~Web_Input_Event() = default;
[[nodiscard]] virtual const Web_Input_Metadata& web_input_metadata() const noexcept = 0;
};
template <typename Event_Object_Type>
struct Observed_Input_Event final : Event_Object_Type, Web_Input_Event {
template <typename... Arguments>
Observed_Input_Event(Web_Input_Metadata value_metadata,
Arguments&&... arguments)
: Event_Object_Type(std::forward<Arguments>(arguments)...),
metadata(std::move(value_metadata)) {}
[[nodiscard]] const Web_Input_Metadata& web_input_metadata() const noexcept override {
return metadata;
}
Web_Input_Metadata metadata;
};
std::string exception_description(const std::exception_ptr& failure) {
try {
if (failure) std::rethrow_exception(failure);
@@ -202,10 +181,30 @@ void append_statistic_json(nlohmann::json& output,
}
}
void append_event_statistics_json(nlohmann::json& output,
const Event_Statistics_State& state) {
for (const auto type : magic_enum::enum_values<Event_Type>()) {
auto& event = output[magic_enum::enum_name(type)];
const auto& values = state.values[static_cast<std::size_t>(type)];
for (const auto statistic : magic_enum::enum_values<Event_Statistic>()) {
if (statistic == Event_Statistic::count) continue;
const auto& value = values[static_cast<std::size_t>(statistic)];
if (value.count == 0) continue;
event[magic_enum::enum_name(statistic)] = {
{"count", value.count}, {"latest", value.latest},
{"minimum", value.minimum}, {"maximum", value.maximum},
{"average", value.average},
{"trimmed_average", value.trimmed_average},
{"variability", value.variability}, {"p50", value.p50},
{"p95", value.p95}, {"p99", value.p99}};
}
if (event.empty()) output.erase(std::string{magic_enum::enum_name(type)});
}
}
template <typename Scene_Object>
void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
Web_Input_Metadata metadata{input, std::chrono::steady_clock::now()};
const auto dispatch = [&](auto event) {
scene.template submit_stream<aethera::Scene_Event_Stream_Tag>(std::move(event));
};
@@ -220,15 +219,14 @@ void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
case Event_Type::pointer_move:
case Event_Type::pointer_press:
case Event_Type::pointer_release: {
auto event = scene.template make_event<Observed_Input_Event<Basic_Pointer_Event<Point_F>>>(
std::move(metadata), input.type);
auto event = scene.template make_event<Basic_Pointer_Event<Point_F>>(
input.type);
apply_pointer(*event);
dispatch(std::move(event));
break;
}
case Event_Type::wheel: {
auto event = scene.template make_event<Observed_Input_Event<Basic_Wheel_Event<Point_F>>>(
std::move(metadata));
auto event = scene.template make_event<Basic_Wheel_Event<Point_F>>();
apply_pointer(*event);
event->pixel_delta_x = input.pixel_delta_x;
event->pixel_delta_y = input.pixel_delta_y;
@@ -239,8 +237,7 @@ void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
}
case Event_Type::key_press:
case Event_Type::key_release: {
auto event = scene.template make_event<Observed_Input_Event<Key_Event>>(
std::move(metadata), input.type);
auto event = scene.template make_event<Key_Event>(input.type);
event->key = input.key;
event->native_key = input.native_key;
event->modifiers = input.modifiers;
@@ -249,8 +246,7 @@ void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input) {
break;
}
default:
dispatch(scene.template make_event<Observed_Input_Event<Event>>(
std::move(metadata), input.type));
dispatch(scene.template make_event<Event>(input.type));
break;
}
}
@@ -728,12 +724,11 @@ void Plot::render_once() {
void Plot::submit_input(Plot_Input_Event event) {
ensure_started();
if (d->terminal_failure.load(std::memory_order_acquire)) return;
if (event.received_time == std::chrono::steady_clock::time_point{})
event.received_time = std::chrono::steady_clock::now();
/*
* WebSocket 线程只向 Scene 的当前事件缓冲追加一个由 Scene
* memory_resource 分配的基类指针。Prepare 边界交换完整批次,
* 处理结果再由反向双缓冲交给 Plot 统计;事件处理不执行 Web 回调。
* Scene 在 Renderable 完成消费时按 Event_Type 增量统计,并随自身
* State 双缓冲发布;Web 层只在低频 diagnostics 请求中读取结果。
*/
try {
if (auto* scene_2d = std::get_if<std::unique_ptr<Scene_2D>>(&d->scene))
@@ -767,6 +762,7 @@ nlohmann::json Plot::generate_data(const nlohmann::json& input) {
nlohmann::json Plot::diagnostics() const {
nlohmann::json frame_statistics = nlohmann::json::object();
nlohmann::json input_statistics = nlohmann::json::object();
Frame_Identity identity{};
std::uint64_t created_time_unix_ns{};
std::uint64_t dropped_sequences{};
@@ -775,6 +771,7 @@ nlohmann::json Plot::diagnostics() const {
const auto read_statistics = [&](const auto& state) {
const auto& statistics = state.frame_statistics;
append_statistic_json(frame_statistics, statistics);
append_event_statistics_json(input_statistics, state.event_statistics);
identity = statistics.identity;
created_time_unix_ns = statistics.created_time_unix_ns;
dropped_sequences = statistics.dropped_sequences;
@@ -836,7 +833,7 @@ nlohmann::json Plot::diagnostics() const {
{"render_enabled", pacing.render_enabled},
{"video_enabled", pacing.video_enabled}}},
{"frame_statistics", std::move(frame_statistics)},
{"input_statistics", nlohmann::json::object()}};
{"input_statistics", std::move(input_statistics)}};
if (is_3d) {
const auto gpu = gpu_completion_state();
const auto milliseconds = [](std::uint64_t nanoseconds) {
-3
View File
@@ -2,7 +2,6 @@
#include <nlohmann/json_fwd.hpp>
#include <render_2D/scene/Render_Scene_2D.hpp>
#include <render_3D/scene/Render_Scene_3D.hpp>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <functional>
@@ -13,7 +12,6 @@
namespace aethera::web {
struct Plot_Input_Event {
std::size_t coalesced_event_count{1}; /* 浏览器显示周期内合并的原始输入数量。 */
Event_Type type{Event_Type::pointer_move}; /* 输入事件业务类型。 */
render_2d::Point_F position{}; /* Plot 像素坐标。 */
render_2d::Point_F global_position{}; /* 浏览器屏幕像素坐标。 */
@@ -27,7 +25,6 @@ struct Plot_Input_Event {
Key key{Key::unknown}; /* 标准化键盘按键。 */
std::uint32_t native_key{}; /* 浏览器原生按键码。 */
bool auto_repeat{}; /* 是否为系统重复按键。 */
std::chrono::steady_clock::time_point received_time{}; /* WebSocket 完成解析的服务端单调时刻。 */
};
struct Plot_Render_Tick {