652 lines
27 KiB
C++
652 lines
27 KiB
C++
#pragma once
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <qlinkedlist.h>
|
|
#include <QImage>
|
|
#include <QRegion>
|
|
#include <qscreen.h>
|
|
#include "GlobalTypes.h"
|
|
namespace YSG {
|
|
static constexpr std::uint8_t triple_buffer_invalid_index = 255;
|
|
enum class Triple_Buffer_Result : std::uint8_t {
|
|
Success,
|
|
Busy,
|
|
State_Changed,
|
|
Condition_Failed
|
|
};
|
|
enum class Triple_Buffer_Mode : std::uint8_t {
|
|
Try,
|
|
Wait
|
|
};
|
|
struct Triple_Buffer_View {
|
|
std::array<std::uint8_t, 3> index{};
|
|
std::uint8_t operator[](std::uint8_t role) const {
|
|
return index[role];
|
|
}
|
|
};
|
|
struct Triple_Buffer_Lease {
|
|
std::uint8_t index = triple_buffer_invalid_index;
|
|
explicit operator bool() const {
|
|
return index != triple_buffer_invalid_index;
|
|
}
|
|
};
|
|
struct Triple_Buffer_Mark_Record {
|
|
Triple_Buffer_Result result = Triple_Buffer_Result::Condition_Failed;
|
|
Triple_Buffer_Lease lease{};
|
|
std::uint8_t busy_index = triple_buffer_invalid_index;
|
|
};
|
|
struct Triple_Buffer_Swap_Record {
|
|
Triple_Buffer_Result result = Triple_Buffer_Result::Condition_Failed;
|
|
Triple_Buffer_View old_view{};
|
|
Triple_Buffer_View new_view{};
|
|
std::uint8_t busy_index = triple_buffer_invalid_index;
|
|
};
|
|
struct alignas(64) Triple_Buffer_Busy {
|
|
std::atomic_bool busy{false};
|
|
};
|
|
class Triple_Role_Buffer_Control {
|
|
public:
|
|
void reset() {
|
|
slot_state.store(0, std::memory_order_release);
|
|
for(auto& item : buffer_busy) {
|
|
item.busy.store(false, std::memory_order_release);
|
|
item.busy.notify_all();
|
|
}
|
|
slot_state.notify_all();
|
|
}
|
|
Triple_Buffer_View read_view() const {
|
|
return decode_order(slot_state.load(std::memory_order_acquire));
|
|
}
|
|
Triple_Buffer_Mark_Record try_mark_use_index(std::uint8_t index) {
|
|
if(!try_mark_index(index)) {
|
|
return {Triple_Buffer_Result::Busy, {}, index};
|
|
}
|
|
return {Triple_Buffer_Result::Success, {index}, triple_buffer_invalid_index};
|
|
}
|
|
Triple_Buffer_Lease wait_mark_use_index(std::uint8_t index) {
|
|
for(;;) {
|
|
if(try_mark_index(index)) {
|
|
return {index};
|
|
}
|
|
wait_index_free(index);
|
|
}
|
|
}
|
|
Triple_Buffer_Mark_Record try_mark_use_role(std::uint8_t role) {
|
|
auto order = slot_state.load(std::memory_order_acquire);
|
|
auto view = decode_order(order);
|
|
auto index = view[role];
|
|
if(!try_mark_index(index)) {
|
|
return {Triple_Buffer_Result::Busy, {}, index};
|
|
}
|
|
auto cur_order = slot_state.load(std::memory_order_acquire);
|
|
if(cur_order != order) {
|
|
unmark_index(index);
|
|
return {Triple_Buffer_Result::State_Changed, {}, triple_buffer_invalid_index};
|
|
}
|
|
return {Triple_Buffer_Result::Success, {index}, triple_buffer_invalid_index};
|
|
}
|
|
Triple_Buffer_Lease wait_mark_use_role(std::uint8_t role) {
|
|
for(;;) {
|
|
auto record = try_mark_use_role(role);
|
|
if(record.result == Triple_Buffer_Result::Success) {
|
|
return record.lease;
|
|
}
|
|
if(record.result == Triple_Buffer_Result::Busy) {
|
|
wait_index_free(record.busy_index);
|
|
}
|
|
}
|
|
}
|
|
void unmark_use(Triple_Buffer_Lease lease) {
|
|
unmark_index(lease.index);
|
|
}
|
|
template <typename Can_Swap>
|
|
Triple_Buffer_Swap_Record try_swap_role(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap) {
|
|
std::uint8_t busy_index = triple_buffer_invalid_index;
|
|
return try_swap_role_once(left_role, right_role, can_swap, busy_index);
|
|
}
|
|
template <typename Can_Swap>
|
|
Triple_Buffer_Swap_Record wait_swap_role(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap) {
|
|
for(;;) {
|
|
std::uint8_t busy_index = triple_buffer_invalid_index;
|
|
auto record = try_swap_role_once(left_role, right_role, can_swap, busy_index);
|
|
if(record.result == Triple_Buffer_Result::Success || record.result == Triple_Buffer_Result::Condition_Failed) {
|
|
return record;
|
|
}
|
|
if(record.result == Triple_Buffer_Result::Busy) {
|
|
wait_index_free(busy_index);
|
|
} else {
|
|
slot_state.wait(encode_order(record.old_view), std::memory_order_acquire);
|
|
}
|
|
}
|
|
}
|
|
private:
|
|
std::atomic<std::uint8_t> slot_state{0};
|
|
std::array<Triple_Buffer_Busy, 3> buffer_busy{};
|
|
static Triple_Buffer_View decode_order(std::uint8_t order) {
|
|
switch(order) {
|
|
case 0:
|
|
return {{0, 1, 2}};
|
|
case 1:
|
|
return {{0, 2, 1}};
|
|
case 2:
|
|
return {{1, 0, 2}};
|
|
case 3:
|
|
return {{1, 2, 0}};
|
|
case 4:
|
|
return {{2, 0, 1}};
|
|
case 5:
|
|
return {{2, 1, 0}};
|
|
}
|
|
return {{0, 1, 2}};
|
|
}
|
|
static std::uint8_t encode_order(const Triple_Buffer_View& view) {
|
|
if(view.index[0] == 0) {
|
|
return view.index[1] == 1 ? 0 : 1;
|
|
}
|
|
if(view.index[0] == 1) {
|
|
return view.index[1] == 0 ? 2 : 3;
|
|
}
|
|
return view.index[1] == 0 ? 4 : 5;
|
|
}
|
|
static std::uint8_t swap_order(std::uint8_t order, std::uint8_t left_role, std::uint8_t right_role) {
|
|
auto view = decode_order(order);
|
|
auto temp = view.index[left_role];
|
|
view.index[left_role] = view.index[right_role];
|
|
view.index[right_role] = temp;
|
|
return encode_order(view);
|
|
}
|
|
bool try_mark_index(std::uint8_t index) {
|
|
bool expected = false;
|
|
return buffer_busy[index].busy.compare_exchange_strong(expected, true, std::memory_order_acq_rel, std::memory_order_acquire);
|
|
}
|
|
void unmark_index(std::uint8_t index) {
|
|
buffer_busy[index].busy.store(false, std::memory_order_release);
|
|
buffer_busy[index].busy.notify_all();
|
|
}
|
|
void wait_index_free(std::uint8_t index) {
|
|
while(buffer_busy[index].busy.load(std::memory_order_acquire)) {
|
|
buffer_busy[index].busy.wait(true, std::memory_order_acquire);
|
|
}
|
|
}
|
|
bool try_mark_two_indices(std::uint8_t left_index, std::uint8_t right_index, std::uint8_t& busy_index) {
|
|
if(left_index == right_index) {
|
|
if(!try_mark_index(left_index)) {
|
|
busy_index = left_index;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
auto first = left_index < right_index ? left_index : right_index;
|
|
auto second = left_index < right_index ? right_index : left_index;
|
|
if(!try_mark_index(first)) {
|
|
busy_index = first;
|
|
return false;
|
|
}
|
|
if(!try_mark_index(second)) {
|
|
unmark_index(first);
|
|
busy_index = second;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
void unmark_two_indices(std::uint8_t left_index, std::uint8_t right_index) {
|
|
if(left_index == right_index) {
|
|
unmark_index(left_index);
|
|
return;
|
|
}
|
|
unmark_index(left_index);
|
|
unmark_index(right_index);
|
|
}
|
|
template <typename Can_Swap>
|
|
Triple_Buffer_Swap_Record try_swap_role_once(std::uint8_t left_role, std::uint8_t right_role, Can_Swap can_swap, std::uint8_t& busy_index) {
|
|
auto old_order = slot_state.load(std::memory_order_acquire);
|
|
auto old_view = decode_order(old_order);
|
|
auto left_index = old_view[left_role];
|
|
auto right_index = old_view[right_role];
|
|
if(!try_mark_two_indices(left_index, right_index, busy_index)) {
|
|
return {Triple_Buffer_Result::Busy, old_view, old_view, busy_index};
|
|
}
|
|
auto cur_order = slot_state.load(std::memory_order_acquire);
|
|
if(cur_order != old_order) {
|
|
auto cur_view = decode_order(cur_order);
|
|
unmark_two_indices(left_index, right_index);
|
|
return {Triple_Buffer_Result::State_Changed, old_view, cur_view, triple_buffer_invalid_index};
|
|
}
|
|
if(!can_swap(old_view)) {
|
|
unmark_two_indices(left_index, right_index);
|
|
return {Triple_Buffer_Result::Condition_Failed, old_view, old_view, triple_buffer_invalid_index};
|
|
}
|
|
auto new_order = swap_order(old_order, left_role, right_role);
|
|
auto new_view = decode_order(new_order);
|
|
auto expected = old_order;
|
|
if(!slot_state.compare_exchange_strong(expected, new_order, std::memory_order_acq_rel, std::memory_order_acquire)) {
|
|
auto cur_view = decode_order(expected);
|
|
unmark_two_indices(left_index, right_index);
|
|
return {Triple_Buffer_Result::State_Changed, old_view, cur_view, triple_buffer_invalid_index};
|
|
}
|
|
unmark_two_indices(left_index, right_index);
|
|
slot_state.notify_all();
|
|
return {Triple_Buffer_Result::Success, old_view, new_view, triple_buffer_invalid_index};
|
|
}
|
|
};
|
|
enum State_Role : std::uint8_t {
|
|
State_Edit,
|
|
State_Ready,
|
|
State_Render
|
|
};
|
|
enum Input_Role : std::uint8_t {
|
|
Input_Edit,
|
|
Input_Ready,
|
|
Input_Render
|
|
};
|
|
enum Color_Role : std::uint8_t {
|
|
Color_Front,
|
|
Color_Ready,
|
|
Color_Render
|
|
};
|
|
inline bool buffer_version_newer(std::uint64_t a, std::uint64_t b) {
|
|
return static_cast<std::int64_t>(a - b) > 0;
|
|
}
|
|
#define INIT_GET(className) className##Private* privateData = d(); \
|
|
className##RenderState* renderState = reinterpret_cast<className##RenderState*>(d()->state(src));
|
|
struct InputData {
|
|
virtual ~InputData() = default;
|
|
virtual void clear() {}
|
|
};
|
|
struct RenderState {
|
|
virtual ~RenderState() = default;
|
|
std::uint64_t version = 0;
|
|
RenderData* dPtr{};
|
|
SRC src();
|
|
};
|
|
struct InputBufferSlot {
|
|
InputData* data{};
|
|
std::uint64_t version = 0;
|
|
bool pending = false;
|
|
};
|
|
struct RenderData {
|
|
RenderAble* qPtr{};
|
|
bool mRenderStart = false;
|
|
Triple_Role_Buffer_Control mStateControl;
|
|
std::array<RenderState*, 3> mStateBuffers{};
|
|
Triple_Role_Buffer_Control mInputControl;
|
|
std::array<InputBufferSlot, 3> mInputBuffers{};
|
|
std::uint64_t mInputVersion = 0;
|
|
std::atomic<Triple_Buffer_Mode> mBufferAcquireMode{Triple_Buffer_Mode::Wait};
|
|
RenderState* state(std::uint8_t role) const {
|
|
return stateByIndex(mStateControl.read_view()[role]);
|
|
}
|
|
RenderState* state(SRC src) const {
|
|
return state(static_cast<std::uint8_t>(src));
|
|
}
|
|
RenderState* stateByIndex(std::uint8_t index) const {
|
|
return mStateBuffers[index];
|
|
}
|
|
Triple_Buffer_Mode bufferAcquireMode() const {
|
|
return mBufferAcquireMode.load(std::memory_order_acquire);
|
|
}
|
|
void setBufferAcquireMode(Triple_Buffer_Mode mode) {
|
|
mBufferAcquireMode.store(mode, std::memory_order_release);
|
|
}
|
|
Triple_Buffer_Lease markStateRole(std::uint8_t role) {
|
|
if(bufferAcquireMode() == Triple_Buffer_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 unmarkState(Triple_Buffer_Lease lease) {
|
|
mStateControl.unmark_use(lease);
|
|
}
|
|
void clearStateBuffers() {
|
|
for(RenderState*& state : mStateBuffers) {
|
|
delete state;
|
|
state = nullptr;
|
|
}
|
|
mStateControl.reset();
|
|
}
|
|
InputData* inputData(std::uint8_t role) const {
|
|
return inputSlot(role).data;
|
|
}
|
|
InputData* inputDataByIndex(std::uint8_t index) const {
|
|
return mInputBuffers[index].data;
|
|
}
|
|
InputBufferSlot& inputSlot(std::uint8_t role) {
|
|
return inputSlotByIndex(mInputControl.read_view()[role]);
|
|
}
|
|
const InputBufferSlot& inputSlot(std::uint8_t role) const {
|
|
return inputSlotByIndex(mInputControl.read_view()[role]);
|
|
}
|
|
InputBufferSlot& inputSlotByIndex(std::uint8_t index) {
|
|
return mInputBuffers[index];
|
|
}
|
|
const InputBufferSlot& inputSlotByIndex(std::uint8_t index) const {
|
|
return mInputBuffers[index];
|
|
}
|
|
void markInputDirty(Triple_Buffer_Lease lease);
|
|
void clearInputRole(std::uint8_t role) {
|
|
InputBufferSlot& slot = inputSlot(role);
|
|
slot.data->clear();
|
|
slot.pending = false;
|
|
}
|
|
void clearRenderInput() {
|
|
clearInputRole(Input_Render);
|
|
}
|
|
void clearInputBuffers() {
|
|
for(InputBufferSlot& slot : mInputBuffers) {
|
|
delete slot.data;
|
|
slot.data = nullptr;
|
|
slot.version = 0;
|
|
slot.pending = false;
|
|
}
|
|
mInputVersion = 0;
|
|
mInputControl.reset();
|
|
}
|
|
protected:
|
|
virtual void syncStatePipeline() = 0;
|
|
virtual RenderState* renderState() = 0;
|
|
virtual RenderState* readyState() = 0;
|
|
virtual RenderState* editState() = 0;
|
|
virtual InputData* renderInputData() = 0;
|
|
virtual InputData* editInputData() = 0;
|
|
virtual ~RenderData() {
|
|
clearStateBuffers();
|
|
clearInputBuffers();
|
|
}
|
|
virtual void draw(QPainter* painter) {}
|
|
virtual void prepareData() {
|
|
syncStatePipeline();
|
|
}
|
|
virtual bool selectTest(const QPointF& pos) {
|
|
return false;
|
|
}
|
|
virtual void plotEvent(QEvent* event) {}
|
|
virtual void mousePressEvent(QMouseEvent* event) {}
|
|
virtual void mouseMoveEvent(QMouseEvent* event) {}
|
|
virtual void mouseReleaseEvent(QMouseEvent* event) {}
|
|
virtual void setHoverState(const QPoint& pos, bool active) {}
|
|
virtual void keyPressEvent(QKeyEvent* event) {}
|
|
virtual void keyReleaseEvent(QKeyEvent* event) {}
|
|
virtual void firstResizeEvent(QResizeEvent* event) {}
|
|
virtual void resizeEvent(QResizeEvent* event) {}
|
|
virtual void wheelEvent(QWheelEvent* event) {}
|
|
friend struct RenderAble;
|
|
};
|
|
struct BaseRenderData : RenderData {
|
|
RenderState* renderState() override {
|
|
return nullptr;
|
|
}
|
|
RenderState* readyState() override {
|
|
return nullptr;
|
|
}
|
|
RenderState* editState() override {
|
|
return nullptr;
|
|
}
|
|
InputData* renderInputData() override {
|
|
return nullptr;
|
|
}
|
|
InputData* editInputData() override {
|
|
return nullptr;
|
|
}
|
|
void syncStatePipeline() override {}
|
|
};
|
|
class Plot;
|
|
struct LIB_DECL RenderEditGuard {
|
|
RenderEditGuard(RenderData* data, Triple_Buffer_Lease lease);
|
|
~RenderEditGuard();
|
|
RenderData* mData{};
|
|
Triple_Buffer_Lease mLease{};
|
|
};
|
|
struct LIB_DECL RenderInputGuard {
|
|
RenderInputGuard(RenderData* data, Triple_Buffer_Lease lease);
|
|
~RenderInputGuard();
|
|
RenderData* mData{};
|
|
Triple_Buffer_Lease mLease{};
|
|
};
|
|
struct RenderAble {
|
|
enum class JobState {
|
|
Idle,
|
|
Queued,
|
|
Running
|
|
};
|
|
struct ColorBuffer {
|
|
std::atomic<std::uint64_t> version{0};
|
|
QImage image;
|
|
QRegion dirtyRegion;
|
|
};
|
|
struct ColorBufferLease {
|
|
ColorBuffer* buffer{};
|
|
Triple_Buffer_Lease lease{};
|
|
explicit operator bool() const {
|
|
return buffer && lease;
|
|
}
|
|
};
|
|
struct RenderPipeline {
|
|
Triple_Role_Buffer_Control colorControl;
|
|
std::array<ColorBuffer, 3> colorBuffers;
|
|
std::atomic<std::uint64_t> editStateVersion{1};
|
|
std::uint64_t renderStateVersion = 0;
|
|
JobState jobState = JobState::Idle;
|
|
std::atomic_bool paintRequestPending{false};
|
|
RenderPipeline();
|
|
void markEditState();
|
|
bool hasNewState() const;
|
|
ColorBuffer* colorByIndex(std::uint8_t index);
|
|
ColorBuffer* colorByRole(std::uint8_t role);
|
|
ColorBufferLease waitRenderColor();
|
|
ColorBufferLease waitFrontColor();
|
|
ColorBufferLease tryFrontColor();
|
|
void unmarkColor(ColorBufferLease lease);
|
|
QRegion publishRenderColor();
|
|
ColorBufferLease consumeReadyColor(Triple_Buffer_Mode mode);
|
|
};
|
|
virtual RenderData* createRenderData() {
|
|
return new BaseRenderData;
|
|
}
|
|
virtual RenderState* createRenderState() {
|
|
return new RenderState;
|
|
}
|
|
virtual InputData* createInputData() {
|
|
return new InputData;
|
|
}
|
|
virtual void init(Plot* plot, QString layerName = "");
|
|
virtual void draw(QPainter* painter) {
|
|
dPtr->draw(painter);
|
|
}
|
|
virtual void prepareData() {
|
|
dPtr->prepareData();
|
|
}
|
|
virtual bool selectTest(const QPointF& pos) {
|
|
return dPtr->selectTest(pos);
|
|
}
|
|
virtual void plotEvent(QEvent* event) {
|
|
dPtr->plotEvent(event);
|
|
}
|
|
virtual void mousePressEvent(QMouseEvent* event) {
|
|
dPtr->mousePressEvent(event);
|
|
}
|
|
virtual void mouseMoveEvent(QMouseEvent* event) {
|
|
dPtr->mouseMoveEvent(event);
|
|
}
|
|
virtual void mouseReleaseEvent(QMouseEvent* event) {
|
|
dPtr->mouseReleaseEvent(event);
|
|
}
|
|
virtual void setHoverState(const QPoint& pos, bool active) {
|
|
dPtr->setHoverState(pos, active);
|
|
}
|
|
virtual void keyPressEvent(QKeyEvent* event) {
|
|
dPtr->keyPressEvent(event);
|
|
}
|
|
virtual void keyReleaseEvent(QKeyEvent* event) {
|
|
dPtr->keyReleaseEvent(event);
|
|
}
|
|
virtual void firstResizeEvent(QResizeEvent* event) {
|
|
dPtr->firstResizeEvent(event);
|
|
}
|
|
virtual void resizeEvent(QResizeEvent* event) {
|
|
dPtr->resizeEvent(event);
|
|
}
|
|
virtual void wheelEvent(QWheelEvent* event) {
|
|
dPtr->wheelEvent(event);
|
|
};
|
|
static bool version_newer(std::uint64_t a, std::uint64_t b) {
|
|
return buffer_version_newer(a, b);
|
|
}
|
|
Triple_Buffer_Mode bufferAcquireMode() const;
|
|
void setBufferAcquireMode(Triple_Buffer_Mode mode);
|
|
void markStateDirty();
|
|
void markRenderDirty();
|
|
QString mObjectName;
|
|
RenderData* dPtr{};
|
|
Plot* mPlot{};
|
|
[[nodiscard]] bool ok() const;
|
|
bool mPrepared = false;
|
|
// 这里面可以预先准备数据用来同步
|
|
virtual ~RenderAble();
|
|
virtual bool select(QPointF pos) {
|
|
return false;
|
|
}
|
|
bool mVisable = true;
|
|
RenderAble* mParent{};
|
|
QVector<RenderAble*> mBeRelyList;
|
|
bool dectCycleRely();
|
|
private:
|
|
bool hasCycleRely(RenderAble* node, QSet<RenderAble*>& visited, QSet<RenderAble*>& recursionStack, QVector<RenderAble*>& currentPath);
|
|
};
|
|
#define Q_Ptr2(ClassName) \
|
|
ClassName##Private* d() {return reinterpret_cast<ClassName##Private*>(dPtr);} \
|
|
RenderData* createRenderData() override; \
|
|
RenderState* createRenderState() override; \
|
|
InputData* createInputData() override; \
|
|
protected: \
|
|
ClassName(); \
|
|
friend struct ClassName##Private; \
|
|
friend struct ClassName##RenderState; \
|
|
friend struct ClassName##InputData; \
|
|
public:
|
|
#define Q_Ptr(ClassName) \
|
|
ClassName(); \
|
|
ClassName##Private* d() {return reinterpret_cast<ClassName##Private*>(dPtr);} \
|
|
RenderData* createRenderData() override; \
|
|
RenderState* createRenderState() override; \
|
|
InputData* createInputData() override;
|
|
#define Q_Ptr_cpp(ClassName) \
|
|
ClassName::ClassName() { \
|
|
dPtr = new ClassName##Private; \
|
|
mObjectName = #ClassName; \
|
|
} \
|
|
RenderData* ClassName::createRenderData() {return new ClassName##Private;} \
|
|
RenderState* ClassName::createRenderState() {return new ClassName##RenderState;} \
|
|
InputData* ClassName::createInputData() {return new ClassName##InputData;}
|
|
#define D_Ptr_3(ClassName) \
|
|
ClassName##RenderState* renderState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Render));} \
|
|
ClassName##RenderState* readyState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Ready));} \
|
|
ClassName##RenderState* editState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Edit));} \
|
|
ClassName##InputData* renderInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Render));} \
|
|
ClassName##InputData* editInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Edit));} \
|
|
friend class ClassName; \
|
|
void syncStatePipeline() override { \
|
|
Triple_Buffer_Lease editLease = mStateControl.wait_mark_use_role(State_Edit); \
|
|
Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(readyLease.index)); \
|
|
auto edit = reinterpret_cast<ClassName##RenderState*>(stateByIndex(editLease.index)); \
|
|
if(buffer_version_newer(edit->version, ready->version)) *ready = *edit; \
|
|
mStateControl.unmark_use(readyLease); \
|
|
mStateControl.unmark_use(editLease); \
|
|
mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Ready])); \
|
|
auto render = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Render])); \
|
|
return buffer_version_newer(ready->version, render->version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& edit = inputSlotByIndex(view[Input_Edit]); \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
return edit.pending && buffer_version_newer(edit.version, ready.version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
const InputBufferSlot& render = inputSlotByIndex(view[Input_Render]); \
|
|
return ready.pending && buffer_version_newer(ready.version, render.version); \
|
|
}); \
|
|
if(!mRenderStart) mRenderStart = true; \
|
|
}
|
|
#define D_Ptr(ClassName) \
|
|
ClassName* q() {return reinterpret_cast<ClassName*>(qPtr);} \
|
|
ClassName##RenderState* renderState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Render));} \
|
|
ClassName##RenderState* readyState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Ready));} \
|
|
ClassName##RenderState* editState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Edit));} \
|
|
ClassName##InputData* renderInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Render));} \
|
|
ClassName##InputData* editInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Edit));} \
|
|
friend class ClassName; \
|
|
void syncStatePipeline() override { \
|
|
Triple_Buffer_Lease editLease = mStateControl.wait_mark_use_role(State_Edit); \
|
|
Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(readyLease.index)); \
|
|
auto edit = reinterpret_cast<ClassName##RenderState*>(stateByIndex(editLease.index)); \
|
|
if(buffer_version_newer(edit->version, ready->version)) *ready = *edit; \
|
|
mStateControl.unmark_use(readyLease); \
|
|
mStateControl.unmark_use(editLease); \
|
|
mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Ready])); \
|
|
auto render = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Render])); \
|
|
return buffer_version_newer(ready->version, render->version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& edit = inputSlotByIndex(view[Input_Edit]); \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
return edit.pending && buffer_version_newer(edit.version, ready.version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
const InputBufferSlot& render = inputSlotByIndex(view[Input_Render]); \
|
|
return ready.pending && buffer_version_newer(ready.version, render.version); \
|
|
}); \
|
|
if(!mRenderStart) mRenderStart = true; \
|
|
}
|
|
#define D_Ptr2(ClassName) \
|
|
ClassName* q() {return reinterpret_cast<ClassName*>(qPtr);} \
|
|
ClassName##RenderState* renderState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Render));} \
|
|
ClassName##RenderState* readyState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Ready));} \
|
|
ClassName##RenderState* editState() override {return reinterpret_cast<ClassName##RenderState*>(state(State_Edit));} \
|
|
ClassName##InputData* renderInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Render));} \
|
|
ClassName##InputData* editInputData() override {return reinterpret_cast<ClassName##InputData*>(inputData(Input_Edit));} \
|
|
friend class ClassName; \
|
|
void syncStatePipeline() override { \
|
|
Triple_Buffer_Lease editLease = mStateControl.wait_mark_use_role(State_Edit); \
|
|
Triple_Buffer_Lease readyLease = mStateControl.wait_mark_use_role(State_Ready); \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(readyLease.index)); \
|
|
auto edit = reinterpret_cast<ClassName##RenderState*>(stateByIndex(editLease.index)); \
|
|
if(buffer_version_newer(edit->version, ready->version)) *ready = *edit; \
|
|
mStateControl.unmark_use(readyLease); \
|
|
mStateControl.unmark_use(editLease); \
|
|
mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { \
|
|
auto ready = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Ready])); \
|
|
auto render = reinterpret_cast<ClassName##RenderState*>(stateByIndex(view[State_Render])); \
|
|
return buffer_version_newer(ready->version, render->version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& edit = inputSlotByIndex(view[Input_Edit]); \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
return edit.pending && buffer_version_newer(edit.version, ready.version); \
|
|
}); \
|
|
mInputControl.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) { \
|
|
const InputBufferSlot& ready = inputSlotByIndex(view[Input_Ready]); \
|
|
const InputBufferSlot& render = inputSlotByIndex(view[Input_Render]); \
|
|
return ready.pending && buffer_version_newer(ready.version, render.version); \
|
|
}); \
|
|
if(!mRenderStart) mRenderStart = true; \
|
|
}
|
|
#define INIT_SET(className) className##Private* pd = d(); \
|
|
Triple_Buffer_Lease _stateLease = pd->mStateControl.wait_mark_use_role(State_Edit); \
|
|
className##RenderState* sc = reinterpret_cast<className##RenderState*>(pd->stateByIndex(_stateLease.index));\
|
|
RenderEditGuard _editGuard(pd, _stateLease);
|
|
#define INIT_INPUT(className) className##Private* pd = d(); \
|
|
Triple_Buffer_Lease _inputLease = pd->mInputControl.wait_mark_use_role(Input_Edit); \
|
|
className##InputData* input = reinterpret_cast<className##InputData*>(pd->inputDataByIndex(_inputLease.index)); \
|
|
RenderInputGuard _inputGuard(pd, _inputLease);
|
|
}
|