Files
Renderive/Core/architecture/Renderable.cpp
T
2026-08-02 19:26:50 +08:00

574 lines
26 KiB
C++

#include <algorithm>
#include <utility>
#include "../base/Memory.h"
#include "../render/Frame_Prepare_Subflow.h"
#include "Plot_Render_Context.h"
#include "../plot/Plot_Core.h"
#include "../plot/Plot_Core_Access.h"
#include "../render/Render_Frame_Snapshot.h"
#include "Renderable.h"
#include "Render_Time.h"
namespace renderive {
namespace {
std::uint64_t next_renderable_node_id() {
static std::atomic<std::uint64_t> next_id{1};
return next_id.fetch_add(1, std::memory_order_acq_rel);
}
} // namespace
Renderable_Cache_Mode Renderable::get_cache_mode() const {
return cache_mode.load(std::memory_order_acquire);
}
void Renderable::set_cache_mode(Renderable_Cache_Mode mode) {
cache_mode.store(mode, std::memory_order_release);
mark_render_dirty(Dirty_Reason::Config);
}
bool Renderable::attached_to_plot() const {
return plot != nullptr;
}
bool Renderable::shares_plot_with(const Renderable& other) const {
return plot != nullptr && plot == other.plot;
}
const std::string& Renderable::object_name() const {
return object_name_;
}
std::uint64_t Renderable::node_id() const {
return node_id_;
}
void Renderable::set_object_name(std::string name) {
if (initialized.load(std::memory_order_acquire) && object_name_ != name) {
ASSERT(false, "Renderable object_name must be fixed before attach");
return;
}
object_name_ = std::move(name);
}
bool Renderable::is_visible() const {
return visible_.load(std::memory_order_acquire);
}
void Renderable::set_visible(bool value) {
bool old = visible_.exchange(value, std::memory_order_acq_rel);
if (old == value)
return;
mark_render_dirty(Dirty_Reason::Config);
}
bool Renderable::should_prepare() const {
return !get_retiring() && visible_.load(std::memory_order_acquire) && d_ptr;
}
void Renderable::detach_from_parent() {
if (auto parent = parent_renderable.lock())
parent->remove_child(shared_from_this());
}
std::string Renderable::cache_parent_object_name() const {
std::shared_ptr<Renderable> parent = parent_renderable.lock();
while (parent) {
if (parent->get_cache_mode() == Renderable_Cache_Mode::Local_Pixel)
return parent->object_name_;
parent = parent->parent_renderable.lock();
}
return {};
}
int Renderable::cache_tree_depth() const {
int depth = 0;
std::shared_ptr<Renderable> parent = parent_renderable.lock();
while (parent) {
if (parent->get_cache_mode() == Renderable_Cache_Mode::Local_Pixel)
++depth;
parent = parent->parent_renderable.lock();
}
return depth;
}
std::string Renderable::render_parent_object_name() const {
if (auto parent = parent_renderable.lock())
return parent->object_name_;
return {};
}
int Renderable::render_tree_depth() const {
int depth = 0;
std::shared_ptr<Renderable> parent = parent_renderable.lock();
while (parent) {
++depth;
parent = parent->parent_renderable.lock();
}
return depth;
}
void Renderable::init_root(Plot_Core* plot) {
if (!plot) {
ASSERT(plot, "Renderable root init error! plot == nullptr");
return;
}
bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel);
if (initialized) {
ASSERT(!initialized, "Renderable root init error! Renderable already initialized");
return;
}
init_common(plot);
}
void Renderable::init(const std::shared_ptr<Renderable>& parent) {
if (!parent || !parent->plot) {
ASSERT(parent && parent->plot, "Renderable init error! parent invalid");
return;
}
bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel);
if (initialized) {
ASSERT(!initialized, "Renderable init error! Renderable already initialized");
return;
}
init_common(parent->plot);
parent->add_child(shared_from_this());
}
void Renderable::init_common(Plot_Core* plot) {
this->plot = plot;
if (!node_id_)
node_id_ = next_renderable_node_id();
plot_context = Plot_Core_Context_Access::render_context(*plot);
retiring.store(false, std::memory_order_release);
if (!d_ptr) {
d_owner = create_render_data();
d_ptr = d_owner.get<Render_Data>();
}
d_ptr->q_ptr = this;
d_ptr->initialize_runtime(plot->create_renderable_runtime(*this));
plot->notify_model_dirty(Dirty_Reason::Config);
}
void Renderable::add_child(const std::shared_ptr<Renderable>& child) {
if (!child || child.get() == this || child->plot != plot || !child->parent_renderable.expired() || get_retiring() || child->get_retiring()) {
ASSERT(child && child.get() != this && child->plot == plot && child->parent_renderable.expired() && !get_retiring() && !child->get_retiring(), "Renderable add_child error! invalid child");
return;
}
{
std::lock_guard<std::mutex> lock(children_mutex);
if (get_retiring())
return;
if (std::find(children.begin(), children.end(), child) != children.end())
return;
child->parent_renderable = shared_from_this();
children.push_back(child);
}
// Marking dirty may render synchronously, so the child list lock must be released first.
mark_render_dirty(Dirty_Reason::Config);
}
void Renderable::remove_child(const std::shared_ptr<Renderable>& child) {
if (!child || child->parent_renderable.lock().get() != this)
return;
std::shared_ptr<Renderable> removed;
{
std::lock_guard<std::mutex> lock(children_mutex);
auto it = std::find(children.begin(), children.end(), child);
if (it == children.end())
return;
removed = *it;
removed->parent_renderable.reset();
children.erase(it);
}
removed->detach_from_plot_tree();
mark_render_dirty(Dirty_Reason::Config);
}
std::vector<std::shared_ptr<Renderable>> Renderable::children_snapshot() const {
std::lock_guard<std::mutex> lock(children_mutex);
return children;
}
void Renderable::append_tree_snapshot(
Renderable_Frame_Tree& snapshot,
std::uint64_t parent_node_id,
const std::string& parent_object_name,
int render_tree_depth,
std::uint64_t cache_parent_node_id,
const std::string& cache_parent_object_name,
int cache_tree_depth) {
std::size_t index = snapshot.size();
Renderable_Cache_Mode mode = get_cache_mode();
Renderable_Frame_Node node;
node.renderable = shared_from_this();
node.subtree_end = index + 1;
node.node_id = node_id_;
node.parent_node_id = parent_node_id;
node.parent_object_name = parent_object_name;
node.render_tree_depth = render_tree_depth;
node.object_name = object_name_;
node.cache_parent_node_id = cache_parent_node_id;
node.cache_parent_object_name = cache_parent_object_name;
node.cache_tree_depth = cache_tree_depth;
if (d_ptr && should_prepare())
node.frame_view = d_ptr->capture_frame_view();
snapshot.push_back(std::move(node));
std::string child_cache_parent = cache_parent_object_name;
std::uint64_t child_cache_parent_id = cache_parent_node_id;
int child_cache_depth = cache_tree_depth;
if (mode == Renderable_Cache_Mode::Local_Pixel) {
child_cache_parent = object_name_;
child_cache_parent_id = node_id_;
++child_cache_depth;
}
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
for (const auto& child : children) {
if (child)
child->append_tree_snapshot(snapshot, node_id_, object_name_, render_tree_depth + 1, child_cache_parent_id, child_cache_parent, child_cache_depth);
}
snapshot[index].subtree_end = snapshot.size();
}
std::vector<std::shared_ptr<Renderable>> Renderable::hit_renderables(const PointF& pos) {
std::vector<std::shared_ptr<Renderable>> hits;
append_hit_renderables(hits, pos);
return hits;
}
void Renderable::append_hit_renderables(std::vector<std::shared_ptr<Renderable>>& hits, const PointF& pos) {
if (get_retiring() || !visible_.load(std::memory_order_acquire))
return;
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) {
const auto& child = children.at(i);
if (child)
child->append_hit_renderables(hits, pos);
}
if (select_test(pos))
hits.push_back(shared_from_this());
}
void Renderable::render(Canvas& canvas, const Render_Frame_Snapshot& snapshot) {
if (get_retiring() || !visible_.load(std::memory_order_acquire))
return;
Renderable_Cache_Mode mode = get_cache_mode();
std::uint64_t begin_time = steady_now_ns();
if (mode == Renderable_Cache_Mode::Local_Pixel)
render_cached(canvas, snapshot);
else
render_direct(canvas, snapshot);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_render(node_id_, 0, object_name_, render_parent_object_name(), render_tree_depth(), mode, steady_now_ns() - begin_time);
}
void Renderable::render_tree_snapshot(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Tree& tree, std::size_t index) {
render_tree_node(canvas, snapshot, tree, index);
}
void Renderable::render_direct(Canvas& canvas, const Render_Frame_Snapshot& snapshot) {
render_self(canvas, snapshot);
render_children(canvas, snapshot);
}
void Renderable::render_children(Canvas& canvas, const Render_Frame_Snapshot& snapshot) {
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
for (const auto& child : children) {
if (child)
child->render(canvas, snapshot);
}
}
void Renderable::render_cached(Canvas& canvas, const Render_Frame_Snapshot& snapshot) {
Size size = snapshot.size;
Rect bounds = d_ptr ? d_ptr->pixel_bounds(size).intersected(Rect{0, 0, size.width, size.height}) : Rect{0, 0, size.width, size.height};
if (bounds.empty())
return;
std::uint64_t edit_version = cache_edit_version.load(std::memory_order_acquire);
std::string parent_object_name = cache_parent_object_name();
int tree_depth = cache_tree_depth();
bool ready = cache_ready_version.load(std::memory_order_acquire) == edit_version && cache_image.size() == Size{bounds.width, bounds.height} && cache_bounds.x == bounds.x && cache_bounds.y == bounds.y && cache_bounds.width == bounds.width && cache_bounds.height == bounds.height;
if (ready) {
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_hit(node_id_, 0, object_name_, parent_object_name, tree_depth);
std::uint64_t begin_time = steady_now_ns();
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_compose(node_id_, 0, object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
return;
}
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_miss(node_id_, 0, object_name_, parent_object_name, tree_depth);
std::uint64_t rebuild_begin_time = steady_now_ns();
render_cache_image(bounds, snapshot, edit_version);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_rebuild(node_id_, 0, object_name_, parent_object_name, tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
if (!cache_image.empty()) {
std::uint64_t begin_time = steady_now_ns();
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_compose(node_id_, 0, object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
}
}
std::size_t Renderable::render_tree_node(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Tree& tree, std::size_t index) {
if (index >= tree.size())
return tree.size();
const Renderable_Frame_Node& node = tree[index];
Renderable* current = node.renderable.get();
if (!current)
return std::max(index + 1, node.subtree_end);
if (current != this)
return current->render_tree_node(canvas, snapshot, tree, index);
if (get_retiring() || !visible_.load(std::memory_order_acquire))
return std::max(index + 1, node.subtree_end);
Renderable_Cache_Mode mode = get_cache_mode();
std::uint64_t begin_time = steady_now_ns();
if (mode == Renderable_Cache_Mode::Local_Pixel)
render_cached_tree_node(canvas, snapshot, tree, index);
else
render_direct_tree_node(canvas, snapshot, tree, index);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_render(node.node_id, node.parent_node_id, node.object_name, node.parent_object_name, node.render_tree_depth, mode, steady_now_ns() - begin_time);
return std::max(index + 1, node.subtree_end);
}
void Renderable::render_direct_tree_node(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Tree& tree, std::size_t index) {
render_self(canvas, snapshot, &tree[index]);
std::size_t child_index = index + 1;
while (child_index < tree[index].subtree_end && child_index < tree.size()) {
auto child = tree[child_index].renderable;
if (!child) {
++child_index;
continue;
}
child_index = child->render_tree_node(canvas, snapshot, tree, child_index);
}
}
void Renderable::render_cached_tree_node(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Tree& tree, std::size_t index) {
Size size = snapshot.size;
Rect bounds = d_ptr ? d_ptr->pixel_bounds(size).intersected(Rect{0, 0, size.width, size.height}) : Rect{0, 0, size.width, size.height};
if (bounds.empty())
return;
const Renderable_Frame_Node& node = tree[index];
std::uint64_t edit_version = cache_edit_version.load(std::memory_order_acquire);
bool ready = cache_ready_version.load(std::memory_order_acquire) == edit_version && cache_image.size() == Size{bounds.width, bounds.height} && cache_bounds.x == bounds.x && cache_bounds.y == bounds.y && cache_bounds.width == bounds.width && cache_bounds.height == bounds.height;
if (ready) {
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_hit(node.node_id, node.cache_parent_node_id, node.object_name, node.cache_parent_object_name, node.cache_tree_depth);
std::uint64_t begin_time = steady_now_ns();
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_compose(node.node_id, node.cache_parent_node_id, node.object_name, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
return;
}
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_miss(node.node_id, node.cache_parent_node_id, node.object_name, node.cache_parent_object_name, node.cache_tree_depth);
std::uint64_t rebuild_begin_time = steady_now_ns();
render_cache_image_tree_node(bounds, snapshot, tree, index, edit_version);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_rebuild(node.node_id, node.cache_parent_node_id, node.object_name, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
if (!cache_image.empty()) {
std::uint64_t begin_time = steady_now_ns();
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
if (snapshot.frame_metadata)
snapshot.frame_metadata->record_renderable_cache_compose(node.node_id, node.cache_parent_node_id, node.object_name, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
}
}
void Renderable::render_cache_image_tree_node(const Rect& bounds, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Tree& tree, std::size_t index, std::uint64_t version) {
if (get_retiring())
return;
Image temp_image;
temp_image.resize(bounds.width, bounds.height);
temp_image.fill(Color::transparent());
{
Canvas cache_canvas(temp_image);
cache_canvas.translate(static_cast<double>(-bounds.x), static_cast<double>(-bounds.y));
render_direct_tree_node(cache_canvas, snapshot, tree, index);
}
cache_bounds = bounds;
this->cache_image = std::move(temp_image);
cache_ready_version.store(version, std::memory_order_release);
}
void Renderable::render_cache_image(const Rect& bounds, const Render_Frame_Snapshot& snapshot, std::uint64_t version) {
if (get_retiring())
return;
Image temp_image;
temp_image.resize(bounds.width, bounds.height);
temp_image.fill(Color::transparent());
{
Canvas cache_canvas(temp_image);
cache_canvas.translate(static_cast<double>(-bounds.x), static_cast<double>(-bounds.y));
render_direct(cache_canvas, snapshot);
}
cache_bounds = bounds;
this->cache_image = std::move(temp_image);
cache_ready_version.store(version, std::memory_order_release);
}
void Renderable::render_self(Canvas& canvas, const Render_Frame_Snapshot& snapshot) {
render_self(canvas, snapshot, nullptr);
}
void Renderable::render_self(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_Node* node) {
if (!d_ptr)
return;
Renderable_Frame_View local_frame_view;
const Renderable_Frame_View* frame_view = node ? &node->frame_view : nullptr;
if (!frame_view) {
local_frame_view = d_ptr->capture_frame_view();
frame_view = &local_frame_view;
}
if (!*frame_view)
return;
Renderable_Cache_Mode mode = get_cache_mode();
std::uint64_t begin_time = steady_now_ns();
draw(canvas, snapshot, *frame_view);
std::uint64_t draw_time = steady_now_ns() - begin_time;
if (snapshot.frame_metadata) {
const std::string& parent_name = node ? node->parent_object_name : render_parent_object_name();
int depth = node ? node->render_tree_depth : render_tree_depth();
snapshot.frame_metadata->record_renderable_self_draw(node ? node->node_id : node_id_, node ? node->parent_node_id : 0, node ? node->object_name : object_name_, parent_name, depth, mode, draw_time);
}
}
void Renderable::draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) {
if (get_retiring())
return;
d_ptr->draw(canvas, snapshot, frame_view);
}
void Renderable::prepare_data(const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) {
if (get_retiring())
return;
if (!frame_view)
return;
d_ptr->prepare_data(snapshot, frame_view);
}
void build_renderable_prepare(
Renderable& renderable,
Render_Task_Subflow& subflow,
const Render_Frame_Snapshot& snapshot,
const Renderable_Frame_View& frame_view) {
if (renderable.get_retiring() || !frame_view || !renderable.d_ptr)
return;
if (auto* source = dynamic_cast<Frame_Prepare_Subtask_Source*>(renderable.d_ptr)) {
if (source->build_prepare_subtasks(subflow, snapshot, frame_view))
return;
}
renderable.prepare_data(snapshot, frame_view);
}
void drain_renderable_prepare_updates(Renderable& renderable, std::pmr::vector<std::shared_ptr<Update_State>>& output) {
if (renderable.get_retiring() || !renderable.d_ptr)
return;
renderable.d_ptr->drain_committed_update_states(output);
}
bool Renderable::select_test(const PointF& pos) {
if (get_retiring())
return false;
auto* hit_testable = dynamic_cast<Hit_Testable*>(d_ptr);
return hit_testable && hit_testable->select_test(pos);
}
void Renderable::plot_event(const Event& event) {
if (get_retiring() || event.is_accepted())
return;
switch (event.type) {
case Event_Type::Resize:
resize_event(static_cast<const Resize_Event&>(event));
break;
case Event_Type::Pointer_Move:
mouse_move_event(static_cast<const Pointer_Event&>(event));
break;
case Event_Type::Pointer_Press:
mouse_press_event(static_cast<const Pointer_Event&>(event));
break;
case Event_Type::Pointer_Release:
mouse_release_event(static_cast<const Pointer_Event&>(event));
break;
case Event_Type::Wheel:
wheel_event(static_cast<const Wheel_Event&>(event));
break;
case Event_Type::Key_Press:
key_press_event(static_cast<const Key_Event&>(event));
break;
case Event_Type::Key_Release:
key_release_event(static_cast<const Key_Event&>(event));
break;
default:
break;
}
}
void Renderable::mouse_press_event(const Pointer_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
if (interactive)
interactive->mouse_press_event(event);
}
void Renderable::mouse_move_event(const Pointer_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
if (interactive)
interactive->mouse_move_event(event);
}
void Renderable::mouse_release_event(const Pointer_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
if (interactive)
interactive->mouse_release_event(event);
}
void Renderable::set_hover_state(Point pos, bool active) {
if (get_retiring())
return;
auto* interactive = dynamic_cast<Hover_Interactive*>(d_ptr);
if (interactive)
interactive->set_hover_state(pos, active);
}
void Renderable::key_press_event(const Key_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Key_Press_Interactive*>(d_ptr);
if (interactive)
interactive->key_press_event(event);
}
void Renderable::key_release_event(const Key_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Key_Release_Interactive*>(d_ptr);
if (interactive)
interactive->key_release_event(event);
}
void Renderable::resize_event(const Resize_Event& event) {
if (get_retiring())
return;
(void)event;
}
void Renderable::wheel_event(const Wheel_Event& event) {
if (get_retiring() || event.is_accepted())
return;
auto* interactive = dynamic_cast<Wheel_Interactive*>(d_ptr);
if (interactive)
interactive->wheel_event(event);
}
void Renderable::mark_render_dirty(Dirty_Reason reason) {
if (get_retiring())
return;
auto context = plot_context.lock();
if (!context || context->destroying.load(std::memory_order_acquire))
return;
cache_edit_version.fetch_add(1, std::memory_order_acq_rel);
if (auto parent = parent_renderable.lock()) {
parent->mark_render_dirty(reason);
return;
}
Plot_Core* target_plot = context->owner.load(std::memory_order_acquire);
if (!context->destroying.load(std::memory_order_acquire) && target_plot)
target_plot->notify_model_dirty(reason);
}
bool Renderable::ok() const {
auto context = plot_context.lock();
return d_ptr && initialized.load(std::memory_order_acquire) && !get_retiring() && context && !context->destroying.load(std::memory_order_acquire);
}
bool Renderable::get_retiring() const {
return retiring.load(std::memory_order_acquire);
}
void Renderable::detach_from_plot_tree() {
bool was_retiring = retiring.exchange(true, std::memory_order_acq_rel);
if (was_retiring && plot == nullptr)
return;
if (d_ptr)
d_ptr->cancel_pending_completions();
std::vector<std::shared_ptr<Renderable>> detached_children;
{
std::lock_guard<std::mutex> lock(children_mutex);
detached_children = std::move(children);
for (const auto& child : detached_children) {
if (child)
child->parent_renderable.reset();
}
children.clear();
}
for (const auto& child : detached_children) {
if (child)
child->detach_from_plot_tree();
}
plot = nullptr;
cache_image.clear();
cache_bounds = {};
}
Renderable::~Renderable() {
detach_from_plot_tree();
d_owner.reset();
d_ptr = nullptr;
}
} // namespace renderive