256 lines
8.4 KiB
C++
256 lines
8.4 KiB
C++
#pragma once
|
|
#include <QImage>
|
|
#include <QRect>
|
|
#include <QRegion>
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include "Render_Config.h"
|
|
#include "Plot_Render_Context.h"
|
|
#include "global.h"
|
|
class QEvent;
|
|
class QKeyEvent;
|
|
class QMouseEvent;
|
|
class QPainter;
|
|
class QPointF;
|
|
class QResizeEvent;
|
|
class QWheelEvent;
|
|
namespace YSG {
|
|
struct Render_Data;
|
|
struct Renderable;
|
|
struct Input_Data {
|
|
virtual ~Input_Data() = default;
|
|
virtual void clear() {
|
|
}
|
|
virtual std::uint64_t pending_count() const {
|
|
return 0;
|
|
}
|
|
virtual std::uint64_t dropped_count() const {
|
|
return 0;
|
|
}
|
|
virtual std::uint64_t capacity_dropped_count() const {
|
|
return 0;
|
|
}
|
|
virtual std::uint64_t rebuild_dropped_count() const {
|
|
return 0;
|
|
}
|
|
virtual std::uint64_t consumer_dropped_count() const {
|
|
return 0;
|
|
}
|
|
virtual std::uint64_t pushed_count() const {
|
|
return 0;
|
|
}
|
|
};
|
|
struct Render_State {
|
|
virtual ~Render_State() = default;
|
|
std::uint64_t version = 0;
|
|
Render_Data* dPtr{};
|
|
SRC src();
|
|
};
|
|
struct Input_Buffer_Slot {
|
|
Input_Data* data{};
|
|
std::uint64_t version = 0;
|
|
bool pending = false;
|
|
};
|
|
struct Render_Data {
|
|
Render_Data() {
|
|
mStateControl.set_stats(&mStateBufferStats);
|
|
mInputControl.set_stats(&mInputBufferStats);
|
|
}
|
|
Renderable* qPtr{};
|
|
bool mRenderStart = false;
|
|
Triple_Role_Buffer_Control mStateControl;
|
|
Triple_Buffer_Stats mStateBufferStats;
|
|
std::array<Render_State*, 3> mStateBuffers{};
|
|
Triple_Role_Buffer_Control mInputControl;
|
|
Triple_Buffer_Stats mInputBufferStats;
|
|
std::array<Input_Buffer_Slot, 3> mInputBuffers{};
|
|
std::uint64_t mInputVersion = 0;
|
|
std::atomic<Plot_Buffer_Acquire_Mode> mBufferAcquireMode{Plot_Buffer_Acquire_Mode::Wait};
|
|
std::atomic<RenderAble_Render_Schedule_Mode> mRenderScheduleMode{RenderAble_Render_Schedule_Mode::Inherit};
|
|
std::atomic<double> mRenderScheduleMaxFps{0.0};
|
|
std::atomic<std::uint64_t> mNextRenderSubmitNs{0};
|
|
Render_State* state(std::uint8_t role) const {
|
|
return state_by_index(mStateControl.read_view()[role]);
|
|
}
|
|
Render_State* state(SRC src) const {
|
|
return state(static_cast<std::uint8_t>(src));
|
|
}
|
|
Render_State* state_by_index(std::uint8_t index) const {
|
|
return mStateBuffers[index];
|
|
}
|
|
Plot_Buffer_Acquire_Mode buffer_acquire_mode() const {
|
|
return mBufferAcquireMode.load(std::memory_order_acquire);
|
|
}
|
|
void set_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) {
|
|
mBufferAcquireMode.store(mode, std::memory_order_release);
|
|
}
|
|
RenderAble_Render_Schedule_Mode render_schedule_mode() const {
|
|
return mRenderScheduleMode.load(std::memory_order_acquire);
|
|
}
|
|
void set_render_schedule_mode(RenderAble_Render_Schedule_Mode mode) {
|
|
mRenderScheduleMode.store(mode, std::memory_order_release);
|
|
}
|
|
double render_schedule_max_fps() const {
|
|
return mRenderScheduleMaxFps.load(std::memory_order_acquire);
|
|
}
|
|
void set_render_schedule_max_fps(double fps) {
|
|
mRenderScheduleMaxFps.store(fps, std::memory_order_release);
|
|
}
|
|
Triple_Buffer_Lease mark_state_role(std::uint8_t role) {
|
|
if (buffer_acquire_mode() == Plot_Buffer_Acquire_Mode::Wait) {
|
|
return mStateControl.wait_mark_use_role(role);
|
|
}
|
|
auto record = mStateControl.try_mark_use_role(role);
|
|
if (record.result != Triple_Buffer_Result::Success) {
|
|
return {};
|
|
}
|
|
return record.lease;
|
|
}
|
|
void unmark_state(Triple_Buffer_Lease lease) {
|
|
mStateControl.unmark_use(lease);
|
|
}
|
|
void clear_state_buffers() {
|
|
for (Render_State*& state : mStateBuffers) {
|
|
delete state;
|
|
state = nullptr;
|
|
}
|
|
mStateControl.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 mInputBuffers[index].data;
|
|
}
|
|
Input_Buffer_Slot& input_slot(std::uint8_t role) {
|
|
return input_slot_by_index(mInputControl.read_view()[role]);
|
|
}
|
|
const Input_Buffer_Slot& input_slot(std::uint8_t role) const {
|
|
return input_slot_by_index(mInputControl.read_view()[role]);
|
|
}
|
|
Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) {
|
|
return mInputBuffers[index];
|
|
}
|
|
const Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) const {
|
|
return mInputBuffers[index];
|
|
}
|
|
bool has_pending_state() const {
|
|
auto view = mStateControl.read_view();
|
|
return buffer_version_newer(mStateBuffers[view[State_Edit]]->version, mStateBuffers[view[State_Render]]->version);
|
|
}
|
|
bool has_pending_input() const {
|
|
auto view = mInputControl.read_view();
|
|
const Input_Buffer_Slot& edit = mInputBuffers[view[Input_Edit]];
|
|
const Input_Buffer_Slot& ready = mInputBuffers[view[Input_Ready]];
|
|
const Input_Buffer_Slot& render = mInputBuffers[view[Input_Render]];
|
|
return (edit.pending && buffer_version_newer(edit.version, render.version)) || (ready.pending && buffer_version_newer(ready.version, render.version));
|
|
}
|
|
bool has_pending_render_data() const {
|
|
return has_pending_state() || has_pending_input();
|
|
}
|
|
void mark_input_dirty(Triple_Buffer_Lease lease, bool notifyRender = true);
|
|
void clear_input_role(std::uint8_t role) {
|
|
Input_Buffer_Slot& slot = input_slot(role);
|
|
slot.data->clear();
|
|
slot.pending = false;
|
|
}
|
|
void clear_render_input() {
|
|
clear_input_role(Input_Render);
|
|
}
|
|
void clear_input_buffers() {
|
|
for (Input_Buffer_Slot& slot : mInputBuffers) {
|
|
delete slot.data;
|
|
slot.data = nullptr;
|
|
slot.version = 0;
|
|
slot.pending = false;
|
|
}
|
|
mInputVersion = 0;
|
|
mInputControl.reset();
|
|
}
|
|
public:
|
|
/// 同步 State/Input 的 ready 角色到 render 角色。
|
|
virtual void sync_state_pipeline() = 0;
|
|
/// 返回 render 角色 State。
|
|
virtual Render_State* render_state() = 0;
|
|
/// 返回 ready 角色 State。
|
|
virtual Render_State* ready_state() = 0;
|
|
/// 返回 edit 角色 State。
|
|
virtual Render_State* edit_state() = 0;
|
|
/// 返回 render 角色 Input。
|
|
virtual Input_Data* render_input_data() = 0;
|
|
/// 返回 edit 角色 Input。
|
|
virtual Input_Data* edit_input_data() = 0;
|
|
virtual ~Render_Data() {
|
|
clear_state_buffers();
|
|
clear_input_buffers();
|
|
}
|
|
/// 绘制当前已准备好的数据。
|
|
virtual void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) {
|
|
}
|
|
/// 准备当前帧数据,默认只同步三缓冲管线。
|
|
virtual void prepare_data(const Plot_Render_Snapshot& snapshot) {
|
|
sync_state_pipeline();
|
|
}
|
|
virtual QRect pixel_bounds(const QSize& plotSize) {
|
|
return QRect(QPoint(0, 0), plotSize);
|
|
}
|
|
/// 判断指定坐标是否命中对象。
|
|
virtual bool select_test(const QPointF& pos) {
|
|
return false;
|
|
}
|
|
virtual void plot_event(QEvent* event) {
|
|
}
|
|
virtual void mousePressEvent(QMouseEvent* event) {
|
|
}
|
|
virtual void mouseMoveEvent(QMouseEvent* event) {
|
|
}
|
|
virtual void mouseReleaseEvent(QMouseEvent* event) {
|
|
}
|
|
virtual void set_hover_state(const QPoint& pos, bool active) {
|
|
}
|
|
virtual void keyPressEvent(QKeyEvent* event) {
|
|
}
|
|
virtual void keyReleaseEvent(QKeyEvent* event) {
|
|
}
|
|
virtual void first_resize_event(QResizeEvent* event) {
|
|
}
|
|
virtual void resizeEvent(QResizeEvent* event) {
|
|
}
|
|
virtual void wheelEvent(QWheelEvent* event) {
|
|
}
|
|
};
|
|
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 Abs_Plot;
|
|
struct LIB_DECL Render_Edit_Guard {
|
|
Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease);
|
|
~Render_Edit_Guard();
|
|
Render_Data* mData{};
|
|
Triple_Buffer_Lease mLease{};
|
|
};
|
|
struct LIB_DECL Render_Input_Guard {
|
|
Render_Input_Guard(Render_Data* data, Triple_Buffer_Lease lease);
|
|
~Render_Input_Guard();
|
|
Render_Data* mData{};
|
|
Triple_Buffer_Lease mLease{};
|
|
};
|
|
} // namespace YSG
|