397 lines
16 KiB
C++
397 lines
16 KiB
C++
#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;
|
||
}
|
||
|
||
|
||
}
|