diff --git a/YSGraphic_Core/base/PerformanceShower.cpp b/YSGraphic_Core/base/PerformanceShower.cpp index 7a50729..d1847df 100644 --- a/YSGraphic_Core/base/PerformanceShower.cpp +++ b/YSGraphic_Core/base/PerformanceShower.cpp @@ -1,106 +1,67 @@ #include "PerformanceShower_p.h" -#include -#include - namespace YSG { - PerformanceShower::PerformanceShower(QWidget *parent) : QWidget(parent) { - setAttribute(Qt::WA_OpaquePaintEvent, true); - auto layout = new QVBoxLayout(this); - layout->setSpacing(0); + PerformanceShower::PerformanceShower() { + dPtr = new PerformanceShowerPrivate; + mObjectName = "PerformanceShower"; + } + PerformanceShowerPrivate* PerformanceShower::d() { + return reinterpret_cast(dPtr); + } + RenderData* PerformanceShower::createRenderData() { + return new PerformanceShowerPrivate; + } + RenderState* PerformanceShower::createRenderState() { + return new PerformanceShowerRenderState; + } + InputData* PerformanceShower::createInputData() { + return new PerformanceShowerInputData; + } + void PerformanceShower::setEnabled(bool enabled) { + mEnabled.store(enabled, std::memory_order_release); + if(enabled) { + appendEvent({PerformanceEventType::Clear}); + } + markRenderDirty(); + } + bool PerformanceShower::enabled() const { + return mEnabled.load(std::memory_order_acquire); } void PerformanceShower::refreshCounter() { - std::lock_guard lock(mMutex); - for(CounterLine& value : mCounter) { - value.mStatistics.clear(); - } + appendEvent({PerformanceEventType::Clear}); } void PerformanceShower::counterIncrease(const QString& counterName) { - std::lock_guard lock(mMutex); - if(!mCounter.contains(counterName)) { - mCounter[counterName].mName = counterName; - } - mCounter[counterName].mStatistics.update(1); + PerformanceEvent event; + event.type = PerformanceEventType::Counter; + event.key = counterName; + appendEvent(event); } void PerformanceShower::setPerformanceLine(const QString& key, const PerformanceLine& line) { - std::lock_guard lock(mMutex); - mInfoMap[key] = line; + PerformanceEvent event; + event.type = PerformanceEventType::Line; + event.key = key; + event.line = line; + appendEvent(event); } void PerformanceShower::setInfo(const QString& key, const QString& value) { - std::lock_guard lock(mMutex); - mInfos[key] = value; + PerformanceEvent event; + event.type = PerformanceEventType::Info; + event.key = key; + event.value = value; + appendEvent(event); } - void PerformanceShower::paintEvent(QPaintEvent *event) { - QPainter painter(this); - QPoint topLeft = rect().topLeft(); - int x = topLeft.x() + mLeftMargin; - int y = topLeft.y() + mTopMargin; - painter.fillRect(rect(), Qt::white); - painter.setFont(mFont); - { - std::lock_guard lock(mMutex); - QFontMetrics fm(mFont); - int n = mAllInfo.size(); - for(int i = 0; i < n; i++) { - painter.drawText(topLeft + QPointF(x, y + i * fm.lineSpacing() + fm.lineSpacing()), mAllInfo[i]); - } - } - painter.end(); + void PerformanceShower::recordCost(const QString& key, double value) { + PerformanceEvent event; + event.type = PerformanceEventType::Cost; + event.key = key; + event.number = value; + appendEvent(event); } - - void PerformanceShower::mousePressEvent(QMouseEvent *event) { - if(mMoving) return; - if(event->button() == Qt::LeftButton) { - mMoving = true; - mStartPos = pos(); - mStartGlobalPos = event->globalPos(); - } - event->accept(); - } - - void PerformanceShower::mouseMoveEvent(QMouseEvent *event) { - if(!mMoving) return; - move(mStartPos + event->globalPos() - mStartGlobalPos); - event->accept(); - } - void PerformanceShower::mouseReleaseEvent(QMouseEvent *event) { - if(!mMoving) return; - mMoving = false; - event->accept(); - } - - QVector PerformanceShower::all() { - std::lock_guard lock(mMutex); - QVector infoList = mFixedInfo; - for(PerformanceLine& l : mInfoMap) infoList.append(l.toString()); - for(CounterLine& c : mCounter) infoList.append(c.toString()); - for(auto it = mInfos.cbegin(); it != mInfos.cend(); ++it) { - infoList.append(QString("%1: %2").arg(it.key(), it.value())); - } - return infoList; - } - - void PerformanceShower::refresh() { - QVector infoList = all(); - { - std::lock_guard lock(mMutex); - mAllInfo = infoList; - int n = mAllInfo.size(); - if(mOldSize != n) { - int maxWidth = 0; - QFontMetrics fm(mFont); - for(int i = 0; i < n; i++) maxWidth = qMax(maxWidth, fm.horizontalAdvance(mAllInfo[i])); - int w = maxWidth + mLeftMargin + mRightMargin; - int h = fm.lineSpacing() * n + mTopMargin + mBottomMargin; - QMetaObject::invokeMethod(this, "firstResize", Q_ARG(int, w), Q_ARG(int, h)); - } - mOldSize = n; - } - QMetaObject::invokeMethod(this, "update"); - } - void PerformanceShower::firstResize(int w, int h) { - resize(w, h); - } - void PerformanceShower::resizeEvent(QResizeEvent *event) { - event->accept(); + void PerformanceShower::appendEvent(const PerformanceEvent& event) { + if(!enabled() && event.type != PerformanceEventType::Clear) return; + auto pd = d(); + Triple_Buffer_Lease inputLease = pd->mInputControl.wait_mark_use_role(Input_Edit); + auto input = reinterpret_cast(pd->inputDataByIndex(inputLease.index)); + input->events.append(event); + RenderInputGuard inputGuard(pd, inputLease); } } diff --git a/YSGraphic_Core/base/PerformanceShower_p.h b/YSGraphic_Core/base/PerformanceShower_p.h index 94530ca..3af2a43 100644 --- a/YSGraphic_Core/base/PerformanceShower_p.h +++ b/YSGraphic_Core/base/PerformanceShower_p.h @@ -1,7 +1,7 @@ #pragma once #include "Core/Statistics/Statistics.h" #include "../RenderAble.h" -#include +#include namespace YSG { struct PerformanceLine { PerformanceLine() = default; @@ -37,65 +37,141 @@ namespace YSG { struct CounterLine { QString mName; Psc::Speed_Statistics mStatistics; - [[nodiscard]] double getRate() const { - return mStatistics.instant_speed; - } [[nodiscard]] QString toString() const { return QString("%1 :%2 avg:%3 (次/s)") .arg(mName, QString::number(mStatistics.instant_speed, 'f', 2), QString::number(mStatistics.average_speed, 'f', 2)); } }; - class PerformanceShower : public QWidget { - Q_OBJECT + enum class PerformanceEventType : std::uint8_t { + Clear, + Counter, + Line, + Info, + Cost + }; + struct PerformanceEvent { + PerformanceEventType type = PerformanceEventType::Clear; + QString key; + QString value; + PerformanceLine line; + double number{}; + }; + struct PerformanceShowerRenderState : RenderState { + QFont font; + int topMargin = 4; + int leftMargin = 4; + int rightMargin = 28; + int bottomMargin = 8; + QColor background = Qt::white; + QColor foreground = Qt::black; + }; + struct PerformanceShowerInputData : InputData { + QVector events; + void clear() override { + events.clear(); + } + }; + struct PerformanceShowerPrivate; + class PerformanceShower : public RenderAble { public: - explicit PerformanceShower(QWidget *parent = nullptr); - QFont mFont; - int mTopMargin = 4, mLeftMargin = 4, mRightMargin = 28, mBottomMargin = 8; - int mOldSize = -1; - QVector mAllInfo; - Q_INVOKABLE void firstResize(int w, int h); - void refresh(); - QVector all(); - std::mutex mMutex; - QMap mInfoMap; - QMap mCounter; - QVector mFixedInfo; - QMap mInfos; - + PerformanceShower(); + PerformanceShowerPrivate* d(); + RenderData* createRenderData() override; + RenderState* createRenderState() override; + InputData* createInputData() override; + void setEnabled(bool enabled); + bool enabled() const; void refreshCounter(); void counterIncrease(const QString& counterName); void setPerformanceLine(const QString& key, const PerformanceLine& line); void setInfo(const QString& key, const QString& value); - protected: - void paintEvent(QPaintEvent *event) override; - bool mMoving = false; - QPoint mStartPos, mStartGlobalPos; - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void resizeEvent(QResizeEvent *event) override; + void recordCost(const QString& key, double value); + private: + void appendEvent(const PerformanceEvent& event); + std::atomic_bool mEnabled{false}; + }; + struct PerformanceShowerPrivate : RenderData { + D_Ptr(PerformanceShower) + QMap mInfoMap; + QMap mCounter; + QMap mInfos; + QVector mAllInfo; + void prepareData() override { + syncStatePipeline(); + auto input = renderInputData(); + for(const PerformanceEvent& event : input->events) { + applyEvent(event); + } + clearRenderInput(); + rebuildLines(); + } + void draw(QPainter* painter) override { + if(!q()->enabled() || mAllInfo.isEmpty()) return; + auto s = renderState(); + painter->save(); + painter->setFont(s->font); + QFontMetrics fm(s->font); + int maxWidth = 0; + for(const QString& line : mAllInfo) maxWidth = qMax(maxWidth, fm.horizontalAdvance(line)); + int width = maxWidth + s->leftMargin + s->rightMargin; + int height = fm.lineSpacing() * mAllInfo.size() + s->topMargin + s->bottomMargin; + QRect rect(0, 0, width, height); + painter->fillRect(rect, s->background); + painter->setPen(s->foreground); + for(int i = 0; i < mAllInfo.size(); ++i) { + painter->drawText(QPointF(s->leftMargin, s->topMargin + i * fm.lineSpacing() + fm.lineSpacing()), mAllInfo[i]); + } + painter->restore(); + } + void applyEvent(const PerformanceEvent& event) { + switch(event.type) { + case PerformanceEventType::Clear: + mInfoMap.clear(); + mCounter.clear(); + mInfos.clear(); + mAllInfo.clear(); + break; + case PerformanceEventType::Counter: + if(!mCounter.contains(event.key)) mCounter[event.key].mName = event.key; + mCounter[event.key].mStatistics.update(1); + break; + case PerformanceEventType::Line: + mInfoMap[event.key] = event.line; + break; + case PerformanceEventType::Info: + mInfos[event.key] = event.value; + break; + case PerformanceEventType::Cost: + if(!mInfoMap.contains(event.key)) mInfoMap[event.key] = PerformanceLine(event.key); + mInfoMap[event.key].update(event.number); + break; + } + } + void rebuildLines() { + QVector lines; + for(PerformanceLine& line : mInfoMap) lines.append(line.toString()); + for(CounterLine& counter : mCounter) lines.append(counter.toString()); + for(auto it = mInfos.cbegin(); it != mInfos.cend(); ++it) { + lines.append(QString("%1: %2").arg(it.key(), it.value())); + } + mAllInfo = lines; + } }; - class Cacl { public: std::chrono::system_clock::time_point mStart; QString mName; PerformanceShower *mPerformanceShower{}; Cacl(const QString& name, PerformanceShower* performanceShower) { - if(!performanceShower) return; + if(!performanceShower || !performanceShower->enabled()) return; mStart = std::chrono::system_clock::now(); mName = name; mPerformanceShower = performanceShower; } ~Cacl() { - if(!mPerformanceShower) return; + if(!mPerformanceShower || !mPerformanceShower->enabled()) return; double useTime = std::chrono::duration(std::chrono::system_clock::now() - mStart).count() * 1000; - std::lock_guard lock(mPerformanceShower->mMutex); - if(!mPerformanceShower->mInfoMap.contains(mName)) { - mPerformanceShower->mInfoMap[mName] = PerformanceLine(mName); - } - PerformanceLine& data = mPerformanceShower->mInfoMap[mName]; - data.update(useTime); + mPerformanceShower->recordCost(mName, useTime); } }; } diff --git a/YSGraphic_Core/base/Plot.cpp b/YSGraphic_Core/base/Plot.cpp index 969dd9c..dbbfb4e 100644 --- a/YSGraphic_Core/base/Plot.cpp +++ b/YSGraphic_Core/base/Plot.cpp @@ -20,18 +20,14 @@ namespace YSG { Global::instance()->renderScheduler().registerPlot(this); } bool Plot::usePerformanceShower() { - return d->mShower; + return d->mShower && d->mShower->enabled(); } 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(); + if(!d->mShower) { + d->mShower = new PerformanceShower; + d->mShower->init(this, "legend"); } + d->mShower->setEnabled(use); } Plot::~Plot() { @@ -44,6 +40,8 @@ namespace YSG { return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0; }); } + delete d->mShower; + d->mShower = nullptr; delete d; } @@ -195,7 +193,6 @@ namespace YSG { 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) {