#include "Plot_p.h" #include "PerformanceShower_p.h" #include "Global.h" #include #include namespace YSG { class PrePareMutiDataMutexGuard { public: QVector mLockList; PrePareMutiDataMutexGuard(RenderAble* renderAble, Plot* plot) { for(PrePareMutiDataMutex* curLock : plot->mMutiSpinLock) { if(curLock->mSet.contains(renderAble)) { mLockList.append(curLock); } } for(PrePareMutiDataMutex* curLock : mLockList) curLock->lock(renderAble); } ~PrePareMutiDataMutexGuard() { for(PrePareMutiDataMutex* curLock : mLockList) curLock->unlock(); } }; 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) { SpinLockGuard g(&d->mRenderLock); 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 = false; if(d->mTimerThread) d->mTimerThread->removePlot(this); { std::unique_lock 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; } void Plot::startRender(int refreshTimesPreSecond) { d->mRefreshTimesPreSecond = refreshTimesPreSecond; startRender(); } void Plot::startRender() const { if(d->mDestroying.load(std::memory_order_acquire)) return; d->mRenderEnabled = true; if(!d->mTimerThread) return; Plot* self = const_cast(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 = false; if(d->mDestroying.load(std::memory_order_acquire)) return; if(!d->mTimerThread) return; Plot* self = const_cast(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); RenderAble::ColorBuffer* color = d->mPipeline.consumeReadyColor(); if(color && !color->image.isNull()) painter.drawImage(QPoint(0, 0), color->image); else painter.fillRect(rect(), d->mBackground); painter.end(); if(d->mShower) d->mShower->counterIncrease("plot paint"); } void Plot::render() { submitRender(); } void Plot::submitRender() { if(d->mDestroying.load(std::memory_order_acquire)) return; if(mFirstResize) return; if(!d->mRenderEnabled) 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->mInfos["interval"] = QString("渲染:%1, global:%2").arg(qRound(1000.0 / (double)d->mRefreshTimesPreSecond)).arg(Global::instance()->mInterval); } { Cacl prepareData("准备数据耗时: %1 avg: %2", d->mShower); SpinLockGuard prepareDataLock(&d->mPrepareDataLock); for(Layer* layer : mLayerList) { for(RenderAble *cur : layer->mRenderAbles) { //qDebug() << "info: "<< layer->mLayerName << " " << cur->mObjectName; for(auto rely : cur->mBeRelyList) { if(!rely->mPrepared){ PrePareMutiDataMutexGuard _guard(rely, this); // qDebug() << cur->mObjectName << "rely: " << mObjectName; rely->prepareData(); rely->mPrepared = true; } } if(!cur->mPrepared){ PrePareMutiDataMutexGuard _guard(cur, this); 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; } } RenderAble::ColorBuffer* color = pipeline.currentRenderColor(); 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, color, renderSize, background, version, thread]() { if(privateData->mDestroying.load(std::memory_order_acquire)) { notifyRenderTaskDone(privateData); return; } renderColor(color, renderSize, background, version); 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); 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); 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; cur->draw(&painter); } } } painter.end(); color->version = version; color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size)); } void Plot::scheduleRenderTimer() { if(d->mDestroying.load(std::memory_order_acquire) || !d->mRenderTimer || !d->mRenderEnabled) 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(event); { SpinLockGuard guard(&d->mRenderLock); d->mRenderSize = e->size(); 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(event); for(Layer* layer : mLayerList) { for(RenderAble* able : layer->mRenderAbles) { able->wheelEvent(e); } } break; } case QEvent::MouseMove: { auto e = reinterpret_cast(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(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(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(event); for(Layer* layer : mLayerList) { for(RenderAble* able : layer->mRenderAbles) { able->keyPressEvent(e); } } break; } case QEvent::KeyRelease: { auto e = reinterpret_cast(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; } }