3D性能优化

This commit is contained in:
2026-08-22 14:23:05 +08:00
parent 049516bf3b
commit e2ba9b8384
15 changed files with 347 additions and 270 deletions
+31 -21
View File
@@ -33,7 +33,7 @@ using Frequency_Axis_Object = Impl<Frequency_Axis>;
using Numeric_Axis_Object = Impl<Numeric_Axis>;
using Time_Axis_Object = Impl<Time_Axis>;
using Selection_Object = Impl<Selection_Rectangle_Overlay>;
constexpr std::uint16_t frame_protocol_version{4};
constexpr std::uint16_t frame_protocol_version{5};
enum class Frame_Pacing_Mode : std::uint32_t {
manual,
fixed_rate,
@@ -70,6 +70,13 @@ std::optional<Frame_Pacing_Mode> parse_pacing_mode(std::string_view value) {
if (value == "maximum_rate") return Frame_Pacing_Mode::maximum_rate;
return std::nullopt;
}
std::string_view delivery_name(Plot_Frame_Delivery delivery) {
switch (delivery) {
case Plot_Frame_Delivery::pixels: return "pixels";
case Plot_Frame_Delivery::diagnostics: return "diagnostics";
}
throw std::logic_error("unknown plot frame delivery");
}
Frame_Pacing_Properties Frame_Policy::snapshot() const {
std::lock_guard lock(mutex);
return pacing;
@@ -107,7 +114,7 @@ nlohmann::json Frame_Policy::write_prop(std::string_view key, const nlohmann::js
}
return {{"success", false}, {"error", "unknown frame runtime property"}};
}
nlohmann::json frame_metadata(Render_Frame& frame, std::uint32_t width, std::uint32_t height, std::size_t byte_length, const Frame_Pacing_Properties& pacing) {
nlohmann::json frame_metadata(Render_Frame& frame, std::uint32_t width, std::uint32_t height, std::size_t byte_length, Plot_Frame_Delivery delivery, const Frame_Pacing_Properties& pacing) {
nlohmann::json markers = nlohmann::json::object();
for (const auto& point : frame.trace_points()) markers[std::string(magic_enum::enum_name(point.marker))] = point.elapsed_ns;
nlohmann::json measurements = nlohmann::json::object();
@@ -116,42 +123,44 @@ nlohmann::json frame_metadata(Render_Frame& frame, std::uint32_t width, std::uin
return {
{"kind", "frame_metadata"}, {"protocol", "aethera.frame"}, {"version", frame_protocol_version},
{"sequence", identity.sequence}, {"correlation_id", identity.correlation_id},
{"created_time_unix_ms", static_cast<double>(frame.created_time_unix_ns()) / 1'000'000.0},
{"created_time_unix_ms", static_cast<double>(frame.created_time_unix_ns()) / 1'000'000.0}, {"delivery", delivery_name(delivery)},
{"pixel", {{"width", width}, {"height", height}, {"format", "rgba8"}, {"byte_length", byte_length}}},
{"pacing", {{"mode", pacing_mode_name(pacing.mode)}, {"fixed_rate_fps", pacing.fixed_rate_fps}, {"minimum_latency_headroom", pacing.minimum_latency_headroom}}},
{"trace", {{"clock", "steady_elapsed_ns"}, {"markers", std::move(markers)}, {"measurements", std::move(measurements)}}}
};
}
std::shared_ptr<const Plot_Frame_Message> encode_frame(Frame_2D* frame, const Frame_Pacing_Properties& pacing) {
std::shared_ptr<const Plot_Frame_Message> encode_frame(Frame_2D* frame, Plot_Frame_Delivery delivery, const Frame_Pacing_Properties& pacing) {
frame->mark(Frame_Trace_Marker::websocket_publish_started);
const Image_View image = frame->image();
std::string output;
output.reserve(static_cast<std::size_t>(image.width) * image.height * 4);
for (int y = 0; y < image.height; ++y) {
const auto* row = reinterpret_cast<const std::uint8_t*>(
image.data + static_cast<std::ptrdiff_t>(y) * image.stride);
for (int x = 0; x < image.width; ++x) {
const auto* pixel = row + x * 4;
output.push_back(static_cast<char>(pixel[2]));
output.push_back(static_cast<char>(pixel[1]));
output.push_back(static_cast<char>(pixel[0]));
output.push_back(static_cast<char>(pixel[3]));
if (delivery == Plot_Frame_Delivery::pixels) {
output.reserve(static_cast<std::size_t>(image.width) * image.height * 4);
for (int y = 0; y < image.height; ++y) {
const auto* row = reinterpret_cast<const std::uint8_t*>(
image.data + static_cast<std::ptrdiff_t>(y) * image.stride);
for (int x = 0; x < image.width; ++x) {
const auto* pixel = row + x * 4;
output.push_back(static_cast<char>(pixel[2]));
output.push_back(static_cast<char>(pixel[1]));
output.push_back(static_cast<char>(pixel[0]));
output.push_back(static_cast<char>(pixel[3]));
}
}
}
frame->mark(Frame_Trace_Marker::websocket_publish_finished);
auto message = std::make_shared<Plot_Frame_Message>();
message->pixels = std::move(output);
message->metadata = frame_metadata(*frame, static_cast<std::uint32_t>(image.width), static_cast<std::uint32_t>(image.height), message->pixels.size(), pacing).dump();
message->metadata = frame_metadata(*frame, static_cast<std::uint32_t>(image.width), static_cast<std::uint32_t>(image.height), message->pixels.size(), delivery, pacing).dump();
return message;
}
std::shared_ptr<const Plot_Frame_Message> encode_frame(Frame_3D* frame, const Frame_Pacing_Properties& pacing) {
std::shared_ptr<const Plot_Frame_Message> encode_frame(Frame_3D* frame, Plot_Frame_Delivery delivery, const Frame_Pacing_Properties& pacing) {
frame->mark(Frame_Trace_Marker::websocket_publish_started);
const auto pixels = frame->pixels();
auto message = std::make_shared<Plot_Frame_Message>();
message->pixels.assign(reinterpret_cast<const char*>(pixels.data()), pixels.size());
if (delivery == Plot_Frame_Delivery::pixels) message->pixels.assign(reinterpret_cast<const char*>(pixels.data()), pixels.size());
frame->mark(Frame_Trace_Marker::websocket_publish_finished);
const auto extent = frame->extent();
message->metadata = frame_metadata(*frame, extent.width, extent.height, message->pixels.size(), pacing).dump();
message->metadata = frame_metadata(*frame, extent.width, extent.height, message->pixels.size(), delivery, pacing).dump();
return message;
}
struct Schema_Query {
@@ -273,7 +282,8 @@ nlohmann::json Plot::Private::schema() const {
Plot::Private::Managed_Frame Plot::Private::make_frame(Frame_Submission submission) {
const Frame_Identity identity{next_frame_sequence++, submission.request.correlation_id};
if (std::holds_alternative<std::unique_ptr<Scene_2D>>(scene)) return {submission.owner, std::move(submission.request), std::make_unique<Frame_2D>(identity)};
return {submission.owner, std::move(submission.request), std::make_unique<Frame_3D>(identity)};
const auto output = submission.request.delivery == Plot_Frame_Delivery::pixels ? Frame_3D_Output::pixels : Frame_3D_Output::diagnostics;
return {submission.owner, std::move(submission.request), std::make_unique<Frame_3D>(identity, output)};
}
void Plot::Private::request_frame(Frame_Submission submission) {
auto frame = make_frame(std::move(submission));
@@ -316,8 +326,8 @@ void Plot::Private::render_frame(Managed_Frame frame) {
void Plot::Private::publish_completed_frame(Render_Frame* frame) {
if (!active_frame) throw std::logic_error("frame callback has no externally owned active frame");
const auto pacing = frame_policy.snapshot();
if (auto* frame_2d = std::get_if<std::unique_ptr<Frame_2D>>(&active_frame->frame); frame_2d && frame_2d->get() == frame) publish(active_frame->owner, encode_frame(frame_2d->get(), pacing));
else if (auto* frame_3d = std::get_if<std::unique_ptr<Frame_3D>>(&active_frame->frame); frame_3d && frame_3d->get() == frame) publish(active_frame->owner, encode_frame(frame_3d->get(), pacing));
if (auto* frame_2d = std::get_if<std::unique_ptr<Frame_2D>>(&active_frame->frame); frame_2d && frame_2d->get() == frame) publish(active_frame->owner, encode_frame(frame_2d->get(), active_frame->request.delivery, pacing));
else if (auto* frame_3d = std::get_if<std::unique_ptr<Frame_3D>>(&active_frame->frame); frame_3d && frame_3d->get() == frame) publish(active_frame->owner, encode_frame(frame_3d->get(), active_frame->request.delivery, pacing));
else throw std::logic_error("frame callback does not match the externally owned active frame");
frame_completed();
}