ai改了半天还是不对

This commit is contained in:
2026-08-28 02:52:44 +08:00
parent 144602ef45
commit 5c2be8eef0
18 changed files with 1091 additions and 390 deletions
+3 -3
View File
@@ -306,9 +306,9 @@ public:
detail::Prop_Field < &Camera_3D::Prop::near_plane, "near_plane", "Nearest visible camera distance." >,
detail::Prop_Field<&Camera_3D::Prop::far_plane, "far_plane", "Farthest visible camera distance."> >;
using Axes_Adapter = detail::Renderable_Adapter<Axes_Object,
detail::Prop_Field < &Axes_3D::Prop::x_axis, "x_axis", "X axis range, scale, ticks, label and unit.">,
detail::Prop_Field < &Axes_3D::Prop::y_axis, "y_axis", "Y axis range, scale, ticks, label and unit." >,
detail::Prop_Field<&Axes_3D::Prop::z_axis, "z_axis", "Z axis range, scale, ticks, label and unit."> >;
detail::Prop_Field < &Axes_3D::Prop::x_axis, "x_axis", "X axis range, scale, ticks, label and unit.", "axis3d">,
detail::Prop_Field < &Axes_3D::Prop::y_axis, "y_axis", "Y axis range, scale, ticks, label and unit.", "axis3d" >,
detail::Prop_Field<&Axes_3D::Prop::z_axis, "z_axis", "Z axis range, scale, ticks, label and unit.", "axis3d"> >;
descriptors_.push_back(detail::make_renderable_descriptor("scene", "3D 场景", "scene", Scene_Adapter{scene}));
descriptors_.push_back(detail::make_renderable_descriptor("camera", "相机控制", "camera", Camera_Adapter{*camera_}));
descriptors_.push_back(detail::make_renderable_descriptor("axes", "三维坐标轴", "axes", Axes_Adapter{*axes_}));
+90 -12
View File
@@ -33,6 +33,14 @@ struct Gallery_WebSocket::Private {
Gallery_Transport_Mode transport{Gallery_Transport_Mode::ffmpeg}; /* 连接建立时协商的唯一媒体模型。 */
std::atomic_bool attached{}; /* start 成功后为真,并保证 close 只执行一次。 */
std::atomic_bool media_failed{}; /* 首次 WebRTC 发送 Unknown Failure 后停止重复报告。 */
std::atomic<std::shared_ptr<const frame_sampling::websocket_pixel::
WebSocket_Pixel_Frame>> pending_pixels{}; /* 浏览器尚未确认时仅保留最新图集帧。 */
std::atomic_bool pixel_frame_in_flight{}; /* Drogon 写队列中至多存在一个原始像素帧。 */
std::atomic_uint64_t pixel_in_flight_sequence{}; /* 当前等待浏览器确认的协议序号。 */
std::atomic_uint64_t pixel_queued_count{}; /* 进入 latest-only 槽的图集帧数。 */
std::atomic_uint64_t pixel_sent_count{}; /* 已交给 Drogon 的有界帧数。 */
std::atomic_uint64_t pixel_acknowledged_count{}; /* 浏览器完成上传后确认的帧数。 */
std::atomic_uint64_t pixel_replaced_count{}; /* 等待槽中被更新图集替换的旧帧数。 */
};
Gallery_WebSocket::Gallery_WebSocket(
@@ -90,11 +98,27 @@ void Gallery_WebSocket::start() {
[weak] {
const auto socket = weak.lock();
if (socket &&
socket->d->transport == Gallery_Transport_Mode::websocket_pixels)
socket->d->transport == Gallery_Transport_Mode::websocket_pixels) {
const auto pending = socket->d->pending_pixels.load(
std::memory_order_acquire);
return nlohmann::json{
{"kind", "websocket_pixel_transport_state"},
{"available", socket->d->attached.load(
std::memory_order_acquire)}};
std::memory_order_acquire)},
{"frame_in_flight", socket->d->pixel_frame_in_flight.load(
std::memory_order_acquire)},
{"pending_latest_frame", static_cast<bool>(pending)},
{"in_flight_sequence", socket->d->pixel_in_flight_sequence.load(
std::memory_order_relaxed)},
{"queued_frame_count", socket->d->pixel_queued_count.load(
std::memory_order_relaxed)},
{"sent_frame_count", socket->d->pixel_sent_count.load(
std::memory_order_relaxed)},
{"acknowledged_frame_count", socket->d->pixel_acknowledged_count.load(
std::memory_order_relaxed)},
{"replaced_frame_count", socket->d->pixel_replaced_count.load(
std::memory_order_relaxed)}};
}
return socket && socket->d->video
? socket->d->video->diagnostics()
: nlohmann::json{{"kind", "webrtc_transport_state"},
@@ -121,15 +145,8 @@ void Gallery_WebSocket::deliver(
}
if (frame.pixels &&
d->transport == Gallery_Transport_Mode::websocket_pixels &&
!d->media_failed.load(std::memory_order_acquire)) {
try {
connection->send(frame.pixels->bytes,
drogon::WebSocketMessageType::Binary);
}
catch (...) {
fail_media(std::current_exception());
}
}
!d->media_failed.load(std::memory_order_acquire))
queue_pixel_frame(std::move(frame.pixels));
if (!frame.notification.empty()) {
try {
connection->send(std::move(frame.notification),
@@ -139,6 +156,63 @@ void Gallery_WebSocket::deliver(
}
}
void Gallery_WebSocket::queue_pixel_frame(
std::shared_ptr<const frame_sampling::websocket_pixel::
WebSocket_Pixel_Frame> frame) {
if (!frame || !d->attached.load(std::memory_order_acquire)) return;
d->pixel_queued_count.fetch_add(1, std::memory_order_relaxed);
if (d->pending_pixels.exchange(
std::move(frame), std::memory_order_acq_rel))
d->pixel_replaced_count.fetch_add(1, std::memory_order_relaxed);
try_send_pixel_frame();
}
void Gallery_WebSocket::try_send_pixel_frame() {
bool available{};
if (!d->pixel_frame_in_flight.compare_exchange_strong(
available, true, std::memory_order_acq_rel,
std::memory_order_acquire))
return;
auto frame = d->pending_pixels.exchange({}, std::memory_order_acq_rel);
if (!frame) {
d->pixel_frame_in_flight.store(false, std::memory_order_release);
if (d->pending_pixels.load(std::memory_order_acquire))
try_send_pixel_frame();
return;
}
const auto connection = d->connection.lock();
if (!connection || !connection->connected() ||
!d->attached.load(std::memory_order_acquire)) {
d->pixel_frame_in_flight.store(false, std::memory_order_release);
return;
}
d->pixel_in_flight_sequence.store(
frame->sequence, std::memory_order_release);
try {
connection->send(frame->bytes,
drogon::WebSocketMessageType::Binary);
d->pixel_sent_count.fetch_add(1, std::memory_order_relaxed);
}
catch (...) {
d->pixel_frame_in_flight.store(false, std::memory_order_release);
fail_media(std::current_exception());
}
}
void Gallery_WebSocket::acknowledge_pixel_frame(std::uint64_t sequence) {
if (d->transport != Gallery_Transport_Mode::websocket_pixels ||
sequence == 0 || sequence != d->pixel_in_flight_sequence.load(
std::memory_order_acquire))
return;
bool in_flight{true};
if (!d->pixel_frame_in_flight.compare_exchange_strong(
in_flight, false, std::memory_order_acq_rel,
std::memory_order_acquire))
return;
d->pixel_acknowledged_count.fetch_add(1, std::memory_order_relaxed);
try_send_pixel_frame();
}
void Gallery_WebSocket::fail_media(std::exception_ptr failure) noexcept {
if (d->media_failed.exchange(true, std::memory_order_acq_rel)) return;
try {
@@ -159,7 +233,9 @@ void Gallery_WebSocket::receive(std::string_view message) {
if (json.is_discarded() || !json.is_object()) return;
const auto kind = json.value("kind", std::string{});
try {
if (kind == "webrtc_answer" && d->video) {
if (kind == "pixel_frame_consumed") {
acknowledge_pixel_frame(json.value("sequence", 0ULL));
} else if (kind == "webrtc_answer" && d->video) {
const auto sdp = json.value("sdp", std::string{});
if (!sdp.empty()) d->video->accept_answer(sdp);
} else if (kind == "webrtc_candidate" && d->video) {
@@ -182,6 +258,8 @@ void Gallery_WebSocket::close() noexcept {
}
catch (...) {}
d->subscription = 0;
d->pending_pixels.store({}, std::memory_order_release);
d->pixel_frame_in_flight.store(false, std::memory_order_release);
if (d->video) d->video->close();
}
+5
View File
@@ -21,6 +21,11 @@ public:
void close() noexcept;
private:
void deliver(Gallery_Stream_Frame frame);
void queue_pixel_frame(
std::shared_ptr<const frame_sampling::websocket_pixel::
WebSocket_Pixel_Frame> frame);
void try_send_pixel_frame();
void acknowledge_pixel_frame(std::uint64_t sequence);
void fail_media(std::exception_ptr failure) noexcept;
struct Private;
std::unique_ptr<Private> d;
+63 -7
View File
@@ -288,11 +288,56 @@ void append_event_statistics_json(nlohmann::json& output,
}
}
nlohmann::json datoviz_observation_json(
const Datoviz_Frame_Observation& value) {
const auto milliseconds = [](std::uint64_t nanoseconds) {
return static_cast<double>(nanoseconds) / 1'000'000.0;
};
nlohmann::json result{
{"render_sequence", value.render_sequence},
{"path", magic_enum::enum_name(value.path)},
{"gpu_timing_requested", value.gpu_timing_requested},
{"readback_requested", value.readback_requested},
{"timings_ms", {
{"render_domain_queue_wait",
milliseconds(value.render_domain_queue_wait_ns)},
{"apply", milliseconds(value.apply_ns)},
{"emit", milliseconds(value.emit_ns)},
{"execute", milliseconds(value.execute_ns)},
{"submit", milliseconds(value.submit_ns)},
{"gpu_fence_wait", milliseconds(value.gpu_fence_wait_ns)},
{"readback", milliseconds(value.readback_ns)}}},
{"traffic", {
{"uploaded_bytes", value.uploaded_bytes},
{"readback_bytes", value.readback_bytes}}},
{"frame_plan", {
{"resource_version", value.artifact_resource_version},
{"frame_index", value.artifact_frame_index},
{"status", value.artifact_status}}},
{"validation", {
{"performed", value.validation_performed},
{"ok", value.validation_ok},
{"code", value.validation_code},
{"command_index", value.validation_command_index}}}
};
if (value.gpu) {
result["gpu_ms"] = {
{"render", milliseconds(value.gpu->render_ns)},
{"transition", milliseconds(value.gpu->transition_ns)},
{"copy", milliseconds(value.gpu->copy_ns)},
{"total", milliseconds(value.gpu->total_ns)}};
}
if (!value.artifact_json.empty())
result["frame_plan"]["artifact_json"] = value.artifact_json;
return result;
}
}
nlohmann::json taskflow_trace_json(
const Taskflow_Frame_Trace& trace,
const nlohmann::json& captured_components) {
const nlohmann::json& captured_components,
const nlohmann::json& captured_backend) {
nlohmann::json markers = nlohmann::json::object();
for (const auto& marker : trace.markers)
markers[magic_enum::enum_name(marker.marker)] =
@@ -359,7 +404,7 @@ nlohmann::json taskflow_trace_json(
{"observer_exit_ms", task.observer_exit_ms},
{"queue_wait_ms", task.queue_wait_ms}});
}
return {
nlohmann::json result{
{"sequence", trace.identity.sequence},
{"correlation_id", trace.identity.correlation_id},
{"request_source", magic_enum::enum_name(trace.request_source)},
@@ -370,6 +415,8 @@ nlohmann::json taskflow_trace_json(
{"measurements", std::move(measurements)},
{"graphs", std::move(graphs)},
{"executions", std::move(executions)}};
if (!captured_backend.empty()) result["datoviz"] = captured_backend;
return result;
}
namespace {
@@ -596,7 +643,8 @@ struct Plot::Private {
std::array<std::atomic<std::shared_ptr<const nlohmann::json>>,
maximum_taskflow_trace_frames>& slots,
const Taskflow_Frame_Trace& trace,
const nlohmann::json& captured_components = {});
const nlohmann::json& captured_components = {},
const nlohmann::json& captured_backend = {});
[[nodiscard]] nlohmann::json trace_response(
const std::atomic_uint64_t& control,
const std::atomic_size_t& remaining,
@@ -848,9 +896,10 @@ void Plot::Private::store_trace(
std::array<std::atomic<std::shared_ptr<const nlohmann::json>>,
maximum_taskflow_trace_frames>& slots,
const Taskflow_Frame_Trace& value,
const nlohmann::json& captured_components) {
const nlohmann::json& captured_components,
const nlohmann::json& captured_backend) {
auto trace = std::make_shared<const nlohmann::json>(
taskflow_trace_json(value, captured_components));
taskflow_trace_json(value, captured_components, captured_backend));
auto state = control.load(std::memory_order_acquire);
for (;;) {
const auto requested = static_cast<std::uint32_t>(state >> 32U);
@@ -1324,6 +1373,7 @@ void Plot::Private::finalize_retired_frame(Render_Frame* frame) {
std::optional<Taskflow_Frame_Trace> captured_trace;
nlohmann::json captured_components;
nlohmann::json captured_backend;
if (frame->taskflow_trace_requested()) {
captured_trace.emplace(frame->take_taskflow_trace());
std::unordered_set<std::uint64_t> executed_nodes;
@@ -1343,6 +1393,10 @@ void Plot::Private::finalize_retired_frame(Render_Frame* frame) {
}
}
captured_components = view->capture_components(executed_components);
if (auto* frame_3d = dynamic_cast<render_3d::Frame_3D*>(frame)) {
if (auto observation = frame_3d->take_datoviz_observation())
captured_backend = datoviz_observation_json(*observation);
}
}
auto expected = Frame_State::consuming;
@@ -1363,11 +1417,13 @@ void Plot::Private::finalize_retired_frame(Render_Frame* frame) {
auto owner = lifetime;
schedule_task("plot.taskflow.serialize", [owner,
trace = std::move(*captured_trace),
components = std::move(captured_components)]() mutable {
components = std::move(captured_components),
backend = std::move(captured_backend)]() mutable {
if (const auto plot = owner.lock())
plot->d->store_trace(
plot->d->taskflow_trace_control,
plot->d->taskflow_trace_slots, trace, components);
plot->d->taskflow_trace_slots, trace, components,
backend);
});
}
}
+2 -1
View File
@@ -5,5 +5,6 @@
namespace aethera::web {
[[nodiscard]] nlohmann::json taskflow_trace_json(
const Taskflow_Frame_Trace& trace,
const nlohmann::json& captured_components = {});
const nlohmann::json& captured_components = {},
const nlohmann::json& captured_backend = {});
}