Files
Renderive/Core/architecture/Render_Data.h
T
2026-08-02 12:48:37 +08:00

247 lines
8.5 KiB
C++

#pragma once
#include "../base/Geometry.h"
#include "../base/Object_Semantics.h"
#include "../event/Event.h"
#include "../event/Key_Event.h"
#include "../event/Pointer_Event.h"
#include "../event/Resize_Event.h"
#include "../event/Wheel_Event.h"
#include "../render/Canvas.h"
#include "Buffer_Role.h"
#include "Plot_Render_Context.h"
#include "Render_Config.h"
#include "Triple_Buffer.h"
#include "Update_Completion.h"
#include "global.h"
#include <array>
#include <atomic>
#include <cstdint>
#include <memory_resource>
#include <type_traits>
#include <utility>
namespace renderive {
struct Render_Data;
struct Renderable;
struct Input_Data {
virtual ~Input_Data() = default;
virtual void clear() {}
};
struct Latest_Input_Data : Input_Data {
bool pending = false;
void mark_latest_pushed() {
pending = true;
}
void clear_latest() {
pending = false;
}
};
struct Render_State {
virtual ~Render_State() = default;
std::uint64_t version = 0;
};
struct Hit_Testable {
virtual ~Hit_Testable() = default;
virtual bool select_test(const PointF& pos) = 0;
};
struct Pointer_Interactive {
virtual ~Pointer_Interactive() = default;
virtual void mouse_press_event(const Pointer_Event& event) = 0;
virtual void mouse_move_event(const Pointer_Event& event) = 0;
virtual void mouse_release_event(const Pointer_Event& event) = 0;
};
struct Wheel_Interactive {
virtual ~Wheel_Interactive() = default;
virtual void wheel_event(const Wheel_Event& event) = 0;
};
struct Key_Press_Interactive {
virtual ~Key_Press_Interactive() = default;
virtual void key_press_event(const Key_Event& event) = 0;
};
struct Key_Release_Interactive {
virtual ~Key_Release_Interactive() = default;
virtual void key_release_event(const Key_Event& event) = 0;
};
struct Hover_Interactive {
virtual ~Hover_Interactive() = default;
virtual void set_hover_state(Point pos, bool active) = 0;
};
struct Render_Object_Owner : Move_Only {
Render_Object_Owner() noexcept = default;
Render_Object_Owner(void* pointer, std::pmr::memory_resource* resource, void (*destroy)(void*, std::pmr::memory_resource*)) noexcept : pointer(pointer), resource(resource), destroy(destroy) {}
Render_Object_Owner(Render_Object_Owner&& other) noexcept : pointer(std::exchange(other.pointer, nullptr)), resource(std::exchange(other.resource, nullptr)), destroy(std::exchange(other.destroy, nullptr)) {}
Render_Object_Owner& operator=(Render_Object_Owner&& other) noexcept {
if (this == &other)
return *this;
reset();
pointer = std::exchange(other.pointer, nullptr);
resource = std::exchange(other.resource, nullptr);
destroy = std::exchange(other.destroy, nullptr);
return *this;
}
~Render_Object_Owner() {
reset();
}
template <typename T>
T* get() const {
return static_cast<T*>(pointer);
}
void reset() noexcept {
if (!pointer)
return;
destroy(pointer, resource);
pointer = nullptr;
resource = nullptr;
destroy = nullptr;
}
explicit operator bool() const noexcept {
return pointer != nullptr;
}
void* pointer{};
std::pmr::memory_resource* resource{};
void (*destroy)(void*, std::pmr::memory_resource*){};
};
template <typename T, typename... Args>
Render_Object_Owner make_render_object(Args&&... args) {
std::pmr::memory_resource* resource = memory_resource(Memory_Domain::Renderable);
std::pmr::polymorphic_allocator<T> allocator(resource);
T* pointer = allocator.allocate(1);
try {
std::construct_at(pointer, std::forward<Args>(args)...);
}
catch (...) {
allocator.deallocate(pointer, 1);
throw;
}
return Render_Object_Owner(pointer, resource, [](void* object, std::pmr::memory_resource* resource) {
std::pmr::polymorphic_allocator<T> allocator(resource);
std::destroy_at(static_cast<T*>(object));
allocator.deallocate(static_cast<T*>(object), 1);
});
}
struct Input_Buffer_Slot {
Input_Data* data{};
std::uint64_t version = 0;
bool pending = false;
std::shared_ptr<Update_State> completion_state;
};
struct Render_Data {
Renderable* q_ptr{};
Triple_Role_Buffer_Control state_control;
std::array<Render_State*, 3> state_buffers{};
std::array<Render_Object_Owner, 3> state_buffer_owners{};
Triple_Role_Buffer_Control input_control;
std::array<Input_Buffer_Slot, 3> input_buffers{};
std::array<Render_Object_Owner, 3> input_buffer_owners{};
std::pmr::vector<std::shared_ptr<Update_State>> committed_update_states{memory_resource(Memory_Domain::Update_Completion)};
std::uint64_t input_version = 0;
Render_State* state(std::uint8_t role) const {
return state_by_index(state_control.read_view()[role]);
}
Render_State* state(State_Role src) const {
return state(static_cast<std::uint8_t>(src));
}
Render_State* state_by_index(std::uint8_t index) const {
return state_buffers[index];
}
Triple_Buffer_Lease try_mark_state_role(std::uint8_t role) {
auto record = state_control.try_acquire_role(role);
if (record.result != Triple_Buffer_Result::Success)
return {};
return record.lease;
}
void unmark_state(Triple_Buffer_Lease lease) {
state_control.unmark_use(lease);
}
void clear_state_buffers() {
state_control.close();
for (std::size_t i = 0; i < state_buffers.size(); ++i) {
state_buffer_owners[i].reset();
state_buffers[i] = nullptr;
}
state_control.reset();
}
Input_Data* input_data(std::uint8_t role) const {
return input_slot(role).data;
}
Input_Data* input_data_by_index(std::uint8_t index) const {
return input_buffers[index].data;
}
Input_Buffer_Slot& input_slot(std::uint8_t role) {
return input_slot_by_index(input_control.read_view()[role]);
}
const Input_Buffer_Slot& input_slot(std::uint8_t role) const {
return input_slot_by_index(input_control.read_view()[role]);
}
Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) {
return input_buffers[index];
}
const Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) const {
return input_buffers[index];
}
void mark_input_dirty(Triple_Buffer_Lease lease, bool notify_render = true);
void set_input_completion(Triple_Buffer_Lease lease, std::shared_ptr<Update_State> state);
void drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output);
void clear_input_role(std::uint8_t role);
void clear_render_input() {
clear_input_role(Input_Render);
}
void clear_input_buffers() {
input_control.close();
cancel_pending_completions();
for (std::size_t i = 0; i < input_buffers.size(); ++i) {
input_buffer_owners[i].reset();
input_buffers[i].data = nullptr;
input_buffers[i].version = 0;
input_buffers[i].pending = false;
input_buffers[i].completion_state.reset();
}
input_version = 0;
input_control.reset();
}
void cancel_pending_completions();
public:
virtual void sync_state_pipeline() = 0;
virtual Render_State* render_state() = 0;
virtual Render_State* ready_state() = 0;
virtual Render_State* edit_state() = 0;
virtual Input_Data* render_input_data() = 0;
virtual Input_Data* edit_input_data() = 0;
virtual ~Render_Data() {
clear_state_buffers();
clear_input_buffers();
}
virtual void draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {}
virtual void prepare_data(const Plot_Render_Snapshot& snapshot) {
sync_state_pipeline();
}
virtual Rect pixel_bounds(const Size& plot_size) {
return {0, 0, plot_size.width, plot_size.height};
}
};
struct Base_Render_Data : Render_Data {
Render_State* render_state() override {
return nullptr;
}
Render_State* ready_state() override {
return nullptr;
}
Render_State* edit_state() override {
return nullptr;
}
Input_Data* render_input_data() override {
return nullptr;
}
Input_Data* edit_input_data() override {
return nullptr;
}
void sync_state_pipeline() override {}
};
class Plot_Core;
struct LIB_DECL Render_Edit_Guard {
Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease);
~Render_Edit_Guard();
Render_Data* data{};
Triple_Buffer_Lease lease{};
};
} // namespace renderive