574 lines
26 KiB
C++
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
|