#include "Renderable.h" #include "../plot/Plot_Core.h" #include "../render/Blend2D_Cache.h" #include #include #include namespace renderive { Renderable_Observation Renderable_Observer::observation() const noexcept { std::lock_guard lock(mutex_); auto result = observation_; const auto render = render_duration_statistics_.snapshot(); const auto task = task_duration_statistics_.snapshot(); const auto nanoseconds = [](double value) { return static_cast(std::max(0.0, std::round(value))); }; result.render_duration_sample_count = render.sample_count; result.render_duration_average_ns = nanoseconds(render.average); result.render_duration_deviation_ns = nanoseconds(render.deviation); result.render_duration_p50_ns = nanoseconds(render.p50); result.render_duration_p95_ns = nanoseconds(render.p95); result.render_duration_p99_ns = nanoseconds(render.p99); result.task_duration_sample_count = task.sample_count; result.task_duration_average_ns = nanoseconds(task.average); result.task_duration_deviation_ns = nanoseconds(task.deviation); result.task_duration_p50_ns = nanoseconds(task.p50); result.task_duration_p95_ns = nanoseconds(task.p95); result.task_duration_p99_ns = nanoseconds(task.p99); return result; } void Renderable_Observer::observe_state(Renderable_Observer_Event event, std::uint64_t time_ns, std::uint64_t cache_update_count, std::uint64_t publish_count) noexcept { std::lock_guard lock(mutex_); observation_.event = event; observation_.event_time_ns = time_ns; observation_.cache_update_count = cache_update_count; observation_.publish_count = publish_count; } void Renderable_Observer::observe_task( const Renderable_Task_Observation& task) noexcept { std::lock_guard lock(mutex_); if (task.event == Renderable_Task_Observation_Event::started) { if (active_render_sequence_ != task.render_sequence) { active_render_sequence_ = task.render_sequence; active_render_started_ns_ = task.time_ns; active_task_count_ = task.task_count; completed_task_count_ = 0; running_task_count_ = 0; active_peak_parallelism_ = 0; active_render_failed_ = false; } ++running_task_count_; ++observation_.task_execution_count; active_peak_parallelism_ = std::max(active_peak_parallelism_, running_task_count_); if (!active_render_failed_) { observation_.event = Renderable_Observer_Event::Render_Started; observation_.event_time_ns = task.time_ns; } observation_.last_render_sequence = task.render_sequence; return; } if (active_render_sequence_ != task.render_sequence) return; if (running_task_count_ != 0) --running_task_count_; ++completed_task_count_; observation_.last_task_duration_ns = task.task_duration_ns; observation_.total_task_duration_ns += task.task_duration_ns; observation_.maximum_task_duration_ns = std::max(observation_.maximum_task_duration_ns, task.task_duration_ns); task_duration_statistics_.add(static_cast(task.task_duration_ns)); const auto render_duration = task.time_ns >= active_render_started_ns_ ? task.time_ns - active_render_started_ns_ : 0; const auto extend_failed_render_duration = [&] { if (render_duration > observation_.last_render_duration_ns) { observation_.total_render_duration_ns += render_duration - observation_.last_render_duration_ns; observation_.last_render_duration_ns = render_duration; render_duration_statistics_.replace_latest( static_cast(render_duration)); observation_.maximum_render_duration_ns = std::max(observation_.maximum_render_duration_ns, render_duration); } }; if (task.event == Renderable_Task_Observation_Event::failed) { ++observation_.failed_task_count; if (!active_render_failed_) { active_render_failed_ = true; ++observation_.failed_render_count; observation_.event = Renderable_Observer_Event::Render_Failed; observation_.event_time_ns = task.time_ns; observation_.last_render_duration_ns = render_duration; observation_.total_render_duration_ns += render_duration; render_duration_statistics_.add(static_cast(render_duration)); observation_.maximum_render_duration_ns = std::max(observation_.maximum_render_duration_ns, render_duration); observation_.last_task_count = active_task_count_; observation_.peak_parallelism = active_peak_parallelism_; } else extend_failed_render_duration(); return; } if (active_render_failed_) { extend_failed_render_duration(); return; } if (completed_task_count_ == active_task_count_) { ++observation_.successful_render_count; observation_.event = Renderable_Observer_Event::Render_Completed; observation_.event_time_ns = task.time_ns; observation_.last_render_duration_ns = render_duration; observation_.total_render_duration_ns += render_duration; render_duration_statistics_.add(static_cast(render_duration)); observation_.maximum_render_duration_ns = std::max(observation_.maximum_render_duration_ns, render_duration); observation_.last_task_count = active_task_count_; observation_.peak_parallelism = active_peak_parallelism_; } } void Renderable_Observer::reset_performance() noexcept { std::lock_guard lock(mutex_); Renderable_Observation reset; if (observation_.event == Renderable_Observer_Event::Cache_Updated || observation_.event == Renderable_Observer_Event::Published) { reset.event = observation_.event; reset.event_time_ns = observation_.event_time_ns; } reset.cache_update_count = observation_.cache_update_count; reset.publish_count = observation_.publish_count; observation_ = reset; active_render_sequence_ = 0; active_render_started_ns_ = 0; active_task_count_ = 0; completed_task_count_ = 0; running_task_count_ = 0; active_peak_parallelism_ = 0; active_render_failed_ = false; render_duration_statistics_.clear(); task_duration_statistics_.clear(); } Renderable::Renderable(Plot_Core& plot, bool cache_enabled) : ::Renderable_Base(plot.kernel_scene(), {.cache_enabled = cache_enabled}), plot_(plot) {} Renderable::~Renderable() = default; Renderable_Cache_Mode Renderable::get_cache_mode() const noexcept { return configuration().cache_enabled ? Renderable_Cache_Mode::Local_Pixel : Renderable_Cache_Mode::Direct; } void Renderable::set_cache_mode(Renderable_Cache_Mode mode) { plot_.set_renderable_cache(*this, mode); } std::string Renderable::object_name() const { std::lock_guard lock(metadata_mutex_); return object_name_; } void Renderable::set_object_name(std::string name) { std::lock_guard lock(metadata_mutex_); object_name_ = std::move(name); } bool Renderable::is_visible() const noexcept { return visible_.load(std::memory_order_acquire); } void Renderable::set_visible(bool visible) { if (visible_.exchange(visible, std::memory_order_acq_rel) != visible) changed(); } Renderable_Observation Renderable::observation() const noexcept { return observer_.observation(); } void Renderable::observe_state(Renderable_Observer_Event event, std::uint64_t time_ns, std::uint64_t cache_update_count, std::uint64_t publish_count) noexcept { observer_.observe_state(event, time_ns, cache_update_count, publish_count); } void Renderable::observe_task( const Renderable_Task_Observation& observation) noexcept { observer_.observe_task(observation); } void Renderable::reset_task_observation() noexcept { observer_.reset_performance(); } void Renderable::render(const ::Scene_Render_Context& context) { if (!is_visible() || context.color_cache == nullptr) return; auto* cache = dynamic_cast(context.color_cache); if (!cache) return; detail::Painter painter(*cache, viewport_size()); if (painter) { const auto state = render_state_view(); paint(painter, state); } } void Renderable::build_task_graph(Renderable_Task_Graph& graph) { build_paint_task_graph(graph); } void Renderable::build_paint_task_graph(Renderable_Task_Graph& graph) { add_paint_task(graph, "绘制", [this](detail::Painter& painter, const Render_State_View& state, const Scene_Render_Context&) { paint(painter, state); }); } Renderable_Task_Graph::Task Renderable::add_paint_task( Renderable_Task_Graph& graph, std::string name, Paint_Task_Function function) { return graph.emplace( [this, function = std::move(function)](const Scene_Render_Context& context) { if (!is_visible() || context.color_cache == nullptr) return; auto* cache = dynamic_cast(context.color_cache); if (!cache) return; detail::Painter painter(*cache, viewport_size()); if (painter) function(painter, render_state_view(), context); }, std::move(name)); } void Renderable::changed() noexcept { invalidate_cache(); plot_.notify_model_dirty(); } void Renderable::task_graph_changed() noexcept { rebuild_task_graph(); plot_.notify_model_dirty(); } Size Renderable::viewport_size() const noexcept { return plot_.viewport_size(); } } // namespace renderive