Files
Renderive/render_2D/renderable/Renderable.cpp
T
2026-08-12 13:46:53 +08:00

270 lines
10 KiB
C++

#include "Renderable.h"
#include "../plot/Plot_Core.h"
#include "../render/Blend2D_Cache.h"
#include <renderive/scene/base/Scene_Render_Context.hpp>
#include <algorithm>
#include <cmath>
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::uint64_t>(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<double>(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<double>(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<double>(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<double>(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<detail::Blend2D_Color_Cache*>(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<detail::Blend2D_Color_Cache*>(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