Files
Renderive/YSGraphic_Core/base/Plot.cpp
T
2026-07-23 12:27:06 +08:00

418 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Plot_p.h"
#include "PerformanceShower_p.h"
#include "Global.h"
#include <algorithm>
#include <chrono>
namespace YSG {
static void notifyRenderTaskDone(PlotPrivate* data) {
if(data->mActiveRenderTasks.fetch_sub(1, std::memory_order_acq_rel) == 1) data->mRenderTaskDone.notify_all();
}
void startAllRenderThread() {
Global::instance()->startAllTimeThread();
}
void Plot::bindRenderThread(const QString& threadName) {
auto g = Global::instance();
if (!g->mTimerThreadMap.contains(threadName)) {
auto newThread = new TimerThread;
g->mTimerThreadMap[threadName] = newThread;
newThread->setObjectName(threadName);
}
TimerThread* thread = g->mTimerThreadMap[threadName];
thread->mPlots.append(this);
d->mTimerThread = thread;
}
Plot::Plot() {
d = new PlotPrivate(this);
setAttribute(Qt::WA_OpaquePaintEvent, true);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
}
bool Plot::usePerformanceShower() {
return d->mShower;
}
void Plot::set_usePerformanceShower(bool use) {
if(!use) {
PerformanceShower* t = d->mShower;
d->mShower = nullptr;
delete t;
} else {
if(d->mShower) return;
d->mShower = new PerformanceShower(this);
d->mShower->show();
}
}
Plot::~Plot() {
d->mDestroying.store(true, std::memory_order_release);
d->mRenderEnabled.store(false, std::memory_order_release);
if(d->mTimerThread) d->mTimerThread->removePlot(this);
{
std::unique_lock<std::mutex> lock(d->mRenderTaskMutex);
d->mRenderTaskDone.wait(lock, [this]() {
return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0;
});
}
delete d;
}
bool Plot::isRendering() {
return d->mRenderEnabled.load(std::memory_order_acquire);
}
void Plot::startRender(int refreshTimesPreSecond) {
d->mRefreshTimesPreSecond = refreshTimesPreSecond;
startRender();
}
void Plot::startRender() const {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mRenderEnabled.store(true, std::memory_order_release);
if(!d->mTimerThread) return;
Plot* self = const_cast<Plot*>(this);
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([self, privateData]() {
PlotPrivate* d = self->d;
if(!d->mDestroying.load(std::memory_order_acquire)) {
if(d->mRenderTimer) {
d->mRenderTimer->cancel();
self->scheduleRenderTimer();
}
self->submitRender();
}
notifyRenderTaskDone(privateData);
});
}
void Plot::pauseRender() const {
d->mRenderEnabled.store(false, std::memory_order_release);
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(!d->mTimerThread) return;
Plot* self = const_cast<Plot*>(this);
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([self, privateData]() {
PlotPrivate* d = self->d;
if(!d->mDestroying.load(std::memory_order_acquire)) {
if(d->mRenderTimer) {
d->mRenderTimer->cancel();
}
}
notifyRenderTaskDone(privateData);
});
}
void Plot::paintEvent(QPaintEvent* event) {
Q_UNUSED(event)
QPainter painter(this);
auto colorLease = d->mPipeline.consumeReadyColor();
RenderAble::ColorBuffer* color = colorLease.buffer;
if(color && !color->image.isNull()) painter.drawImage(QPoint(0, 0), color->image);
else painter.fillRect(rect(), d->mBackground);
if(colorLease) d->mPipeline.unmarkColor(colorLease);
painter.end();
if(d->mShower) d->mShower->counterIncrease("plot paint");
}
void Plot::render() {
submitRender();
}
void Plot::submitRender() {
if(d->mTimerThread && d->mTimerThread->isRunning() && !d->mTimerThread->isSchedulerThread()) {
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([this, privateData]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) submitRender();
notifyRenderTaskDone(privateData);
});
return;
}
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(mFirstResize) return;
if(!d->mRenderEnabled.load(std::memory_order_acquire)) return;
QSize renderSize = d->mRenderSize;
if(renderSize.width() <= 0 || renderSize.height() <= 0) return;
RenderAble::RenderPipeline& pipeline = d->mPipeline;
if(pipeline.jobState != RenderAble::JobState::Idle) return;
if(!pipeline.hasNewState()) return;
pipeline.jobState = RenderAble::JobState::Queued;
pipeline.renderStateVersion = pipeline.editStateVersion.load(std::memory_order_acquire);
if(d->mShower) {
d->mShower->counterIncrease("渲染帧率");
d->mShower->setInfo("interval", QString("渲染:%1, global%2").arg(qRound(1000.0 / (double)d->mRefreshTimesPreSecond)).arg(Global::instance()->mInterval));
}
{
Cacl prepareData("准备数据耗时: %1 avg: %2", d->mShower);
for(Layer* layer : mLayerList) {
for(RenderAble *cur : layer->mRenderAbles) {
//qDebug() << "info: "<< layer->mLayerName << " " << cur->mObjectName;
for(auto rely : cur->mBeRelyList) {
if(!rely->mPrepared){
// qDebug() << cur->mObjectName << "rely: " << mObjectName;
rely->prepareData();
rely->mPrepared = true;
}
}
if(!cur->mPrepared){
cur->prepareData();
//qDebug() << cur->mObjectName << " prepareData";
cur->mPrepared = true;
}
}
}
if(mFirstPrepareData) mFirstPrepareData = false;
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->mPrepared = false;
}
}
auto colorLease = pipeline.waitRenderColor();
RenderAble::ColorBuffer* color = colorLease.buffer;
QColor background = d->mBackground;
std::uint64_t version = pipeline.renderStateVersion;
TimerThread* thread = d->mTimerThread;
pipeline.jobState = RenderAble::JobState::Running;
if(thread) {
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
thread->postCpu([this, privateData, colorLease, color, renderSize, background, version, thread]() {
if(privateData->mDestroying.load(std::memory_order_acquire)) {
privateData->mPipeline.unmarkColor(colorLease);
notifyRenderTaskDone(privateData);
return;
}
renderColor(color, renderSize, background, version);
privateData->mPipeline.unmarkColor(colorLease);
if(privateData->mDestroying.load(std::memory_order_acquire)) {
notifyRenderTaskDone(privateData);
return;
}
thread->post([this, privateData]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender();
notifyRenderTaskDone(privateData);
});
});
} else {
renderColor(color, renderSize, background, version);
pipeline.unmarkColor(colorLease);
finishRender();
}
}
void Plot::finishRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
RenderAble::RenderPipeline& pipeline = d->mPipeline;
QRegion updateRegion = pipeline.publishRenderColor();
pipeline.jobState = RenderAble::JobState::Idle;
if(!updateRegion.isEmpty()) requestUpdate(updateRegion);
if(d->mShower) d->mShower->refresh();
if(pipeline.hasNewState()) submitRender();
}
void Plot::renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version) {
Cacl renderData("整体渲染耗时: %1 avg: %2", d->mShower);
if(color->image.size() != size || color->image.format() != QImage::Format_ARGB32) {
color->image = QImage(size, QImage::Format_ARGB32);
}
color->image.detach();
color->image.fill(background);
QVector<RenderData*> leasedData;
QVector<Triple_Buffer_Lease> stateLeases;
QPainter painter(&color->image);
{
Cacl drawData("draw耗时: %1 avg: %2", d->mShower);
for(Layer* layer : mLayerList) {
for(RenderAble* cur : layer->mRenderAbles) {
if(!cur->mVisable) continue;
leasedData.append(cur->dPtr);
stateLeases.append(cur->dPtr->waitMarkStateRole(State_Render));
}
}
for(Layer* layer : mLayerList) {
for(RenderAble* cur : layer->mRenderAbles) {
if(!cur->mVisable) continue;
cur->draw(&painter);
}
}
}
for(int i = 0; i < leasedData.size(); ++i) {
leasedData[i]->unmarkState(stateLeases[i]);
}
painter.end();
color->version.store(version, std::memory_order_release);
color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size));
}
void Plot::scheduleRenderTimer() {
if(d->mDestroying.load(std::memory_order_acquire) || !d->mRenderTimer || !d->mRenderEnabled.load(std::memory_order_acquire)) return;
int interval = std::max(1, qRound(1000.0 / (double)d->mRefreshTimesPreSecond));
d->mRenderTimer->expires_after(std::chrono::milliseconds(interval));
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mRenderTimer->async_wait([this, privateData](const asio::error_code& error) {
if(!error && !d->mDestroying.load(std::memory_order_acquire)) {
submitRender();
scheduleRenderTimer();
}
notifyRenderTaskDone(privateData);
});
}
void Plot::markRenderStateDirty() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mPipeline.markEditState();
requestRender();
}
void Plot::requestRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(!d->mTimerThread) return;
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([this, privateData]() {
if(!d->mDestroying.load(std::memory_order_acquire)) submitRender();
notifyRenderTaskDone(privateData);
});
}
void Plot::requestUpdate(const QRegion& region) {
QTimer::singleShot(0, this, [this, region]() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(region.isEmpty()) update();
else update(region);
});
}
QColor Plot::backgroundColor() {
return d->mBackground;
}
void Plot::setBackgroundColor(const QColor& color) const {
d->mBackground = color;
}
bool Plot::event(QEvent* event) {
bool ret = QWidget::event(event);
switch (event->type()){
case QEvent::Resize: {
auto e = reinterpret_cast<QResizeEvent*>(event);
QSize renderSize = e->size();
d->mPendingRenderWidth.store(renderSize.width(), std::memory_order_release);
d->mPendingRenderHeight.store(renderSize.height(), std::memory_order_release);
if(d->mTimerThread && d->mTimerThread->isRunning()) {
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mTimerThread->post([privateData, renderSize]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) privateData->mRenderSize = renderSize;
notifyRenderTaskDone(privateData);
});
} else {
d->mRenderSize = renderSize;
}
if(mFirstResize) {
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->firstResizeEvent(e);
}
}
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->resizeEvent(e);
}
}
if(mFirstResize) mFirstResize = false;
markRenderStateDirty();
break;
}
case QEvent::Show: {
startRender();
break;
}
case QEvent::Hide: {
pauseRender();
break;
}
case QEvent::Enter: {
break;
}
case QEvent::Leave: {
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->setHoverState(QPoint(), false);
}
}
break;
}
case QEvent::Wheel: {
auto e = reinterpret_cast<QWheelEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->wheelEvent(e);
}
}
break;
}
case QEvent::MouseMove: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
bool selected = able->selectTest(e->pos());
able->setHoverState(e->pos(), selected);
if(selected) {
able->mouseMoveEvent(e);
}
}
}
break;
}
case QEvent::MouseButtonPress: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
if(able->selectTest(e->pos())) {
able->mousePressEvent(e);
}
}
}
break;
}
case QEvent::MouseButtonRelease: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
if(able->selectTest(e->pos())) {
able->mouseReleaseEvent(e);
}
}
}
break;
}
case QEvent::KeyPress: {
auto e = reinterpret_cast<QKeyEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->keyPressEvent(e);
}
}
break;
}
case QEvent::KeyRelease: {
auto e = reinterpret_cast<QKeyEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->keyReleaseEvent(e);
}
}
break;
}
default: break;
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->plotEvent(event);
}
}
return ret;
}
}