261 lines
10 KiB
C++
261 lines
10 KiB
C++
#include "Renderable.h"
|
|
#include <QDir>
|
|
#include "base/Plot.h"
|
|
#include "Axis/Abs_Axis.h"
|
|
#include "plottable/Hover_Info.h"
|
|
#include "psc_global_include/export.h"
|
|
#include "psc_global_include/Fail_Fast.h"
|
|
namespace YSG {
|
|
QDebug operator<<(QDebug debug, const Range& range) {
|
|
QDebugStateSaver saver(debug); // 保存当前的 qDebug 状态
|
|
debug.nospace() << "Range(" << range.lower << ", " << range.upper << ")";
|
|
return debug;
|
|
}
|
|
Renderable::Render_Pipeline::Render_Pipeline() {
|
|
colorControl.set_stats(&colorBufferStats);
|
|
colorControl.reset();
|
|
}
|
|
void Renderable::Render_Pipeline::mark_edit_state() {
|
|
editStateVersion.fetch_add(1, std::memory_order_release);
|
|
}
|
|
bool Renderable::Render_Pipeline::has_new_state() const {
|
|
return Renderable::version_newer(editStateVersion.load(std::memory_order_acquire), renderStateVersion);
|
|
}
|
|
Renderable::Color_Buffer* Renderable::Render_Pipeline::color_by_index(std::uint8_t index) {
|
|
return &colorBuffers[index];
|
|
}
|
|
Renderable::Color_Buffer* Renderable::Render_Pipeline::color_by_role(std::uint8_t role) {
|
|
return color_by_index(colorControl.read_view()[role]);
|
|
}
|
|
Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::wait_render_color() {
|
|
auto lease = colorControl.wait_mark_use_role(Color_Render);
|
|
return {color_by_index(lease.index), lease};
|
|
}
|
|
Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::wait_front_color() {
|
|
auto lease = colorControl.wait_mark_use_role(Color_Front);
|
|
return {color_by_index(lease.index), lease};
|
|
}
|
|
Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::try_front_color() {
|
|
auto record = colorControl.try_mark_use_role(Color_Front);
|
|
if (record.result != Triple_Buffer_Result::Success) {
|
|
return {};
|
|
}
|
|
return {color_by_index(record.lease.index), record.lease};
|
|
}
|
|
void Renderable::Render_Pipeline::unmark_color(Color_Buffer_Lease lease) {
|
|
colorControl.unmark_use(lease.lease);
|
|
}
|
|
Plot_Buffer_Acquire_Mode Renderable::buffer_acquire_mode() const {
|
|
return dPtr->buffer_acquire_mode();
|
|
}
|
|
void Renderable::set_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) {
|
|
dPtr->set_buffer_acquire_mode(mode);
|
|
}
|
|
RenderAble_Render_Schedule_Mode Renderable::render_schedule_mode() const {
|
|
return dPtr->render_schedule_mode();
|
|
}
|
|
void Renderable::set_render_schedule_mode(RenderAble_Render_Schedule_Mode mode) {
|
|
dPtr->set_render_schedule_mode(mode);
|
|
}
|
|
double Renderable::render_schedule_max_fps() const {
|
|
return dPtr->render_schedule_max_fps();
|
|
}
|
|
void Renderable::set_render_schedule_max_fps(double fps) {
|
|
dPtr->set_render_schedule_max_fps(fps);
|
|
}
|
|
bool Renderable::independent_pixel_cache() const {
|
|
return dPtr->independent_pixel_cache();
|
|
}
|
|
void Renderable::set_independent_pixel_cache(bool enabled) {
|
|
dPtr->set_independent_pixel_cache(enabled);
|
|
}
|
|
QRegion Renderable::Render_Pipeline::publish_render_color() {
|
|
colorControl.wait_swap_role(Color_Ready, Color_Render, [this](const Triple_Buffer_View& view) {
|
|
auto render = color_by_index(view[Color_Render]);
|
|
auto ready = color_by_index(view[Color_Ready]);
|
|
return Renderable::version_newer(render->version.load(std::memory_order_acquire), ready->version.load(std::memory_order_acquire));
|
|
});
|
|
auto view = colorControl.read_view();
|
|
auto ready = color_by_index(view[Color_Ready]);
|
|
auto front = color_by_index(view[Color_Front]);
|
|
if (Renderable::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)) && !paintRequestPending.exchange(true, std::memory_order_acq_rel)) {
|
|
return ready->dirtyRegion;
|
|
}
|
|
return {};
|
|
}
|
|
Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::consume_ready_color(Triple_Buffer_Mode mode) {
|
|
auto canSwap = [this](const Triple_Buffer_View& view) {
|
|
auto ready = color_by_index(view[Color_Ready]);
|
|
auto front = color_by_index(view[Color_Front]);
|
|
return Renderable::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire));
|
|
};
|
|
if (mode == Triple_Buffer_Mode::Wait) {
|
|
colorControl.wait_swap_role(Color_Front, Color_Ready, canSwap);
|
|
}
|
|
else {
|
|
colorControl.try_swap_role(Color_Front, Color_Ready, canSwap);
|
|
}
|
|
paintRequestPending.store(false, std::memory_order_release);
|
|
if (mode == Triple_Buffer_Mode::Wait) {
|
|
return wait_front_color();
|
|
}
|
|
return try_front_color();
|
|
}
|
|
Render_Edit_Guard::Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease) : mData(data), mLease(lease) {}
|
|
Render_Edit_Guard::~Render_Edit_Guard() {
|
|
if (!mData) return;
|
|
++mData->state_by_index(mLease.index)->version;
|
|
if (mData->qPtr) mData->qPtr->mark_render_dirty();
|
|
mData->unmark_state(mLease);
|
|
}
|
|
Render_Input_Guard::Render_Input_Guard(Render_Data* data, Triple_Buffer_Lease lease) : mData(data), mLease(lease) {}
|
|
Render_Input_Guard::~Render_Input_Guard() {
|
|
if (!mData) return;
|
|
mData->mark_input_dirty(mLease);
|
|
mData->mInputControl.unmark_use(mLease);
|
|
}
|
|
void Render_Data::mark_input_dirty(Triple_Buffer_Lease lease, bool notifyRender) {
|
|
Input_Buffer_Slot& slot = input_slot_by_index(lease.index);
|
|
slot.version = ++mInputVersion;
|
|
slot.pending = true;
|
|
if (notifyRender && qPtr) qPtr->mark_render_dirty();
|
|
}
|
|
void Renderable::init(Plot* plot, QString layerName) {
|
|
if (layerName.isEmpty()) {
|
|
layerName = plot->default_layer_name;
|
|
}
|
|
plot->mLayerMap[layerName]->renderable_list.append(this);
|
|
mPlot = plot;
|
|
if (!dPtr) dPtr = create_render_data();
|
|
dPtr->set_buffer_acquire_mode(plot->render_able_buffer_acquire_mode());
|
|
dPtr->clear_state_buffers();
|
|
dPtr->clear_input_buffers();
|
|
dPtr->mStateBuffers[State_Edit] = create_render_state();
|
|
dPtr->mStateBuffers[State_Ready] = create_render_state();
|
|
dPtr->mStateBuffers[State_Render] = create_render_state();
|
|
dPtr->mInputBuffers[Input_Edit].data = create_input_data();
|
|
dPtr->mInputBuffers[Input_Ready].data = create_input_data();
|
|
dPtr->mInputBuffers[Input_Render].data = create_input_data();
|
|
for (Render_State* state : dPtr->mStateBuffers) {
|
|
state->dPtr = dPtr;
|
|
}
|
|
dPtr->qPtr = this;
|
|
dPtr->mStateBuffers[State_Edit]->version = 1;
|
|
if (mPlot) mPlot->mark_render_state_dirty();
|
|
}
|
|
void Renderable::mark_state_dirty() {
|
|
if (dPtr) {
|
|
auto lease = dPtr->mStateControl.wait_mark_use_role(State_Edit);
|
|
++dPtr->state_by_index(lease.index)->version;
|
|
dPtr->mStateControl.unmark_use(lease);
|
|
}
|
|
mark_render_dirty();
|
|
}
|
|
void Renderable::mark_render_dirty() {
|
|
if (!mPlot) return;
|
|
if (dPtr&& dPtr->independent_pixel_cache())
|
|
{
|
|
dPtr->mark_pixel_dirty();
|
|
mPlot->mark_independent_render_dirty(this);
|
|
return;
|
|
}
|
|
mPlot->mark_render_state_dirty();
|
|
}
|
|
bool Renderable::ok() const {
|
|
return dPtr->mRenderStart && mPlot && !mPlot->first_resize && !mPlot->first_prepare_data;
|
|
}
|
|
Renderable::~Renderable() {}
|
|
bool Renderable::dect_cycle_rely() {
|
|
QQueue<Renderable*> queue;
|
|
queue.enqueue(this);
|
|
while (!queue.isEmpty()) {
|
|
Renderable* current = queue.dequeue();
|
|
QSet<Renderable*> visited;
|
|
QSet<Renderable*> recursionStack;
|
|
QVector<Renderable*> path;
|
|
bool has = has_cycle_rely(current, visited, recursionStack, path);
|
|
if (has) {
|
|
return true;
|
|
}
|
|
}
|
|
qDebug() << this << " 检测成功!";
|
|
return false;
|
|
}
|
|
bool Renderable::has_cycle_rely(Renderable* node, QSet<Renderable*>& visited, QSet<Renderable*>& recursionStack,
|
|
QVector<Renderable*>& currentPath) {
|
|
if (!node) return false;
|
|
if (recursionStack.contains(node)) {
|
|
// 节点已经在当前递归路径中,检测到循环
|
|
qDebug() << "Cycle detected in path:";
|
|
// 打印循环依赖链
|
|
for (Renderable* n : currentPath) {
|
|
qDebug() << n->mObjectName << "(" << n << ")->";
|
|
}
|
|
qDebug() << node; // 打印形成循环的节点
|
|
return true;
|
|
}
|
|
if (visited.contains(node)) {
|
|
// 节点已经被处理过,无需再次处理
|
|
return false;
|
|
}
|
|
// 标记当前节点为已访问
|
|
visited.insert(node);
|
|
// 将当前节点标记为递归路径中的节点
|
|
recursionStack.insert(node);
|
|
// 记录当前节点在路径中
|
|
currentPath.append(node);
|
|
// 递归检查所有子节点
|
|
for (Renderable* child : node->mBeRelyList) {
|
|
if (has_cycle_rely(child, visited, recursionStack, currentPath)) {
|
|
return true;
|
|
}
|
|
}
|
|
// 从递归路径中移除当前节点
|
|
recursionStack.remove(node);
|
|
// 从路径中移除当前节点
|
|
currentPath.removeLast();
|
|
return false;
|
|
}
|
|
QVector<QRgb> get_turbo_color_gradient() {
|
|
QVector<QRgb> colors;
|
|
// std::cout << "11111111111111111111111111111111111111" << std::endl;
|
|
// for (auto s : QDir(":/").entryList())
|
|
// {
|
|
// std::cout << "QDir=============" << s.toStdString() << std::endl;
|
|
// }
|
|
//
|
|
// std::cout << "11111111111111111111111111111111111111" << std::endl;
|
|
//
|
|
QFile file(":/turbo.colorMap");
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
|
std::ostringstream oss;
|
|
oss << file.errorString().toStdString() << " getTurboColorGradient2: Failed to open file" << LOG_POS_SIMPLE << std::endl;
|
|
Psc::fail_fast(oss.str());
|
|
return colors; // 返回一个空的 std::vector
|
|
}
|
|
QByteArray fileData = file.readAll();
|
|
file.close();
|
|
// 检查文件内容
|
|
if (fileData.size() != 768) {
|
|
qDebug() << "getTurboColorGradient2: File size is not as expected (768 bytes), got" << fileData.size();
|
|
return colors; // 返回一个空的 std::vector
|
|
}
|
|
// 确保每个颜色有 3 个字节 (RGB),总共有 256 个颜色
|
|
colors.reserve(256);
|
|
for (int i = 0; i < 256; ++i) {
|
|
uchar r = fileData[i * 3];
|
|
uchar g = fileData[i * 3 + 1];
|
|
uchar b = fileData[i * 3 + 2];
|
|
colors.push_back(qRgb(r, g, b));
|
|
}
|
|
return colors;
|
|
}
|
|
SRC Render_State::src() {
|
|
auto view = dPtr->mStateControl.read_view();
|
|
for (std::uint8_t role = State_Edit; role <= State_Render; ++role) {
|
|
if (dPtr->mStateBuffers[view[role]] == this) return static_cast<SRC>(role);
|
|
}
|
|
return SRC::Edit;
|
|
}
|
|
}
|