优化
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <render_2D/axis/Axis.hpp>
|
||||
#include <render_2D/base/Frame_2D.hpp>
|
||||
#include <render_2D/plottable/Constellation_Diagram.hpp>
|
||||
#include <render_2D/plottable/Afterglow.hpp>
|
||||
#include <render_2D/plottable/Spectrum.hpp>
|
||||
#include <render_2D/plottable/Waterfall.hpp>
|
||||
#include <render_2D/scene/Render_Scene_2D.hpp>
|
||||
@@ -8,6 +9,7 @@
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
@@ -40,6 +42,7 @@ int main() {
|
||||
using Spectrum_Object = Spectrum;
|
||||
using Constellation_Object = Constellation_Diagram;
|
||||
using Waterfall_Object = Waterfall;
|
||||
using Afterglow_Object = Afterglow;
|
||||
using Scene_Object = Render_Scene_2D;
|
||||
|
||||
initialize_runtime({.workers = 4});
|
||||
@@ -49,11 +52,15 @@ int main() {
|
||||
auto* time = build_object<Time>();
|
||||
auto* waterfall = build_object<Waterfall_Object>(
|
||||
frequency, time, Plot_Partition_Grid{2, 2});
|
||||
auto* afterglow = build_object<Afterglow_Object>(
|
||||
frequency, power, Plot_Partition_Grid{2, 2});
|
||||
auto* q_axis = build_object<Power>();
|
||||
auto* constellation = build_object<Constellation_Object>(
|
||||
power, q_axis, 3u);
|
||||
auto* spectrum_painted = new std::atomic_bool{};
|
||||
auto* topology_valid = new std::atomic_bool{true};
|
||||
auto* second_frame_valid = new std::atomic_bool{};
|
||||
auto* trace_valid = new std::atomic_bool{true};
|
||||
spectrum->taskflow().add("test.spectrum.render.complete", [spectrum_painted] {
|
||||
spectrum_painted->store(true, std::memory_order_release);
|
||||
});
|
||||
@@ -70,6 +77,7 @@ int main() {
|
||||
typename Scene_Object::template Builder<Scene_Object> scene_builder;
|
||||
scene_builder.add_renderable(spectrum);
|
||||
scene_builder.add_renderable(waterfall);
|
||||
scene_builder.add_renderable(afterglow);
|
||||
scene_builder.add_renderable(constellation);
|
||||
auto scene_result = scene_builder.build();
|
||||
if (!scene_result) return 2;
|
||||
@@ -110,6 +118,13 @@ int main() {
|
||||
std::make_shared<const Waterfall_Row>(Waterfall_Row{
|
||||
second_tick, std::vector<Plot_Value>(64, -30.0)}));
|
||||
waterfall->mark_dirty<Render_Graph_Tag>();
|
||||
afterglow->set<&Afterglow::Prop::frequency_range>(
|
||||
Axis_Range{0.0, 100.0});
|
||||
afterglow->set<&Afterglow::Prop::power_range>(Axis_Range{-100.0, 0.0});
|
||||
afterglow->set<&Afterglow::Prop::power_point_size>(32u);
|
||||
afterglow->submit_stream<Afterglow_Stream_Tag>(
|
||||
std::make_shared<const std::vector<Plot_Value>>(64, -40.0));
|
||||
afterglow->mark_dirty<Render_Graph_Tag>();
|
||||
constellation->set<&Constellation_Diagram::Prop::i_range>(
|
||||
Axis_Range{-1.0, 1.0});
|
||||
constellation->set<&Constellation_Diagram::Prop::q_range>(
|
||||
@@ -122,27 +137,40 @@ int main() {
|
||||
scene->activate_view();
|
||||
auto* frame = new Frame_2D(Frame_Identity{1, 0});
|
||||
auto* resized_partition_frame = new Frame_2D(Frame_Identity{2, 0});
|
||||
frame->request_taskflow_trace();
|
||||
resized_partition_frame->request_taskflow_trace();
|
||||
scene->set_frame_retired_callback(
|
||||
[resized_partition_frame, second_frame_valid, trace_valid](
|
||||
Frame_2D* retired) {
|
||||
const auto trace = retired->take_taskflow_trace();
|
||||
bool spectrum_hold{};
|
||||
bool afterglow_reduce{};
|
||||
bool afterglow_color_barrier{};
|
||||
for (const auto& graph : trace.graphs)
|
||||
for (const auto& node : graph.nodes) {
|
||||
spectrum_hold = spectrum_hold ||
|
||||
node.name == "prepare.hold.partition";
|
||||
afterglow_reduce = afterglow_reduce ||
|
||||
node.name == "prepare.normalize";
|
||||
afterglow_color_barrier = afterglow_color_barrier ||
|
||||
node.name == "prepare.color.complete";
|
||||
}
|
||||
if (!spectrum_hold || !afterglow_reduce ||
|
||||
!afterglow_color_barrier)
|
||||
trace_valid->store(false, std::memory_order_relaxed);
|
||||
if (retired == resized_partition_frame)
|
||||
std::_Exit(second_frame_valid->load(std::memory_order_relaxed) &&
|
||||
trace_valid->load(std::memory_order_relaxed)
|
||||
? 0
|
||||
: 1);
|
||||
});
|
||||
scene->set_frame_callback(
|
||||
[scene, spectrum, waterfall, constellation, frequency, power, frame,
|
||||
[scene, spectrum, waterfall, afterglow, constellation, frame,
|
||||
resized_partition_frame, spectrum_painted,
|
||||
topology_valid](Frame_2D* completed) {
|
||||
const auto& spectrum_state =
|
||||
spectrum->read_state<Renderable::Base_Tag>();
|
||||
const auto& waterfall_state =
|
||||
waterfall->read_state<Renderable::Base_Tag>();
|
||||
const auto& constellation_state =
|
||||
constellation->read_state<Renderable::Base_Tag>();
|
||||
topology_valid, second_frame_valid](Frame_2D* completed) {
|
||||
const bool valid = completed == frame &&
|
||||
spectrum_state.render_executed &&
|
||||
spectrum_state.task_count == 11 &&
|
||||
waterfall_state.render_executed &&
|
||||
waterfall_state.task_count == 10 &&
|
||||
constellation_state.render_executed &&
|
||||
constellation_state.task_count == 5 &&
|
||||
spectrum->read_state<Spectrum::Base_Tag>().sample_count ==
|
||||
512 &&
|
||||
frequency->read_state<Renderable::Base_Tag>().render_executed &&
|
||||
power->read_state<Renderable::Base_Tag>().render_executed &&
|
||||
topology_valid->load(std::memory_order_relaxed) &&
|
||||
contains_color(completed->image());
|
||||
if (!valid) std::_Exit(1);
|
||||
@@ -150,34 +178,23 @@ int main() {
|
||||
spectrum->set<&Spectrum::Prop::partition_count>(2u);
|
||||
waterfall->set<&Waterfall::Prop::partition_grid>(
|
||||
Plot_Partition_Grid{3, 2});
|
||||
afterglow->set<&Afterglow::Prop::partition_grid>(
|
||||
Plot_Partition_Grid{3, 2});
|
||||
afterglow->submit_stream<Afterglow_Stream_Tag>(
|
||||
std::make_shared<const std::vector<Plot_Value>>(64, -20.0));
|
||||
afterglow->mark_dirty<Render_Graph_Tag>();
|
||||
constellation->set<
|
||||
&Constellation_Diagram::Prop::partition_count>(2u);
|
||||
spectrum_painted->store(false, std::memory_order_relaxed);
|
||||
scene->set_frame_callback(
|
||||
[spectrum, waterfall, constellation, frequency, power,
|
||||
resized_partition_frame,
|
||||
[resized_partition_frame, second_frame_valid,
|
||||
topology_valid](Frame_2D* next) {
|
||||
const auto& next_spectrum =
|
||||
spectrum->read_state<Renderable::Base_Tag>();
|
||||
const auto& next_waterfall =
|
||||
waterfall->read_state<Renderable::Base_Tag>();
|
||||
const auto& next_constellation =
|
||||
constellation->read_state<Renderable::Base_Tag>();
|
||||
const bool resized_valid =
|
||||
next == resized_partition_frame &&
|
||||
next_spectrum.graph_rebuilt &&
|
||||
next_spectrum.task_count == 7 &&
|
||||
next_waterfall.graph_rebuilt &&
|
||||
next_waterfall.task_count == 14 &&
|
||||
next_constellation.graph_rebuilt &&
|
||||
next_constellation.task_count == 4 &&
|
||||
frequency->read_state<Renderable::Base_Tag>()
|
||||
.render_executed &&
|
||||
power->read_state<Renderable::Base_Tag>()
|
||||
.render_executed &&
|
||||
topology_valid->load(std::memory_order_relaxed) &&
|
||||
contains_color(next->image());
|
||||
std::_Exit(resized_valid ? 0 : 1);
|
||||
second_frame_valid->store(resized_valid,
|
||||
std::memory_order_relaxed);
|
||||
});
|
||||
if (!scene->render(resized_partition_frame)) std::_Exit(2);
|
||||
});
|
||||
|
||||
@@ -141,6 +141,81 @@ TEST(partition_configuration,
|
||||
}
|
||||
}
|
||||
|
||||
TEST(partition_configuration,
|
||||
bilinear_tiles_with_source_halo_match_one_complete_heatmap) {
|
||||
const Size canvas{137, 93};
|
||||
const aethera::render_2d::detail::Raster_Layout layout{
|
||||
19, 13, Rect_F{3.25, 5.5, 128.5, 80.25}, false, false, true};
|
||||
std::vector<Pixel> pixels(
|
||||
static_cast<std::size_t>(layout.width) * layout.height);
|
||||
for (int y = 0; y < layout.height; ++y)
|
||||
for (int x = 0; x < layout.width; ++x)
|
||||
pixels[static_cast<std::size_t>(y) * layout.width + x] =
|
||||
0xff000000u | (static_cast<Pixel>(x * 13) << 16u) |
|
||||
(static_cast<Pixel>(y * 17) << 8u);
|
||||
|
||||
Blend2D_Cache expected_cache;
|
||||
expected_cache.ensure_size(canvas);
|
||||
expected_cache.clear();
|
||||
{
|
||||
aethera::render_2d::detail::Painter painter(expected_cache, canvas);
|
||||
aethera::render_2d::detail::paint_raster(
|
||||
painter, layout, pixels, Image_Interpolation_Mode::bilinear);
|
||||
}
|
||||
|
||||
Blend2D_Cache actual_cache;
|
||||
actual_cache.ensure_size(canvas);
|
||||
actual_cache.clear();
|
||||
constexpr Plot_Partition_Grid grid{4, 3};
|
||||
const Rect_F target = layout.target.normalized();
|
||||
for (Plot_Partition_Count index = 0;
|
||||
index < aethera::render_2d::detail::raster_partition_count(grid);
|
||||
++index) {
|
||||
const auto core = aethera::render_2d::detail::raster_partition(
|
||||
layout, index, grid);
|
||||
const aethera::render_2d::detail::Raster_Partition source{
|
||||
std::max(0, core.first_x - 1),
|
||||
std::min(layout.width, core.last_x + 1),
|
||||
std::max(0, core.first_y - 1),
|
||||
std::min(layout.height, core.last_y + 1)};
|
||||
const int width = source.last_x - source.first_x;
|
||||
const int height = source.last_y - source.first_y;
|
||||
std::vector<Pixel> tile(static_cast<std::size_t>(width) * height);
|
||||
for (int y = source.first_y; y < source.last_y; ++y)
|
||||
std::copy_n(pixels.begin() + static_cast<std::ptrdiff_t>(y) *
|
||||
layout.width + source.first_x,
|
||||
width,
|
||||
tile.begin() + static_cast<std::ptrdiff_t>(
|
||||
y - source.first_y) * width);
|
||||
const auto project_x = [&](int boundary) {
|
||||
return target.x + target.width * boundary / layout.width;
|
||||
};
|
||||
const auto project_y = [&](int boundary) {
|
||||
return target.y + target.height * boundary / layout.height;
|
||||
};
|
||||
const double left = project_x(source.first_x);
|
||||
const double top = project_y(source.first_y);
|
||||
aethera::render_2d::detail::Painter painter(
|
||||
actual_cache, canvas,
|
||||
aethera::render_2d::detail::raster_paint_region(layout, index, grid));
|
||||
painter.heatmap(
|
||||
{left, top, project_x(source.last_x) - left,
|
||||
project_y(source.last_y) - top},
|
||||
width, height, tile, Image_Interpolation_Mode::bilinear);
|
||||
}
|
||||
const Image_View expected = expected_cache.view();
|
||||
const Image_View actual = actual_cache.view();
|
||||
for (int y = 0; y < expected.height; ++y) {
|
||||
const auto* expected_row = reinterpret_cast<const Pixel*>(
|
||||
expected.data + static_cast<std::ptrdiff_t>(y) * expected.stride);
|
||||
const auto* actual_row = reinterpret_cast<const Pixel*>(
|
||||
actual.data + static_cast<std::ptrdiff_t>(y) * actual.stride);
|
||||
for (int x = 0; x < expected.width; ++x)
|
||||
EXPECT_EQ(actual_row[x], expected_row[x])
|
||||
<< "tile seam mismatch at " << x << ", " << y;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(partition_configuration,
|
||||
raster_grid_covers_each_matrix_cell_exactly_once) {
|
||||
const aethera::render_2d::detail::Raster_Layout layout{
|
||||
|
||||
@@ -185,7 +185,6 @@ TEST(plottable_migration, direct_overlay_and_constellation_build_and_render) {
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(diagram->access_rendering_stream<Constellation_Stream_Tag>(
|
||||
[](std::span<Constellation_Point> points) { return points.size(); }), 1u);
|
||||
EXPECT_EQ(overlay->read_state<Renderable::Base_Tag>().task_count, 1u);
|
||||
}
|
||||
|
||||
TEST(selection_overlay, control_extends_selection_and_plain_click_clears_it) {
|
||||
|
||||
@@ -142,8 +142,6 @@ TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
|
||||
EXPECT_TRUE(cache_graph.depends_on(spectrum.get(), power.get()));
|
||||
auto output_frame = render_frame(scene.get());
|
||||
EXPECT_GT(spectrum->read_state<Spectrum::Base_Tag>().rendered_point_count, 0u);
|
||||
const auto& render_state = spectrum->read_state<Renderable::Base_Tag>();
|
||||
EXPECT_EQ(render_state.task_count, 9u);
|
||||
const Image_View frame = output_frame->image();
|
||||
ASSERT_FALSE(frame.empty());
|
||||
EXPECT_TRUE(contains_color(frame));
|
||||
@@ -158,23 +156,16 @@ TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
|
||||
frequency->set<&Numeric_Axis::Prop::precision>(3);
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Cache_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_TRUE(spectrum->read_state<Renderable::Base_Tag>().render_executed);
|
||||
EXPECT_TRUE(frequency->read_state<Renderable::Base_Tag>().render_executed);
|
||||
EXPECT_TRUE(power->read_state<Renderable::Base_Tag>().render_executed);
|
||||
EXPECT_TRUE(contains_color(output_frame->image()));
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 120.0});
|
||||
EXPECT_TRUE(spectrum->dirty<Render_Cache_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Cache_Tag>());
|
||||
EXPECT_TRUE(spectrum->read_state<Renderable::Base_Tag>().render_executed);
|
||||
spectrum->set<&Spectrum::Prop::partition_count>(2u);
|
||||
spectrum->pending_buffer<Spectrum_Frame_Tag>() =
|
||||
Spectrum_Frame{std::vector<Spectrum_Power>(std::begin(samples), std::end(samples))};
|
||||
spectrum->mark_dirty<Render_Graph_Tag>();
|
||||
output_frame = render_frame(scene.get());
|
||||
const auto& rebuilt_state = spectrum->read_state<Renderable::Base_Tag>();
|
||||
EXPECT_TRUE(rebuilt_state.graph_rebuilt);
|
||||
EXPECT_EQ(rebuilt_state.task_count, 7u);
|
||||
EXPECT_TRUE(contains_color(output_frame->image()));
|
||||
const Size resized_canvas{200, 140};
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(resized_canvas);
|
||||
@@ -183,7 +174,6 @@ TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
|
||||
EXPECT_FALSE(power->dirty<Render_Graph_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_EQ(scene->read_prop<Render_Scene_2D::Base_Tag>().viewport, resized_canvas);
|
||||
EXPECT_TRUE(frequency->read_state<Renderable::Base_Tag>().render_executed);
|
||||
const Image_View resized_frame = output_frame->image();
|
||||
EXPECT_EQ(resized_frame.width, resized_canvas.width);
|
||||
EXPECT_EQ(resized_frame.height, resized_canvas.height);
|
||||
@@ -225,7 +215,6 @@ TEST(spectrum_data, repeatedly_publishes_new_samples_during_long_running_render)
|
||||
const auto hash = image_hash(frame->image());
|
||||
if (frame_index != 0 && hash != previous_hash) ++changed_frames;
|
||||
previous_hash = hash;
|
||||
EXPECT_TRUE(spectrum->read_state<Renderable::Base_Tag>().render_executed);
|
||||
EXPECT_EQ(spectrum->read_state<Spectrum::Base_Tag>().sample_count, 128u);
|
||||
}
|
||||
EXPECT_GT(changed_frames, 700u);
|
||||
|
||||
Reference in New Issue
Block a user