更新三缓冲 彻底

This commit is contained in:
2026-08-24 08:36:04 +08:00
parent d6c1db9d06
commit 1d3847d454
24 changed files with 120 additions and 453 deletions
+40 -30
View File
@@ -291,7 +291,9 @@ nlohmann::json generate_2d_data(Object& object, const Json& input) {
std::vector<Frequency_Trace_Sample> samples(count);
for (std::size_t index = 0; index < count; ++index)
samples[index] = {static_cast<Plot_Time_Tick>(index * tick_step), distribution(engine)};
for (const auto& sample : samples) object.append_sample(sample.tick, sample.value);
for (const auto& sample : samples)
object.template submit_stream<Frequency_Trace_Stream_Tag>(sample);
object.template mark_dirty<Prepare_Data_Tag>();
generated_count = count;
} else if constexpr (std::same_as<Definition, Sweep_Spectrum>) {
const auto block_count = generator_count(input, "block_count", 65'536);
@@ -305,7 +307,10 @@ nlohmann::json generate_2d_data(Object& object, const Json& input) {
std::ranges::copy_n(complete.begin() + block * width, width, blocks[block].begin());
object.template set<&Sweep_Spectrum::Prop::bins_per_block>(width);
object.template set<&Sweep_Spectrum::Prop::block_count>(block_count);
for (auto& block : blocks) object.append_block(block);
for (auto& block : blocks)
object.template submit_stream<Sweep_Spectrum_Stream_Tag>(
std::make_shared<const std::vector<Plot_Value>>(std::move(block)));
object.template mark_dirty<Prepare_Data_Tag>();
generated_count = block_count * width;
} else if constexpr (std::same_as<Definition, Afterglow>) {
const auto row_count = generator_count(input, "history_count", 4096);
@@ -317,7 +322,10 @@ nlohmann::json generate_2d_data(Object& object, const Json& input) {
const auto noise_stddev = generator_number(input, "noise_stddev");
for (std::size_t row = 0; row < row_count; ++row)
generate_spectral_row(spectra[row], row, signal_count, minimum, maximum, noise_stddev, engine);
for (auto& spectrum : spectra) object.append_spectrum(spectrum);
for (auto& spectrum : spectra)
object.template submit_stream<Afterglow_Stream_Tag>(
std::make_shared<const std::vector<Plot_Value>>(std::move(spectrum)));
object.template mark_dirty<Prepare_Data_Tag>();
generated_count = row_count * width;
} else if constexpr (std::same_as<Definition, Waterfall>) {
const auto row_count = generator_count(input, "row_count", 4096);
@@ -334,7 +342,10 @@ nlohmann::json generate_2d_data(Object& object, const Json& input) {
rows.push_back({static_cast<Plot_Time_Tick>(row), std::move(row_values)});
}
object.template set<&Waterfall::Prop::frequency_bin_count>(width);
for (auto& row : rows) object.append_row(row.tick, row.values);
for (auto& row : rows)
object.template submit_stream<Waterfall_Stream_Tag>(
std::make_shared<const Waterfall_Row>(std::move(row)));
object.template mark_dirty<Prepare_Data_Tag>();
generated_count = row_count * width;
} else if constexpr (std::same_as<Definition, Constellation_Diagram>) {
const auto count = generator_count(input, "point_count");
@@ -345,7 +356,9 @@ nlohmann::json generate_2d_data(Object& object, const Json& input) {
const auto submitted = monotonic_milliseconds();
for (std::size_t index = 0; index < count; ++index)
points[index] = {{i_distribution(engine), q_distribution(engine)}, submitted};
for (const auto& point : points) object.append_point(point.point);
for (const auto& point : points)
object.template submit_stream<Constellation_Stream_Tag>(point);
object.template mark_dirty<Prepare_Data_Tag>();
generated_count = count;
} else if constexpr (std::same_as<Definition, Selection_Rectangle_Overlay>) {
const auto count = generator_count(input, "region_count");
@@ -614,16 +627,15 @@ std::shared_ptr<Plot> make_frequency_trace_plot(asio::any_io_executor executor)
static_cast<std::int64_t>(
std::fmod(std::max(0.0, event.time_milliseconds), day_milliseconds))
});
raw->append_sample(tick,
std::sin(event.time_milliseconds * 0.0025) * 0.8
+ std::sin(event.time_milliseconds * 0.0007) * 0.2);
raw->template submit_stream<Frequency_Trace_Stream_Tag>(Frequency_Trace_Sample{
tick, std::sin(event.time_milliseconds * 0.0025) * 0.8
+ std::sin(event.time_milliseconds * 0.0007) * 0.2});
raw->template mark_dirty<Prepare_Data_Tag>();
};
auto view = make_scene_view<
Prop_Field<&Frequency_Trace::Prop::partition_count, "partition_count", "Number of partitions used to prepare the time-ordered trace.">,
Prop_Field<&Frequency_Trace::Prop::pen, "pen", "Stroke style used to draw the frequency trace.">,
Prop_Field<&Frequency_Trace::Prop::partition_mode, "partition_mode", "Selects how trace samples are divided between preparation tasks.">,
State_Field<Frequency_Trace, &Frequency_Trace::State::sample_count, "sample_count", "Number of samples retained by the current trace.">,
State_Field<Frequency_Trace, &Frequency_Trace::State::rendered_point_count, "rendered_point_count", "Number of points emitted for the latest trace frame.">>(
Prop_Field<&Frequency_Trace::Prop::partition_mode, "partition_mode", "Selects how trace samples are divided between preparation tasks.">>(
*trace, *scene, std::move(update), std::move(time), std::move(vertical), std::move(trace), std::move(selection));
return std::make_shared<Plot>(std::move(executor), std::move(scene), std::move(view));
}
@@ -658,7 +670,9 @@ std::shared_ptr<Plot> make_sweep_spectrum_plot(asio::any_io_executor executor) {
const auto sweep_index = block_index * values.size() + i;
values[i] = -90.0 + 35.0 * std::sin(sweep_index * 0.08 + event.time_milliseconds * 0.002);
}
raw->append_block(values);
raw->template submit_stream<Sweep_Spectrum_Stream_Tag>(
std::make_shared<const std::vector<Plot_Value>>(std::move(values)));
raw->template mark_dirty<Prepare_Data_Tag>();
};
auto view = make_scene_view<
Prop_Field<&Sweep_Spectrum::Prop::bins_per_block, "bins_per_block", "Number of frequency bins stored in each incoming sweep block.">,
@@ -669,10 +683,7 @@ std::shared_ptr<Plot> make_sweep_spectrum_plot(asio::any_io_executor executor) {
Prop_Field<&Sweep_Spectrum::Prop::partition_mode, "partition_mode", "Selects how sweep blocks are divided between preparation tasks.">,
Prop_Field<&Sweep_Spectrum::Prop::pen, "pen", "Stroke style used for the completed sweep curve.">,
Prop_Field<&Sweep_Spectrum::Prop::current_frequency_pen, "current_frequency_pen", "Stroke style used for the current sweep-frequency indicator.">,
Prop_Field<&Sweep_Spectrum::Prop::interpolation_mode, "interpolation_mode", "Selects interpolation between adjacent sweep bins.">,
State_Field<Sweep_Spectrum, &Sweep_Spectrum::State::stored_block_count, "stored_block_count", "Number of frequency segments that currently contain data.">,
State_Field<Sweep_Spectrum, &Sweep_Spectrum::State::stored_point_count, "stored_point_count", "Total number of points retained by the single composite sweep curve.">,
State_Field<Sweep_Spectrum, &Sweep_Spectrum::State::rendered_point_count, "rendered_point_count", "Number of points emitted for the single composite sweep curve.">>(
Prop_Field<&Sweep_Spectrum::Prop::interpolation_mode, "interpolation_mode", "Selects interpolation between adjacent sweep bins.">>(
*sweep, *scene, std::move(update), std::move(frequency), std::move(vertical), std::move(sweep), std::move(selection));
return std::make_shared<Plot>(std::move(executor), std::move(scene), std::move(view));
}
@@ -703,7 +714,9 @@ std::shared_ptr<Plot> make_afterglow_plot(asio::any_io_executor executor) {
values[i] = -95.0 + 62.0 * std::exp(-220.0 * std::pow(
static_cast<double>(i) / values.size() - 0.5
- 0.18 * std::sin(event.time_milliseconds * 0.0008), 2.0));
raw->append_spectrum(values);
raw->template submit_stream<Afterglow_Stream_Tag>(
std::make_shared<const std::vector<Plot_Value>>(values.begin(), values.end()));
raw->template mark_dirty<Prepare_Data_Tag>();
};
auto view = make_scene_view<
Prop_Field<&Afterglow::Prop::frequency_point_size, "frequency_point_size", "Number of frequency cells allocated across each afterglow row.">,
@@ -714,10 +727,7 @@ std::shared_ptr<Plot> make_afterglow_plot(asio::any_io_executor executor) {
Prop_Field<&Afterglow::Prop::frequency_range, "frequency_range", "Maps input samples onto the afterglow frequency axis.">,
Prop_Field<&Afterglow::Prop::power_range, "power_range", "Defines the minimum and maximum power represented by the color grid.">,
Prop_Field<&Afterglow::Prop::partition_mode, "partition_mode", "Selects how afterglow cells are divided between preparation tasks.">,
Prop_Field<&Afterglow::Prop::color_map, "color_map", "Maps accumulated energy values to rendered colors.">,
State_Field<Afterglow, &Afterglow::State::history_count, "history_count", "Number of spectrum frames retained in afterglow history.">,
State_Field<Afterglow, &Afterglow::State::latest_spectrum_point_count, "latest_spectrum_point_count", "Number of samples in the most recently appended spectrum.">,
State_Field<Afterglow, &Afterglow::State::rendered_cell_count, "rendered_cell_count", "Number of colored cells emitted for the latest frame.">>(
Prop_Field<&Afterglow::Prop::color_map, "color_map", "Maps accumulated energy values to rendered colors.">>(
*afterglow, *scene, std::move(update), std::move(frequency), std::move(vertical), std::move(afterglow), std::move(selection));
return std::make_shared<Plot>(std::move(executor), std::move(scene), std::move(view));
}
@@ -752,7 +762,10 @@ std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
static_cast<std::int64_t>(
std::fmod(std::max(0.0, event.time_milliseconds), day_milliseconds))
});
raw->append_row(tick, values);
raw->template submit_stream<Waterfall_Stream_Tag>(
std::make_shared<const Waterfall_Row>(Waterfall_Row{
tick, {values.begin(), values.end()}}));
raw->template mark_dirty<Prepare_Data_Tag>();
};
auto view = make_scene_view<
Prop_Field<&Waterfall::Prop::tooltip_enabled, "tooltip_enabled", "Enables value inspection tooltips over waterfall cells.">,
@@ -766,10 +779,7 @@ std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
Prop_Field<&Waterfall::Prop::power_range, "power_range", "Defines the power interval mapped through the waterfall color map.">,
Prop_Field<&Waterfall::Prop::partition_mode, "partition_mode", "Selects how waterfall rows are divided between preparation tasks.">,
Prop_Field<&Waterfall::Prop::interpolation_mode, "interpolation_mode", "Selects interpolation when samples are mapped to raster cells.">,
Prop_Field<&Waterfall::Prop::color_map, "color_map", "Maps sample power values to waterfall colors.">,
State_Field<Waterfall, &Waterfall::State::row_count, "row_count", "Number of waterfall rows currently retained.">,
State_Field<Waterfall, &Waterfall::State::stored_point_count, "stored_point_count", "Total number of spectrum points retained across all rows.">,
State_Field<Waterfall, &Waterfall::State::rendered_cell_count, "rendered_cell_count", "Number of raster cells emitted for the latest frame.">>(
Prop_Field<&Waterfall::Prop::color_map, "color_map", "Maps sample power values to waterfall colors.">>(
*waterfall, *scene, std::move(update), std::move(frequency), std::move(time), std::move(waterfall), std::move(selection));
return std::make_shared<Plot>(std::move(executor), std::move(scene), std::move(view));
}
@@ -806,11 +816,12 @@ std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
+ 0.012 * std::cos(phase * 23.0 + index * 0.61);
const double noise_q = 0.025 * std::cos(phase * 13.0 + index * 1.37)
+ 0.012 * std::sin(phase * 19.0 + index * 0.47);
raw->append_point({
raw->template submit_stream<Constellation_Stream_Tag>(Constellation_Point{{
state.i_range.center() + std::cos(angle) * radius + noise_i,
state.q_range.center() + std::sin(angle) * radius + noise_q
});
}, monotonic_milliseconds()});
}
raw->template mark_dirty<Prepare_Data_Tag>();
};
auto view = make_scene_view<
Prop_Field<&Constellation_Diagram::Prop::point_lifetime_ms, "point_lifetime_ms", "Time in milliseconds that an appended constellation point remains visible.">,
@@ -819,8 +830,7 @@ std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
Prop_Field<&Constellation_Diagram::Prop::i_range, "i_range", "Defines the horizontal in-phase coordinate interval.">,
Prop_Field<&Constellation_Diagram::Prop::q_range, "q_range", "Defines the vertical quadrature coordinate interval.">,
Prop_Field<&Constellation_Diagram::Prop::point_color, "point_color", "Color used to render received I/Q samples.">,
Prop_Field<&Constellation_Diagram::Prop::anchor_color, "anchor_color", "Color used to render ideal modulation anchors.">,
State_Field<Constellation_Diagram, &Constellation_Diagram::State::point_count, "point_count", "Number of constellation samples currently retained.">>(
Prop_Field<&Constellation_Diagram::Prop::anchor_color, "anchor_color", "Color used to render ideal modulation anchors.">>(
*constellation, *scene, std::move(update), std::move(horizontal), std::move(vertical), std::move(constellation), std::move(selection));
return std::make_shared<Plot>(std::move(executor), std::move(scene), std::move(view));
}
+12 -2
View File
@@ -242,7 +242,9 @@ void dispatch_plot_input(Scene_Object& scene, const Plot_Input_Event& input,
Plot::Input_Handler handler) {
Web_Input_Metadata metadata{input, std::move(handler),
std::chrono::steady_clock::now()};
const auto dispatch = [&](auto event) { scene.dispatch_event(std::move(event)); };
const auto dispatch = [&](auto event) {
scene.template submit_stream<aethera::Scene_Event_Stream_Tag>(std::move(event));
};
const auto apply_pointer = [&](auto& event) {
event.position = input.position;
event.global_position = input.global_position;
@@ -539,7 +541,15 @@ void Plot::Private::render_frame(Plot_Render_Tick tick) {
void Plot::Private::complete_event_reports(Frame_Identity rendered_identity) {
aethera::Scene::Event_Report_Batch reports = std::visit(
[](auto& value) { return value->take_event_reports(); }, scene);
[](auto& value) {
return value->template access_query_stream<aethera::Scene_Event_Stream_Tag>(
[&](std::span<const aethera::Scene::Event_Pointer> events) {
aethera::Scene::Event_Report_Batch result{value->memory_resource()};
result.reserve(events.size());
for (const auto& event : events) result.push_back(event);
return result;
});
}, scene);
pending_event_reports.insert(pending_event_reports.end(),
std::make_move_iterator(reports.begin()),
std::make_move_iterator(reports.end()));