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

397 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 startRenderScheduler() {
Global::instance()->startRenderScheduler();
}
Plot::Plot() {
d = new PlotPrivate(this);
setAttribute(Qt::WA_OpaquePaintEvent, true);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
Global::instance()->renderScheduler().registerPlot(this);
}
bool Plot::usePerformanceShower() {
return d->mShower && d->mShower->enabled();
}
void Plot::set_usePerformanceShower(bool use) {
if(!d->mShower) {
d->mShower = new PerformanceShower;
d->mShower->init(this, "legend");
}
d->mShower->setEnabled(use);
}
Plot::~Plot() {
d->mDestroying.store(true, std::memory_order_release);
d->mRenderEnabled.store(false, std::memory_order_release);
Global::instance()->renderScheduler().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->mShower;
d->mShower = nullptr;
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);
Plot* self = const_cast<Plot*>(this);
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
Global::instance()->renderScheduler().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;
Plot* self = const_cast<Plot*>(this);
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
Global::instance()->renderScheduler().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 mode = d->mPaintBufferAcquireMode.load(std::memory_order_acquire) == Plot_Buffer_Acquire_Mode::Wait ? Triple_Buffer_Mode::Wait : Triple_Buffer_Mode::Try;
auto colorLease = d->mPipeline.consumeReadyColor(mode);
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();
}
Plot_Buffer_Acquire_Mode Plot::paintBufferAcquireMode() const {
return d->mPaintBufferAcquireMode.load(std::memory_order_acquire);
}
void Plot::setPaintBufferAcquireMode(Plot_Buffer_Acquire_Mode mode) {
d->mPaintBufferAcquireMode.store(mode, std::memory_order_release);
}
void Plot::submitRender() {
RenderScheduler& scheduler = Global::instance()->renderScheduler();
if(!scheduler.isSchedulerThread()) {
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
scheduler.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 SRTT:%2 RTTVAR:%3", 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;
pipeline.jobState = RenderAble::JobState::Running;
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
scheduler.postCpu([this, privateData, colorLease, color, renderSize, background, version]() {
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;
}
Global::instance()->renderScheduler().post([this, privateData]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender();
notifyRenderTaskDone(privateData);
});
});
}
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(pipeline.hasNewState()) submitRender();
}
void Plot::renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version) {
Cacl renderData("整体渲染耗时:%1 SRTT:%2 RTTVAR:%3", 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<RenderAble*> leasedAbles;
QVector<Triple_Buffer_Lease> stateLeases;
QPainter painter(&color->image);
{
Cacl drawData("draw耗时:%1 SRTT:%2 RTTVAR:%3", d->mShower);
for(Layer* layer : mLayerList) {
for(RenderAble* cur : layer->mRenderAbles) {
if(!cur->mVisable) continue;
auto lease = cur->dPtr->markStateRole(State_Render);
if(!lease) continue;
leasedAbles.append(cur);
stateLeases.append(lease);
}
}
for(RenderAble* able : leasedAbles) {
able->draw(&painter);
}
}
for(int i = 0; i < leasedAbles.size(); ++i) {
leasedAbles[i]->dPtr->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;
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
Global::instance()->renderScheduler().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);
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
Global::instance()->renderScheduler().post([privateData, renderSize]() {
if(!privateData->mDestroying.load(std::memory_order_acquire)) privateData->mRenderSize = renderSize;
notifyRenderTaskDone(privateData);
});
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;
}
}