From 650114d95ea7b82ac34e55e43b3d3dc55aef280e Mon Sep 17 00:00:00 2001 From: Sjors Gielen Date: Tue, 23 Oct 2018 00:44:39 +0200 Subject: [PATCH 01/30] Replace usage of deprecated QGLWidget with QOpenGLWidget. --- build/depends.py | 1 - src/mixxx.cpp | 11 +----- src/waveform/sharedglcontext.cpp | 37 ------------------- src/waveform/sharedglcontext.h | 19 ---------- src/waveform/vsyncthread.cpp | 21 +---------- src/waveform/vsyncthread.h | 10 +---- src/waveform/waveformwidgetfactory.cpp | 11 +++--- src/waveform/widgets/glrgbwaveformwidget.cpp | 16 +++----- src/waveform/widgets/glrgbwaveformwidget.h | 4 +- .../widgets/glsimplewaveformwidget.cpp | 17 +++------ src/waveform/widgets/glsimplewaveformwidget.h | 4 +- src/waveform/widgets/glslwaveformwidget.cpp | 16 +++----- src/waveform/widgets/glslwaveformwidget.h | 4 +- src/waveform/widgets/glvsynctestwidget.cpp | 15 +++----- src/waveform/widgets/glvsynctestwidget.h | 4 +- src/waveform/widgets/glwaveformwidget.cpp | 16 +++----- src/waveform/widgets/glwaveformwidget.h | 4 +- src/waveform/widgets/hsvwaveformwidget.cpp | 1 + .../widgets/qtsimplewaveformwidget.cpp | 17 +++------ src/waveform/widgets/qtsimplewaveformwidget.h | 4 +- src/waveform/widgets/qtwaveformwidget.cpp | 16 +++----- src/waveform/widgets/qtwaveformwidget.h | 4 +- src/waveform/widgets/waveformwidgetabstract.h | 2 +- src/widget/wspinny.cpp | 8 +--- src/widget/wspinny.h | 4 +- 25 files changed, 70 insertions(+), 196 deletions(-) delete mode 100644 src/waveform/sharedglcontext.cpp delete mode 100644 src/waveform/sharedglcontext.h diff --git a/build/depends.py b/build/depends.py index 56b0da50f99f..d5336ded1f7a 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1074,7 +1074,6 @@ def sources(self, build): "widget/wwaveformviewer.cpp", - "waveform/sharedglcontext.cpp", "waveform/waveform.cpp", "waveform/waveformfactory.cpp", "waveform/waveformwidgetfactory.cpp", diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 3f8ce55bb7da..7e44750898e1 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -50,7 +50,6 @@ #include "sources/soundsourceproxy.h" #include "track/track.h" #include "waveform/waveformwidgetfactory.h" -#include "waveform/sharedglcontext.h" #include "database/mixxxdb.h" #include "util/debug.h" #include "util/statsmanager.h" @@ -377,14 +376,6 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { // and emit newSkinLoaded. connectMenuBar(); - // Before creating the first skin we need to create a QGLWidget so that all - // the QGLWidget's we create can use it as a shared QGLContext. - if (!CmdlineArgs::Instance().getSafeMode()) { - QGLWidget* pContextWidget = new QGLWidget(this); - pContextWidget->hide(); - SharedGLContext::setWidget(pContextWidget); - } - launchProgress(63); QWidget* oldWidget = m_pWidgetParent; diff --git a/src/waveform/sharedglcontext.cpp b/src/waveform/sharedglcontext.cpp deleted file mode 100644 index 5667316cbec3..000000000000 --- a/src/waveform/sharedglcontext.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "waveform/sharedglcontext.h" - -#include -#include -#include -#include - -const QGLWidget* SharedGLContext::s_pSharedGLWidget = NULL; - -// static -void SharedGLContext::setWidget(const QGLWidget* pWidget) { - s_pSharedGLWidget = pWidget; - qDebug() << "Set root GL Context widget valid:" - << pWidget << (pWidget && pWidget->isValid()); - const QGLContext* pContext = pWidget->context(); - qDebug() << "Created root GL Context valid:" << pContext - << (pContext && pContext->isValid()); - if (pWidget) { - QGLFormat format = pWidget->format(); - qDebug() << "Root GL Context format:"; - qDebug() << "Double Buffering:" << format.doubleBuffer(); - qDebug() << "Swap interval:" << format.swapInterval(); - qDebug() << "Depth buffer:" << format.depth(); - qDebug() << "Direct rendering:" << format.directRendering(); - qDebug() << "Has overlay:" << format.hasOverlay(); - qDebug() << "RGBA:" << format.rgba(); - qDebug() << "Sample buffers:" << format.sampleBuffers(); - qDebug() << "Samples:" << format.samples(); - qDebug() << "Stencil buffers:" << format.stencil(); - qDebug() << "Stereo:" << format.stereo(); - } -} - -// static -const QGLWidget* SharedGLContext::getWidget() { - return s_pSharedGLWidget; -} diff --git a/src/waveform/sharedglcontext.h b/src/waveform/sharedglcontext.h deleted file mode 100644 index ca1bf44b1f70..000000000000 --- a/src/waveform/sharedglcontext.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef WAVEFORM_SHAREDGLCONTEXT_H -#define WAVEFORM_SHAREDGLCONTEXT_H - -class QGLWidget; - -// Creating a QGLContext on its own doesn't work. We've tried that. You can't -// create a context on your own. It has to be associated with a real paint -// device. Source: -// http://lists.trolltech.com/qt-interest/2008-08/thread00046-0.html -class SharedGLContext { - public: - static const QGLWidget* getWidget(); - static void setWidget(const QGLWidget* pWidget); - private: - SharedGLContext() { } - static const QGLWidget* s_pSharedGLWidget; -}; - -#endif /* WAVEFORM_SHAREDGLCONTEXT_H */ diff --git a/src/waveform/vsyncthread.cpp b/src/waveform/vsyncthread.cpp index cde7a01686a4..2b1d91630fc5 100644 --- a/src/waveform/vsyncthread.cpp +++ b/src/waveform/vsyncthread.cpp @@ -121,26 +121,9 @@ void VSyncThread::run() { // static -void VSyncThread::swapGl(QGLWidget* glw, int index) { +void VSyncThread::swapGl(QOpenGLWidget* glw, int index) { Q_UNUSED(index); - // No need for glw->makeCurrent() here. - //qDebug() << "swapGl" << m_timer.elapsed().formatNanosWithUnit(); -#if defined(__APPLE__) - glw->swapBuffers(); -#elif defined(__WINDOWS__) - glw->swapBuffers(); -#else -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#ifdef QT_OPENGL_ES_2 - glw->swapBuffers(); -#else - const QX11Info *xinfo = qt_x11Info(glw); - glXSwapBuffers(xinfo->display(), glw->winId()); -#endif -#else - glw->swapBuffers(); -#endif // QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#endif + // TODO: glw->swapBuffers() used to be called here, but it is not offered by the QOpenGLWidget } int VSyncThread::elapsed() { diff --git a/src/waveform/vsyncthread.h b/src/waveform/vsyncthread.h index 2f55bb3d1c16..4fef2f030fdd 100644 --- a/src/waveform/vsyncthread.h +++ b/src/waveform/vsyncthread.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #if defined(__APPLE__) @@ -42,7 +42,7 @@ class VSyncThread : public QThread { ST_COUNT // Dummy Type at last, counting possible types }; - static void swapGl(QGLWidget* glw, int index); + static void swapGl(QOpenGLWidget* glw, int index); VSyncThread(QObject* pParent, GuiTick* pGuiTick); ~VSyncThread(); @@ -50,18 +50,14 @@ class VSyncThread : public QThread { void run(); void stop(); - bool waitForVideoSync(QGLWidget* glw); int elapsed(); int toNextSyncMicros(); void setSyncIntervalTimeMicros(int usSyncTimer); void setVSyncType(int mode); int droppedFrames(); - void setSwapWait(int sw); int fromTimerToNextSyncMicros(const PerformanceTimer& timer); void vsyncSlotFinished(); void getAvailableVSyncTypes(QList >* list); - void setupSync(QGLWidget* glw, int index); - void waitUntilSwap(QGLWidget* glw); signals: void vsyncRender(); @@ -69,14 +65,12 @@ class VSyncThread : public QThread { private: bool m_bDoRendering; - //QGLWidget *m_glw; #if defined(__APPLE__) #elif defined(__WINDOWS__) #else - void initGlxext(QGLWidget* glw); //bool glXExtensionSupported(Display *dpy, int screen, const char *extension); /* Currently unused, but probably part of later a hardware sync solution diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 725fa0f41f06..3371e76e1f01 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -4,9 +4,10 @@ #include #include #include -#include +#include #include #include +#include #include "waveform/waveformwidgetfactory.h" @@ -170,12 +171,12 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_openGLAvailable = true; - QGLWidget* glWidget = new QGLWidget(); // create paint device + QOpenGLWidget* glWidget = new QOpenGLWidget(); // create paint device // QGLShaderProgram::hasOpenGLShaderPrograms(); valgind error // Without a makeCurrent, hasOpenGLShaderPrograms returns false on Qt 5. - glWidget->context()->makeCurrent(); + glWidget->makeCurrent(); m_openGLShaderAvailable = - QGLShaderProgram::hasOpenGLShaderPrograms(glWidget->context()); + QOpenGLShaderProgram::hasOpenGLShaderPrograms(glWidget->context()); delete glWidget; } @@ -565,7 +566,7 @@ void WaveformWidgetFactory::swap() { for (int i = 0; i < m_waveformWidgetHolders.size(); i++) { WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget; if (pWaveformWidget->getWidth() > 0) { - QGLWidget* glw = dynamic_cast(pWaveformWidget->getWidget()); + QOpenGLWidget* glw = dynamic_cast(pWaveformWidget->getWidget()); // Don't swap invalid / invisible widgets or widgets with an // unexposed window. Prevents continuous log spew of // "QOpenGLContext::swapBuffers() called with non-exposed diff --git a/src/waveform/widgets/glrgbwaveformwidget.cpp b/src/waveform/widgets/glrgbwaveformwidget.cpp index 6c7aff166cb4..c2ac4db7a7f0 100644 --- a/src/waveform/widgets/glrgbwaveformwidget.cpp +++ b/src/waveform/widgets/glrgbwaveformwidget.cpp @@ -1,6 +1,5 @@ #include "glrgbwaveformwidget.h" -#include "waveform/sharedglcontext.h" #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" #include "waveform/renderers/glwaveformrendererrgb.h" @@ -12,8 +11,10 @@ #include "util/performancetimer.h" +#include + GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); @@ -27,12 +28,7 @@ GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); @@ -43,7 +39,7 @@ GLRGBWaveformWidget::~GLRGBWaveformWidget() { } void GLRGBWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void GLRGBWaveformWidget::paintEvent(QPaintEvent* event) { @@ -55,7 +51,7 @@ mixxx::Duration GLRGBWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/glrgbwaveformwidget.h b/src/waveform/widgets/glrgbwaveformwidget.h index e2b19308589e..272f21dae656 100644 --- a/src/waveform/widgets/glrgbwaveformwidget.h +++ b/src/waveform/widgets/glrgbwaveformwidget.h @@ -1,11 +1,11 @@ #ifndef GLRGBWAVEFORMWIDGET_H #define GLRGBWAVEFORMWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class GLRGBWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class GLRGBWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: GLRGBWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/glsimplewaveformwidget.cpp b/src/waveform/widgets/glsimplewaveformwidget.cpp index 8be76fe33b21..6040fb9b2baf 100644 --- a/src/waveform/widgets/glsimplewaveformwidget.cpp +++ b/src/waveform/widgets/glsimplewaveformwidget.cpp @@ -2,8 +2,8 @@ #include #include +#include -#include "waveform/sharedglcontext.h" #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" #include "waveform/renderers/glwaveformrenderersimplesignal.h" @@ -16,7 +16,7 @@ #include "util/performancetimer.h" GLSimpleWaveformWidget::GLSimpleWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); addRenderer(); @@ -29,25 +29,20 @@ GLSimpleWaveformWidget::GLSimpleWaveformWidget(const char* group, QWidget* paren setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); } GLSimpleWaveformWidget::~GLSimpleWaveformWidget() { - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } } void GLSimpleWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void GLSimpleWaveformWidget::paintEvent(QPaintEvent* event) { @@ -59,7 +54,7 @@ mixxx::Duration GLSimpleWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/glsimplewaveformwidget.h b/src/waveform/widgets/glsimplewaveformwidget.h index 0bf0b024aab3..4ff9d7e75491 100644 --- a/src/waveform/widgets/glsimplewaveformwidget.h +++ b/src/waveform/widgets/glsimplewaveformwidget.h @@ -1,11 +1,11 @@ #ifndef GLSIMPLEWAVEFORMWIDGET_H #define GLSIMPLEWAVEFORMWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class GLSimpleWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class GLSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: GLSimpleWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/glslwaveformwidget.cpp b/src/waveform/widgets/glslwaveformwidget.cpp index ae2d3d7ea192..715af86ac4e9 100644 --- a/src/waveform/widgets/glslwaveformwidget.cpp +++ b/src/waveform/widgets/glslwaveformwidget.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" @@ -11,7 +12,6 @@ #include "waveform/renderers/waveformrendermarkrange.h" #include "waveform/renderers/waveformrendererendoftrack.h" #include "waveform/renderers/waveformrenderbeat.h" -#include "waveform/sharedglcontext.h" #include "util/performancetimer.h" @@ -26,7 +26,7 @@ GLSLRGBWaveformWidget::GLSLRGBWaveformWidget(const char* group, QWidget* parent) GLSLWaveformWidget::GLSLWaveformWidget(const char* group, QWidget* parent, bool rgbRenderer) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); addRenderer(); @@ -43,14 +43,8 @@ GLSLWaveformWidget::GLSLWaveformWidget(const char* group, QWidget* parent, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - // Initialization requires activating our context. - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); @@ -61,7 +55,7 @@ GLSLWaveformWidget::~GLSLWaveformWidget() { } void GLSLWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void GLSLWaveformWidget::paintEvent(QPaintEvent* event) { @@ -73,7 +67,7 @@ mixxx::Duration GLSLWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/glslwaveformwidget.h b/src/waveform/widgets/glslwaveformwidget.h index 915c1a56abcb..a446210f5647 100644 --- a/src/waveform/widgets/glslwaveformwidget.h +++ b/src/waveform/widgets/glslwaveformwidget.h @@ -1,13 +1,13 @@ #ifndef GLWAVEFORMWIDGETSHADER_H #define GLWAVEFORMWIDGETSHADER_H -#include +#include #include "waveformwidgetabstract.h" class GLSLWaveformRendererSignal; -class GLSLWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class GLSLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: GLSLWaveformWidget(const char* group, QWidget* parent, diff --git a/src/waveform/widgets/glvsynctestwidget.cpp b/src/waveform/widgets/glvsynctestwidget.cpp index 33a3277d367a..34d2d6eddfe3 100644 --- a/src/waveform/widgets/glvsynctestwidget.cpp +++ b/src/waveform/widgets/glvsynctestwidget.cpp @@ -1,8 +1,8 @@ #include "glvsynctestwidget.h" #include +#include -#include "waveform/sharedglcontext.h" #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" #include "waveform/renderers/glwaveformrenderersimplesignal.h" @@ -16,7 +16,7 @@ #include "util/performancetimer.h" GLVSyncTestWidget::GLVSyncTestWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { // addRenderer(); // 172 µs @@ -30,23 +30,20 @@ GLVSyncTestWidget::GLVSyncTestWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); - qDebug() << "GLVSyncTestWidget.isSharing() =" << isSharing(); } GLVSyncTestWidget::~GLVSyncTestWidget() { - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } } void GLVSyncTestWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void GLVSyncTestWidget::paintEvent(QPaintEvent* event) { @@ -58,7 +55,7 @@ mixxx::Duration GLVSyncTestWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/glvsynctestwidget.h b/src/waveform/widgets/glvsynctestwidget.h index 21d89846ed36..4e49f8a0a0dc 100644 --- a/src/waveform/widgets/glvsynctestwidget.h +++ b/src/waveform/widgets/glvsynctestwidget.h @@ -1,11 +1,11 @@ #ifndef GLVSYNCTESTWIDGET_H #define GLVSYNCTESTWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class GLVSyncTestWidget : public QGLWidget, public WaveformWidgetAbstract { +class GLVSyncTestWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: GLVSyncTestWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/glwaveformwidget.cpp b/src/waveform/widgets/glwaveformwidget.cpp index b9cd81e1e51e..a01bc0296125 100644 --- a/src/waveform/widgets/glwaveformwidget.cpp +++ b/src/waveform/widgets/glwaveformwidget.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "waveform/widgets/glwaveformwidget.h" @@ -12,11 +12,10 @@ #include "waveform/renderers/waveformrendermarkrange.h" #include "waveform/renderers/waveformrendererendoftrack.h" #include "waveform/renderers/waveformrenderbeat.h" -#include "waveform/sharedglcontext.h" #include "util/performancetimer.h" GLWaveformWidget::GLWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); @@ -30,12 +29,7 @@ GLWaveformWidget::GLWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); @@ -45,7 +39,7 @@ GLWaveformWidget::~GLWaveformWidget() { } void GLWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void GLWaveformWidget::paintEvent(QPaintEvent* event) { @@ -57,7 +51,7 @@ mixxx::Duration GLWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/glwaveformwidget.h b/src/waveform/widgets/glwaveformwidget.h index cc3dbd9c5846..9d51560ab1b0 100644 --- a/src/waveform/widgets/glwaveformwidget.h +++ b/src/waveform/widgets/glwaveformwidget.h @@ -1,11 +1,11 @@ #ifndef GLWAVEFORMWIDGET_H #define GLWAVEFORMWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class GLWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class GLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: GLWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/hsvwaveformwidget.cpp b/src/waveform/widgets/hsvwaveformwidget.cpp index 14d7ec1670f9..c4c920d1e2c1 100644 --- a/src/waveform/widgets/hsvwaveformwidget.cpp +++ b/src/waveform/widgets/hsvwaveformwidget.cpp @@ -1,6 +1,7 @@ #include "hsvwaveformwidget.h" #include +#include #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" diff --git a/src/waveform/widgets/qtsimplewaveformwidget.cpp b/src/waveform/widgets/qtsimplewaveformwidget.cpp index 5de3acc81d40..9e1397ac6dbf 100644 --- a/src/waveform/widgets/qtsimplewaveformwidget.cpp +++ b/src/waveform/widgets/qtsimplewaveformwidget.cpp @@ -2,8 +2,8 @@ #include #include +#include -#include "waveform/sharedglcontext.h" #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" #include "waveform/renderers/qtwaveformrenderersimplesignal.h" @@ -16,7 +16,7 @@ #include "util/performancetimer.h" QtSimpleWaveformWidget::QtSimpleWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); addRenderer(); @@ -29,25 +29,20 @@ QtSimpleWaveformWidget::QtSimpleWaveformWidget(const char* group, QWidget* paren setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); } QtSimpleWaveformWidget::~QtSimpleWaveformWidget() { - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } } void QtSimpleWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void QtSimpleWaveformWidget::paintEvent(QPaintEvent* event) { @@ -59,7 +54,7 @@ mixxx::Duration QtSimpleWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/qtsimplewaveformwidget.h b/src/waveform/widgets/qtsimplewaveformwidget.h index 2b87555f9ed6..fc5ca316b947 100644 --- a/src/waveform/widgets/qtsimplewaveformwidget.h +++ b/src/waveform/widgets/qtsimplewaveformwidget.h @@ -1,11 +1,11 @@ #ifndef QTSIMPLEWAVEFORMWIDGET_H #define QTSIMPLEWAVEFORMWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class QtSimpleWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class QtSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: QtSimpleWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/qtwaveformwidget.cpp b/src/waveform/widgets/qtwaveformwidget.cpp index bede3c690c40..ee6a8ca497e1 100644 --- a/src/waveform/widgets/qtwaveformwidget.cpp +++ b/src/waveform/widgets/qtwaveformwidget.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "waveform/widgets/qtwaveformwidget.h" @@ -12,12 +12,11 @@ #include "waveform/renderers/waveformrendermarkrange.h" #include "waveform/renderers/waveformrendererendoftrack.h" #include "waveform/renderers/waveformrenderbeat.h" -#include "waveform/sharedglcontext.h" #include "util/performancetimer.h" QtWaveformWidget::QtWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WaveformWidgetAbstract(group) { addRenderer(); addRenderer(); @@ -30,12 +29,7 @@ QtWaveformWidget::QtWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { + if (QOpenGLContext::currentContext() != context()) { makeCurrent(); } m_initSuccess = init(); @@ -45,7 +39,7 @@ QtWaveformWidget::~QtWaveformWidget() { } void QtWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void QtWaveformWidget::paintEvent(QPaintEvent* event) { @@ -57,7 +51,7 @@ mixxx::Duration QtWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2, t3; timer.start(); - // QPainter makes QGLContext::currentContext() == context() + // QPainter makes QOpenGLContext::currentContext() == context() // this may delayed until previous buffer swap finished QPainter painter(this); t1 = timer.restart(); diff --git a/src/waveform/widgets/qtwaveformwidget.h b/src/waveform/widgets/qtwaveformwidget.h index 7ab1d88d5f28..5121357571ff 100644 --- a/src/waveform/widgets/qtwaveformwidget.h +++ b/src/waveform/widgets/qtwaveformwidget.h @@ -1,11 +1,11 @@ #ifndef QTWAVEFORMWIDGET_H #define QTWAVEFORMWIDGET_H -#include +#include #include "waveformwidgetabstract.h" -class QtWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class QtWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { Q_OBJECT public: QtWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/waveformwidgetabstract.h b/src/waveform/widgets/waveformwidgetabstract.h index 5d294bb02432..4c5707149146 100644 --- a/src/waveform/widgets/waveformwidgetabstract.h +++ b/src/waveform/widgets/waveformwidgetabstract.h @@ -13,7 +13,7 @@ class VSyncThread; // NOTE(vRince) This class represent objects the waveformwidgetfactory can // holds, IMPORTANT all WaveformWidgetAbstract MUST inherist QWidget too !! we -// can't do it here because QWidget and QGLWidget are both QWidgets so they +// can't do it here because QWidget and QOpenGLWidget are both QWidgets so they // already have a common QWidget base class (ambiguous polymorphism) class WaveformWidgetAbstract : public WaveformWidgetRenderer { diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 88aa46fd2ab1..3722a3d314d1 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -8,7 +8,6 @@ #include "control/controlproxy.h" #include "library/coverartcache.h" #include "util/dnd.h" -#include "waveform/sharedglcontext.h" #include "util/math.h" #include "waveform/visualplayposition.h" #include "vinylcontrol/vinylcontrol.h" @@ -21,7 +20,7 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, UserSettingsPointer pConfig, VinylControlManager* pVCMan, BaseTrackPlayer* pPlayer) - : QGLWidget(QGLFormat(QGL::SampleBuffers), parent, SharedGLContext::getWidget()), + : QOpenGLWidget(parent), WBaseWidget(this), m_group(group), m_pConfig(pConfig), @@ -65,9 +64,6 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, #endif //Drag and drop setAcceptDrops(true); - qDebug() << "WSpinny(): Created QGLWidget, Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); CoverArtCache* pCache = CoverArtCache::instance(); if (pCache != nullptr) { @@ -657,7 +653,7 @@ bool WSpinny::event(QEvent* pEvent) { if (pEvent->type() == QEvent::ToolTip) { updateTooltip(); } - return QGLWidget::event(pEvent); + return QOpenGLWidget::event(pEvent); } void WSpinny::dragEnterEvent(QDragEnterEvent* event) { diff --git a/src/widget/wspinny.h b/src/widget/wspinny.h index 64efe28239e8..43dcb2c8f3c5 100644 --- a/src/widget/wspinny.h +++ b/src/widget/wspinny.h @@ -2,7 +2,7 @@ #ifndef _WSPINNY_H #define _WSPINNY_H -#include +#include #include #include #include @@ -21,7 +21,7 @@ class ControlProxy; class VisualPlayPosition; class VinylControlManager; -class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityListener { +class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQualityListener { Q_OBJECT public: WSpinny(QWidget* parent, const QString& group, From e6e230517aab76d0a5b154f0badc4bc370cf8403 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 14:12:53 -0800 Subject: [PATCH 02/30] Fix method collision between WaveformWidgetAbstract and QOpenGLWidget. WaveformWidgetAbstract::isValid -> isInitialized. --- src/waveform/waveformwidgetfactory.cpp | 6 +++--- src/waveform/widgets/waveformwidgetabstract.cpp | 2 +- src/waveform/widgets/waveformwidgetabstract.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 849175b71c99..e45ec9c4c7bf 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -815,12 +815,12 @@ WaveformWidgetAbstract* WaveformWidgetFactory::createWaveformWidget( break; } widget->castToQWidget(); - if (!widget->isValid()) { - qWarning() << "failed to init WafeformWidget" << type << "fall back to \"Empty\""; + if (!widget->isInitialized()) { + qWarning() << "failed to init WaveformWidget" << type << "fall back to \"Empty\""; delete widget; widget = new EmptyWaveformWidget(viewer->getGroup(), viewer); widget->castToQWidget(); - if (!widget->isValid()) { + if (!widget->isInitialized()) { qWarning() << "failed to init EmptyWaveformWidget"; delete widget; widget = NULL; diff --git a/src/waveform/widgets/waveformwidgetabstract.cpp b/src/waveform/widgets/waveformwidgetabstract.cpp index a22237bc4abc..329b4fe77e11 100644 --- a/src/waveform/widgets/waveformwidgetabstract.cpp +++ b/src/waveform/widgets/waveformwidgetabstract.cpp @@ -7,8 +7,8 @@ WaveformWidgetAbstract::WaveformWidgetAbstract(const char* group) : WaveformWidgetRenderer(group), + m_widget(nullptr), m_initSuccess(false) { - m_widget = NULL; } WaveformWidgetAbstract::~WaveformWidgetAbstract() { diff --git a/src/waveform/widgets/waveformwidgetabstract.h b/src/waveform/widgets/waveformwidgetabstract.h index 4c5707149146..2582dfce07b8 100644 --- a/src/waveform/widgets/waveformwidgetabstract.h +++ b/src/waveform/widgets/waveformwidgetabstract.h @@ -24,7 +24,7 @@ class WaveformWidgetAbstract : public WaveformWidgetRenderer { //Type is use by the factory to safely up-cast waveform widgets virtual WaveformWidgetType::Type getType() const = 0; - bool isValid() const { return (m_widget && m_initSuccess); } + bool isInitialized() const { return (m_widget && m_initSuccess); } QWidget* getWidget() { return m_widget; } void hold(); From eb7b2b1d64f3e910a5f534d6f7e017945fc8dfa2 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 14:22:36 -0800 Subject: [PATCH 03/30] Fix more QGLWidget references that were added in 2.2. --- src/waveform/waveformwidgetfactory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index e45ec9c4c7bf..08ad7a136adb 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -42,9 +42,9 @@ bool shouldRenderWaveform(WaveformWidgetAbstract* pWaveformWidget) { return false; } - auto glw = dynamic_cast(pWaveformWidget->getWidget()); + auto glw = dynamic_cast(pWaveformWidget->getWidget()); if (glw == nullptr) { - // Not a QGLWidget. We can simply use QWidget::isVisible. + // Not a QOpenGLWidget. We can simply use QWidget::isVisible. auto qwidget = dynamic_cast(pWaveformWidget->getWidget()); return qwidget != nullptr && qwidget->isVisible(); } @@ -579,8 +579,8 @@ void WaveformWidgetFactory::render() { } } - // WSpinnys are also double-buffered QGLWidgets, like all the waveform - // renderers. Render all the WSpinny widgets now. + // WSpinnys are also double-buffered QOpenGLWidgets, like all the + // waveform renderers. Render all the WSpinny widgets now. emit(renderSpinnies()); // Notify all other waveform-like widgets (e.g. WSpinny's) that they should @@ -631,8 +631,8 @@ void WaveformWidgetFactory::swap() { //qDebug() << "swap x" << m_vsyncThread->elapsed(); } } - // WSpinnys are also double-buffered QGLWidgets, like all the waveform - // renderers. Swap all the WSpinny widgets now. + // WSpinnys are also double-buffered QOpenGLWidgets, like all the + // waveform renderers. Swap all the WSpinny widgets now. emit(swapSpinnies()); } //qDebug() << "swap end" << m_vsyncThread->elapsed(); From fe011aeb8091054ecf90ed8acae12039ea1b9923 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 14:26:44 -0800 Subject: [PATCH 04/30] Remove WSpinny "No OpenGL" fallback. QOpenGLWidget::isValid does not return true until the widget is displayed, so we can't check if the WSpinny is valid during skin parsing. --- src/skin/legacyskinparser.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 00f80e31c86f..4e0ad9dcd625 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -1181,13 +1181,6 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) { BaseTrackPlayer* pPlayer = m_pPlayerManager->getPlayer(channelStr); WSpinny* spinny = new WSpinny(m_pParent, channelStr, m_pConfig, m_pVCManager, pPlayer); - if (!spinny->isValid()) { - delete spinny; - WLabel* dummy = new WLabel(m_pParent); - //: Shown when Spinny can not be displayed. Please keep \n unchanged - dummy->setText(tr("No OpenGL\nsupport.")); - return dummy; - } commonWidgetSetup(node, spinny); auto waveformWidgetFactory = WaveformWidgetFactory::instance(); From 793af641f3db276fa31cf4e2232603efd1a22637 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 16:08:21 -0800 Subject: [PATCH 05/30] Migrate GLSLWaveformRendererSignal to QtOpenGL. --- .../renderers/glslwaveformrenderersignal.cpp | 72 ++++++++----------- .../renderers/glslwaveformrenderersignal.h | 11 ++- 2 files changed, 34 insertions(+), 49 deletions(-) diff --git a/src/waveform/renderers/glslwaveformrenderersignal.cpp b/src/waveform/renderers/glslwaveformrenderersignal.cpp index bc7ca730b889..779a04b88614 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.cpp +++ b/src/waveform/renderers/glslwaveformrenderersignal.cpp @@ -1,4 +1,4 @@ -#include +#include #include "waveform/renderers/glslwaveformrenderersignal.h" #include "waveform/renderers/waveformwidgetrenderer.h" @@ -13,7 +13,6 @@ GLSLWaveformRendererSignal::GLSLWaveformRendererSignal(WaveformWidgetRenderer* w m_textureId(0), m_textureRenderedWaveformCompletion(0), m_bDumpPng(false), - m_shadersValid(false), m_rgbShader(rgbShader) { } @@ -33,43 +32,35 @@ void GLSLWaveformRendererSignal::debugClick() { } bool GLSLWaveformRendererSignal::loadShaders() { - qDebug() << "GLWaveformRendererSignalShader::loadShaders"; - m_shadersValid = false; - - if (m_frameShaderProgram->isLinked()) { - m_frameShaderProgram->release(); + if (m_frameShaderProgram) { + return true; } + qDebug() << "GLWaveformRendererSignalShader::loadShaders"; + auto frameShaderProgram = std::make_unique(); - m_frameShaderProgram->removeAllShaders(); - - if (!m_frameShaderProgram->addShaderFromSourceFile( - QGLShader::Vertex, ":shaders/passthrough.vert")) { - qDebug() << "GLWaveformRendererSignalShader::loadShaders - " - << m_frameShaderProgram->log(); + if (!frameShaderProgram->addShaderFromSourceFile( + QOpenGLShader::Vertex, ":shaders/passthrough.vert")) { + qDebug() << "GLWaveformRendererSignalShader::loadShaders addShaderFromSourceFile failed for passthrough.vert" + << frameShaderProgram->log(); return false; } QString fragmentShader = m_rgbShader ? ":/shaders/rgbsignal.frag" : ":/shaders/filteredsignal.frag"; - if (!m_frameShaderProgram->addShaderFromSourceFile( - QGLShader::Fragment, fragmentShader)) { - qDebug() << "GLWaveformRendererSignalShader::loadShaders - " - << m_frameShaderProgram->log(); + if (!frameShaderProgram->addShaderFromSourceFile( + QOpenGLShader::Fragment, fragmentShader)) { + qDebug() << "GLWaveformRendererSignalShader::loadShaders addShaderFromSourceFile failed for" << fragmentShader + << frameShaderProgram->log(); return false; } - if (!m_frameShaderProgram->link()) { - qDebug() << "GLWaveformRendererSignalShader::loadShaders - " - << m_frameShaderProgram->log(); + if (!frameShaderProgram->link()) { + qDebug() << "GLWaveformRendererSignalShader::loadShaders link failed " + << frameShaderProgram->log(); return false; } - if (!m_frameShaderProgram->bind()) { - qDebug() << "GLWaveformRendererSignalShader::loadShaders - shaders binding failed"; - return false; - } - - m_shadersValid = true; + m_frameShaderProgram = std::move(frameShaderProgram); return true; } @@ -171,6 +162,9 @@ void GLSLWaveformRendererSignal::createGeometry() { } void GLSLWaveformRendererSignal::createFrameBuffers() { + if (m_framebuffer) { + return; + } const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); // We create a frame buffer that is 4x the size of the renderer itself to // "oversample" the texture relative to the surface we're drawing on. @@ -178,29 +172,19 @@ void GLSLWaveformRendererSignal::createFrameBuffers() { const int bufferWidth = oversamplingFactor * m_waveformRenderer->getWidth() * devicePixelRatio; const int bufferHeight = oversamplingFactor * m_waveformRenderer->getHeight() * devicePixelRatio; - m_framebuffer = std::make_unique(bufferWidth, - bufferHeight); + auto framebuffer = std::make_unique(bufferWidth, + bufferHeight); - if (!m_framebuffer->isValid()) { + if (!framebuffer->isValid()) { qWarning() << "GLSLWaveformRendererSignal::createFrameBuffer - frame buffer not valid"; + return; } + m_framebuffer = std::move(framebuffer); } bool GLSLWaveformRendererSignal::onInit() { m_textureRenderedWaveformCompletion = 0; - - if (!m_frameShaderProgram) { - m_frameShaderProgram = std::make_unique(); - } - - if (!loadShaders()) { - return false; - } createGeometry(); - if (!loadTexture()) { - return false; - } - return true; } @@ -231,7 +215,7 @@ void GLSLWaveformRendererSignal::onSetTrack() { } void GLSLWaveformRendererSignal::onResize() { - createFrameBuffers(); + m_framebuffer.reset(); } void GLSLWaveformRendererSignal::slotWaveformUpdated() { @@ -240,7 +224,9 @@ void GLSLWaveformRendererSignal::slotWaveformUpdated() { } void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { - if (!m_framebuffer || !m_framebuffer->isValid() || !m_shadersValid) { + loadShaders(); + createFrameBuffers(); + if (!m_framebuffer || !m_framebuffer->isValid() || !m_frameShaderProgram) { return; } diff --git a/src/waveform/renderers/glslwaveformrenderersignal.h b/src/waveform/renderers/glslwaveformrenderersignal.h index 8e8887afb7c6..8743d732a2e0 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.h +++ b/src/waveform/renderers/glslwaveformrenderersignal.h @@ -1,8 +1,8 @@ #ifndef GLWAVEFORMRENDERERSIGNALSHADER_H #define GLWAVEFORMRENDERERSIGNALSHADER_H -#include -#include +#include +#include #include #include "track/track.h" @@ -41,14 +41,13 @@ class GLSLWaveformRendererSignal : public QObject, public WaveformRendererSignal int m_textureRenderedWaveformCompletion; // Frame buffer for two pass rendering. - std::unique_ptr m_framebuffer; + std::unique_ptr m_framebuffer; bool m_bDumpPng; // shaders - bool m_shadersValid; - bool m_rgbShader; - std::unique_ptr m_frameShaderProgram; + const bool m_rgbShader; + std::unique_ptr m_frameShaderProgram; }; class GLSLWaveformRendererFilteredSignal : public GLSLWaveformRendererSignal { From 6f0d70d3993315b4bc9215e2991e48cf38922a83 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 17:01:37 -0800 Subject: [PATCH 06/30] Remove checks that QWidget::windowHandle()->isExposed() for QtOpenGLWidgets. QWidget::windowHandle is nullptr for QOpenGLWidgets. --- src/waveform/waveformwidgetfactory.cpp | 7 ------- src/widget/wspinny.cpp | 9 --------- 2 files changed, 16 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 08ad7a136adb..f526643d264e 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -53,13 +53,6 @@ bool shouldRenderWaveform(WaveformWidgetAbstract* pWaveformWidget) { return false; } - // Strangely, a widget can have non-zero width/height, be valid and visible, - // yet still not show up on the screen. QWindow::isExposed tells us this. - auto window = glw->windowHandle(); - if (window == nullptr || !window->isExposed()) { - return false; - } - return true; } } // anonymous namespace diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 97e12e2a9c95..ecc92751585e 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -299,11 +299,6 @@ void WSpinny::render() { return; } - auto window = windowHandle(); - if (window == nullptr || !window->isExposed()) { - return; - } - if (!m_pVisualPlayPos.isNull()) { m_pVisualPlayPos->getPlaySlipAt(0, &m_dAngleCurrentPlaypos, @@ -383,10 +378,6 @@ void WSpinny::swap() { if (!isValid() || !isVisible()) { return; } - auto window = windowHandle(); - if (window == nullptr || !window->isExposed()) { - return; - } VSyncThread::swapGl(this, 0); } From 00b8e7c0e4817e7f703a4d918d039ae390511a98 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 17:29:54 -0800 Subject: [PATCH 07/30] Remove setAutoBufferSwap. --- src/widget/wspinny.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index ecc92751585e..a091aa3bc8c0 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -89,9 +89,7 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoFillBackground(false); - setAutoBufferSwap(false); } WSpinny::~WSpinny() { From 1fcc1b5b33235272ae1312b4347e55967fb28992 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Fri, 28 Dec 2018 17:34:56 -0800 Subject: [PATCH 08/30] Replace QGLFormat::setDefaultFormat with QSurfaceFormat::setDefaultFormat. Also set the Qt::AA_ShareOpenGLContexts QApplication attribute to achieve GL context sharing. As per the documentation, calls QSurfaceFormat::setDefaultFormat before the QApplication is created to avoid issues with shared GL contexts. --- res/shaders/passthrough.vert | 3 +-- src/main.cpp | 2 ++ src/waveform/waveformwidgetfactory.cpp | 34 +++++++++----------------- src/waveform/waveformwidgetfactory.h | 2 ++ 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/res/shaders/passthrough.vert b/res/shaders/passthrough.vert index 38ce32d8f83c..07fd12edfec3 100644 --- a/res/shaders/passthrough.vert +++ b/res/shaders/passthrough.vert @@ -1,8 +1,7 @@ -//#version 100 +#version 120 void main(void) { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } - diff --git a/src/main.cpp b/src/main.cpp index 31792cbf6f09..d7ec389c44d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ #include "util/console.h" #include "util/logging.h" #include "util/version.h" +#include "waveform/waveformwidgetfactory.h" #ifdef Q_OS_LINUX #include @@ -72,6 +73,7 @@ int main(int argc, char * argv[]) { #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif + WaveformWidgetFactory::setDefaultSurfaceFormat(); // Setting the organization name results in a QDesktopStorage::DataLocation // of "$HOME/Library/Application Support/Mixxx/Mixxx" on OS X. Leave the diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index f526643d264e..2cc420804bcb 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -110,29 +110,6 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_visualGain[High] = 1.0; if (!CmdlineArgs::Instance().getSafeMode() && QGLFormat::hasOpenGL()) { - QGLFormat glFormat; - glFormat.setDirectRendering(true); - glFormat.setDoubleBuffer(true); - glFormat.setDepth(false); - // Disable waiting for vertical Sync - // This can be enabled when using a single Threads for each QGLContext - // Setting 1 causes QGLContext::swapBuffer to sleep until the next VSync -#if defined(__APPLE__) - // On OS X, syncing to vsync has good performance FPS-wise and - // eliminates tearing. - glFormat.setSwapInterval(1); -#else - // Otherwise, turn VSync off because it could cause horrible FPS on - // Linux. - // TODO(XXX): Make this configurable. - // TODO(XXX): What should we do on Windows? - glFormat.setSwapInterval(0); -#endif - - - glFormat.setRgba(true); - QGLFormat::setDefaultFormat(glFormat); - QGLFormat::OpenGLVersionFlags version = QGLFormat::openGLVersionFlags(); int majorVersion = 0; @@ -857,3 +834,14 @@ float WaveformWidgetFactory::getDevicePixelRatio() { } return devicePixelRatio; } + +void WaveformWidgetFactory::setDefaultSurfaceFormat() { + QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + QSurfaceFormat defaultFormat; + defaultFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + defaultFormat.setSwapInterval(1); + defaultFormat.setProfile(QSurfaceFormat::CompatibilityProfile); + defaultFormat.setRenderableType(QSurfaceFormat::OpenGL); + defaultFormat.setVersion(2, 1); + QSurfaceFormat::setDefaultFormat(defaultFormat); +} diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index f53af12786a8..27219390e5bd 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -60,6 +60,8 @@ class WaveformWidgetFactory : public QObject, public Singleton Date: Fri, 28 Dec 2018 18:50:18 -0800 Subject: [PATCH 09/30] Update OpenGL version detection to use QSurfaceFormat. --- src/waveform/waveformwidgetfactory.cpp | 86 +++++--------------------- 1 file changed, 15 insertions(+), 71 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 2cc420804bcb..79fe32f22138 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -109,79 +109,23 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_visualGain[Mid] = 1.0; m_visualGain[High] = 1.0; - if (!CmdlineArgs::Instance().getSafeMode() && QGLFormat::hasOpenGL()) { - QGLFormat::OpenGLVersionFlags version = QGLFormat::openGLVersionFlags(); - - int majorVersion = 0; - int minorVersion = 0; - if (version == QGLFormat::OpenGL_Version_None) { - m_openGLVersion = "None"; -// Flags introduced in Qt 5.2. -#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) - } else if (version & QGLFormat::OpenGL_Version_4_3) { - majorVersion = 4; - minorVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_4_2) { - majorVersion = 4; - minorVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_4_1) { - majorVersion = 4; - minorVersion = 1; -#endif -// Flags introduced in Qt 4.7. -#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) - } else if (version & QGLFormat::OpenGL_Version_4_0) { - majorVersion = 4; - minorVersion = 0; - } else if (version & QGLFormat::OpenGL_Version_3_3) { - majorVersion = 3; - minorVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_3_2) { - majorVersion = 3; - minorVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_3_1) { - majorVersion = 3; - minorVersion = 1; -#endif - } else if (version & QGLFormat::OpenGL_Version_3_0) { - majorVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_2_1) { - majorVersion = 2; - minorVersion = 1; - } else if (version & QGLFormat::OpenGL_Version_2_0) { - majorVersion = 2; - minorVersion = 0; - } else if (version & QGLFormat::OpenGL_Version_1_5) { - majorVersion = 1; - minorVersion = 5; - } else if (version & QGLFormat::OpenGL_Version_1_4) { - majorVersion = 1; - minorVersion = 4; - } else if (version & QGLFormat::OpenGL_Version_1_3) { - majorVersion = 1; - minorVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_1_2) { - majorVersion = 1; - minorVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_1_1) { - majorVersion = 1; - minorVersion = 1; - } - - if (majorVersion != 0) { - m_openGLVersion = QString::number(majorVersion) + "." + - QString::number(minorVersion); - } + const bool safeMode = CmdlineArgs::Instance().getSafeMode(); + QWindow* pWindow = QGuiApplication::focusWindow(); + if (safeMode) { + m_openGLVersion = tr("Safe Mode"); + } else if (pWindow && pWindow->supportsOpenGL()) { m_openGLAvailable = true; - - QOpenGLWidget* glWidget = new QOpenGLWidget(); // create paint device - // QGLShaderProgram::hasOpenGLShaderPrograms(); valgind error - // Without a makeCurrent, hasOpenGLShaderPrograms returns false on Qt 5. - glWidget->makeCurrent(); - m_openGLShaderAvailable = - QOpenGLShaderProgram::hasOpenGLShaderPrograms(glWidget->context()); - delete glWidget; + const auto format = pWindow->format(); + const auto major_minor = format.version(); + m_openGLVersion = QString("%1 %2.%3").arg( + format.renderableType() == QSurfaceFormat::OpenGL ? "OpenGL" : "OpenGLES", + QString::number(major_minor.first), + QString::number(major_minor.second)); + // Mixxx requires GLSL 1.20, which corresponds to OpenGL version 2.1. + m_openGLShaderAvailable = major_minor.first > 2 || (major_minor.first == 2 && major_minor.second >= 1); + } else { + m_openGLVersion = tr("None"); } evaluateWidgets(); From 569a99ffce42d8e9d56cced8771781585c256c7a Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Wed, 2 Jan 2019 19:28:12 -0800 Subject: [PATCH 10/30] Call QOpenGLWidget::resizeEvent from WSpinny::resizeEvent. Quoth the QOpenGLWidget docs: """ Avoid overriding this function in derived classes. If that is not feasible, make sure that QOpenGLWidget's implementation is invoked too. Otherwise the underlying framebuffer object and related resources will not get resized properly and will lead to incorrect rendering. """ --- src/widget/wspinny.cpp | 3 ++- src/widget/wspinny.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index a091aa3bc8c0..bc4c7b3da235 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -387,7 +387,8 @@ QPixmap WSpinny::scaledCoverArt(const QPixmap& normal) { return normal.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } -void WSpinny::resizeEvent(QResizeEvent* /*unused*/) { +void WSpinny::resizeEvent(QResizeEvent* event) { + QOpenGLWidget::resizeEvent(event); m_loadedCoverScaled = scaledCoverArt(m_loadedCover); if (m_pFgImage && !m_pFgImage->isNull()) { m_fgImageScaled = m_pFgImage->scaled( diff --git a/src/widget/wspinny.h b/src/widget/wspinny.h index 3ccc2e93c46c..50492ac7228c 100644 --- a/src/widget/wspinny.h +++ b/src/widget/wspinny.h @@ -66,7 +66,7 @@ class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQual void mouseMoveEvent(QMouseEvent * e) override; void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; - void resizeEvent(QResizeEvent* /*unused*/) override; + void resizeEvent(QResizeEvent* event) override; void showEvent(QShowEvent* event) override; void hideEvent(QHideEvent* event) override; bool event(QEvent* pEvent) override; From 0d78720ce729b7af43e9c59619c476e9bdac301a Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 31 Dec 2018 13:13:58 -0800 Subject: [PATCH 11/30] Restructure the flow of rendering QOpenGLWidgets. Summary: * Remove responsibility for swapping QOpenGLWidgets from the VSyncThread. * Introduce BaseQOpenGLWidget, a base class for QOpenGLWidget waveforms. * Inherit all QOpenGLWidget waveforms from BaseQOpenGLWidget. * Use aboutToCompose/frameSwapped signals from QOpenGLWidget to determine when to render widgets. * Add the same logic from BaseQOpenGLWidget to WSpinny. After this change the VSyncThread's purpose is to send render ticks to the main thread at the user's configured FPS. It still communicates with the main thread via semaphore, so it can't flood the main thread with signals. A render signal from the VSyncThread causes all QOpenGLWidgets to set a boolean "render on next tick", which when QOpenGLWidget::aboutToCompose fires next, kicks off a blocking render of the widget. One important function of the VSyncThread is that it estimates when the next vsync is. We use this to smoothly interpolate each deck's playposition so that the position we render on the screen at the next swap is where the deck *was* or *will be* at the moment the audio comes out the speakers, assuming the deck continues forward linearly at its last measured rate. This prevents the waveform from "jerking" caused by the interplay between the waveform render period and the audio callback period. To get this equivalent behavior in the new setting, I added an estimator for the time until the next swap by measuring the time between a QOpenGLWidget receiving an aboutToCompose signal from Qt's backing store until the time it receives a frameSwapped signal indicating the widget is now visible. Each widget keeps an exponentially weighted moving average of this estimate, and uses it to estimate the time until swap, which is fed into the playposition interpolation logic in VisualPlayPosition. --- build/depends.py | 1 + src/skin/legacyskinparser.cpp | 4 +- .../renderers/waveformwidgetrenderer.cpp | 4 +- .../renderers/waveformwidgetrenderer.h | 4 +- src/waveform/visualplayposition.cpp | 37 +++++++++---- src/waveform/visualplayposition.h | 12 ++--- src/waveform/vsyncthread.cpp | 52 ++++-------------- src/waveform/vsyncthread.h | 5 +- src/waveform/waveformwidgetfactory.cpp | 53 ++----------------- src/waveform/waveformwidgetfactory.h | 2 - src/waveform/widgets/baseqopenglwidget.cpp | 29 ++++++++++ src/waveform/widgets/baseqopenglwidget.h | 29 ++++++++++ src/waveform/widgets/emptywaveformwidget.h | 4 +- src/waveform/widgets/glrgbwaveformwidget.cpp | 4 +- src/waveform/widgets/glrgbwaveformwidget.h | 10 ++-- .../widgets/glsimplewaveformwidget.cpp | 3 +- src/waveform/widgets/glsimplewaveformwidget.h | 10 ++-- src/waveform/widgets/glslwaveformwidget.cpp | 4 +- src/waveform/widgets/glslwaveformwidget.h | 10 ++-- src/waveform/widgets/glvsynctestwidget.cpp | 4 +- src/waveform/widgets/glvsynctestwidget.h | 10 ++-- src/waveform/widgets/glwaveformwidget.cpp | 4 +- src/waveform/widgets/glwaveformwidget.h | 10 ++-- .../widgets/qtsimplewaveformwidget.cpp | 3 +- src/waveform/widgets/qtsimplewaveformwidget.h | 11 ++-- src/waveform/widgets/qtwaveformwidget.cpp | 3 +- src/waveform/widgets/qtwaveformwidget.h | 10 ++-- .../widgets/waveformwidgetabstract.cpp | 7 +-- src/waveform/widgets/waveformwidgetabstract.h | 9 ++-- src/widget/wspinny.cpp | 42 +++++++++++---- src/widget/wspinny.h | 14 ++++- 31 files changed, 210 insertions(+), 194 deletions(-) create mode 100644 src/waveform/widgets/baseqopenglwidget.cpp create mode 100644 src/waveform/widgets/baseqopenglwidget.h diff --git a/build/depends.py b/build/depends.py index 754be4d892ed..1c98ad2a53ba 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1097,6 +1097,7 @@ def sources(self, build): "src/waveform/renderers/glslwaveformrenderersignal.cpp", "src/waveform/renderers/glvsynctestrenderer.cpp", + "src/waveform/widgets/baseqopenglwidget.cpp", "src/waveform/widgets/waveformwidgetabstract.cpp", "src/waveform/widgets/emptywaveformwidget.cpp", "src/waveform/widgets/softwarewaveformwidget.cpp", diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 4e0ad9dcd625..4c97269653f1 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -1185,9 +1185,7 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) { auto waveformWidgetFactory = WaveformWidgetFactory::instance(); connect(waveformWidgetFactory, SIGNAL(renderSpinnies()), - spinny, SLOT(render())); - connect(waveformWidgetFactory, SIGNAL(swapSpinnies()), - spinny, SLOT(swap())); + spinny, SLOT(slotShouldRenderOnNextTick())); connect(spinny, SIGNAL(trackDropped(QString, QString)), m_pPlayerManager, SLOT(slotLoadToPlayer(QString, QString))); connect(spinny, &WSpinny::cloneDeck, diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index 211914d13bed..195fc9ce81da 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -105,7 +105,7 @@ bool WaveformWidgetRenderer::init() { return true; } -void WaveformWidgetRenderer::onPreRender(VSyncThread* vsyncThread) { +void WaveformWidgetRenderer::onPreRender(mixxx::Duration estimatedTimeUntilSwap) { // For a valid track to render we need m_trackSamples = m_pTrackSamplesControlObject->get(); if (m_trackSamples <= 0.0) { @@ -140,7 +140,7 @@ void WaveformWidgetRenderer::onPreRender(VSyncThread* vsyncThread) { } - double truePlayPos = m_visualPlayPosition->getAtNextVSync(vsyncThread); + double truePlayPos = m_visualPlayPosition->getAtNextSwap(estimatedTimeUntilSwap); // m_playPos = -1 happens, when a new track is in buffer but m_visualPlayPosition was not updated if (m_audioSamplePerPixel && truePlayPos != -1) { diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 1632ac1be268..b402d9f4a38c 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -10,6 +10,7 @@ #include "util/class.h" #include "waveform/renderers/waveformrendererabstract.h" #include "waveform/renderers/waveformsignalcolors.h" +#include "util/duration.h" #include "util/performancetimer.h" //#define WAVEFORMWIDGETRENDERER_DEBUG @@ -17,7 +18,6 @@ class Track; class ControlProxy; class VisualPlayPosition; -class VSyncThread; class WaveformWidgetRenderer { public: @@ -34,7 +34,7 @@ class WaveformWidgetRenderer { virtual bool onInit() {return true;} void setup(const QDomNode& node, const SkinContext& context); - void onPreRender(VSyncThread* vsyncThread); + void onPreRender(mixxx::Duration estimatedTimeUntilSwap); void draw(QPainter* painter, QPaintEvent* event); inline const char* getGroup() const { return m_group;} diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index bf1e7a43bf82..26334ceb2da2 100644 --- a/src/waveform/visualplayposition.cpp +++ b/src/waveform/visualplayposition.cpp @@ -50,39 +50,54 @@ void VisualPlayPosition::set(double playPos, double rate, double positionStep, m_valid = true; } -double VisualPlayPosition::getAtNextVSync(VSyncThread* vsyncThread) { +double VisualPlayPosition::getAtNextSwap(mixxx::Duration estimatedTimeUntilSwap) { //static double testPos = 0; //testPos += 0.000017759; //0.000016608; // 1.46257e-05; //return testPos; if (m_valid) { VisualPlayPositionData data = m_data.getValue(); - int refToVSync = vsyncThread->fromTimerToNextSyncMicros(data.m_referenceTime); - int offset = refToVSync - data.m_callbackEntrytoDac; - offset = math_min(offset, m_audioBufferMicros * kMaxOffsetBufferCnt); + int microsUntilSwap = estimatedTimeUntilSwap.toIntegerMicros(); + int microsUntilDac = data.m_callbackEntrytoDac - data.m_referenceTime.elapsed().toIntegerMicros(); + + // playPos will be played in microsUntilDac seconds. If swap comes + // first, offset will be negative so that playpos goes backward. + int offsetMicros = microsUntilSwap - microsUntilDac; + offsetMicros = math_clamp(offsetMicros, + -m_audioBufferMicros * kMaxOffsetBufferCnt, + m_audioBufferMicros * kMaxOffsetBufferCnt); double playPos = data.m_enginePlayPos; // load playPos for the first sample in Buffer // add the offset for the position of the sample that will be transferred to the DAC // When the next display frame is displayed - playPos += data.m_positionStep * offset * data.m_rate / m_audioBufferMicros; //qDebug() << "playPos" << playPos << offset; + // TODO(rryan): m_audioBufferMicros is not accurate for this purpose. We + // should use the PortAudio reported actual latency instead of Mixxx's + // configured audio buffer size. + playPos += data.m_positionStep * offsetMicros * data.m_rate / m_audioBufferMicros; return playPos; } return -1; } -void VisualPlayPosition::getPlaySlipAt(int fromNowMicros, double* pPlayPosition, double* pSlipPosition) { +void VisualPlayPosition::getPlaySlipAt(mixxx::Duration estimatedTimeUntilSwap, + double* pPlayPosition, double* pSlipPosition) { //static double testPos = 0; //testPos += 0.000017759; //0.000016608; // 1.46257e-05; //return testPos; if (m_valid) { VisualPlayPositionData data = m_data.getValue(); - int elapsed = data.m_referenceTime.elapsed().toIntegerMicros(); - int dacFromNow = elapsed - data.m_callbackEntrytoDac; - int offset = dacFromNow - fromNowMicros; - offset = math_min(offset, m_audioBufferMicros * kMaxOffsetBufferCnt); + int microsUntilSwap = estimatedTimeUntilSwap.toIntegerMicros(); + int microsUntilDac = data.m_callbackEntrytoDac - data.m_referenceTime.elapsed().toIntegerMicros(); + int offsetMicros = microsUntilSwap - microsUntilDac; + offsetMicros = math_clamp(offsetMicros, + -m_audioBufferMicros * kMaxOffsetBufferCnt, + m_audioBufferMicros * kMaxOffsetBufferCnt); double playPos = data.m_enginePlayPos; // load playPos for the first sample in Buffer - playPos += data.m_positionStep * offset * data.m_rate / m_audioBufferMicros; + // TODO(rryan): m_audioBufferMicros is not accurate for this purpose. We + // should use the PortAudio reported actual latency instead of Mixxx's + // configured audio buffer size. + playPos += data.m_positionStep * offsetMicros * data.m_rate / m_audioBufferMicros; *pPlayPosition = playPos; *pSlipPosition = data.m_slipPosition; } diff --git a/src/waveform/visualplayposition.h b/src/waveform/visualplayposition.h index 0095a3b57fe5..31e0b12da526 100644 --- a/src/waveform/visualplayposition.h +++ b/src/waveform/visualplayposition.h @@ -6,11 +6,11 @@ #include #include +#include "util/duration.h" #include "util/performancetimer.h" #include "control/controlvalue.h" class ControlProxy; -class VSyncThread; // This class is for synchronizing the sound device DAC time with the waveforms, displayed on the // graphic device, using the CPU time @@ -23,7 +23,7 @@ class VSyncThread; // ^Start m_timeInfoTime | // | // GPU: ---------|----------------------------------- |--|------------------------------- -// ^Render Waveform sample X | ^VSync (New waveform is displayed +// ^Render Waveform sample X | ^Swap (New waveform is displayed // by use usFromTimerToNextSync ^swap Buffer class VisualPlayPositionData { @@ -46,10 +46,10 @@ class VisualPlayPosition : public QObject { // WARNING: Not thread safe. This function must be called only from the // engine thread. - void set(double playPos, double rate, double positionStep, - double slipPosition, double tempoTrackSeconds); - double getAtNextVSync(VSyncThread* vsyncThread); - void getPlaySlipAt(int usFromNow, double* playPosition, double* slipPosition); + void set(double playPos, double rate, double positionStep, double pSlipPosition, double tempoTrackSeconds); + double getAtNextSwap(mixxx::Duration estimatedTimeUntilSwap); + void getPlaySlipAt(mixxx::Duration estimatedTimeUntilSwap, + double* playPosition, double* slipPosition); double getEnginePlayPos(); void getTrackTime(double* pPlayPosition, double* pTempoTrackSeconds); diff --git a/src/waveform/vsyncthread.cpp b/src/waveform/vsyncthread.cpp index 1793728640ed..12bc72f5813a 100644 --- a/src/waveform/vsyncthread.cpp +++ b/src/waveform/vsyncthread.cpp @@ -1,14 +1,15 @@ #include -#include #include #include #include +#include #include "vsyncthread.h" #include "util/performancetimer.h" #include "util/event.h" #include "util/counter.h" #include "util/math.h" +#include "util/time.h" #include "waveform/guitick.h" #if defined(__APPLE__) @@ -62,15 +63,11 @@ void VSyncThread::run() { m_semaVsyncSlot.acquire(); Event::end("VsyncThread vsync render"); - Event::start("VsyncThread vsync swap"); - emit(vsyncSwap()); // swaps the new waveform to front - m_semaVsyncSlot.acquire(); - Event::end("VsyncThread vsync swap"); - m_timer.restart(); m_waitToSwapMicros = 1000; usleep(1000); } else { // if (m_vSyncMode == ST_TIMER) { + m_timer.restart(); Event::start("VsyncThread vsync render"); emit(vsyncRender()); // renders the new waveform. @@ -80,47 +77,18 @@ void VSyncThread::run() { m_semaVsyncSlot.acquire(); Event::end("VsyncThread vsync render"); - // qDebug() << "ST_TIMER " << lastMicros << restMicros; - int remainingForSwap = m_waitToSwapMicros - static_cast( - m_timer.elapsed().toIntegerMicros()); - // waiting for interval by sleep - if (remainingForSwap > 100) { - Event::start("VsyncThread usleep for VSync"); - usleep(remainingForSwap); - Event::end("VsyncThread usleep for VSync"); - } - - Event::start("VsyncThread vsync swap"); - // swaps the new waveform to front in case of gl-wf - emit(vsyncSwap()); - - // wait until swap occurred. It might be delayed due to driver vSync - // settings. - m_semaVsyncSlot.acquire(); - Event::end("VsyncThread vsync swap"); - - // <- Assume we are VSynced here -> - int lastSwapTime = static_cast(m_timer.restart().toIntegerMicros()); - if (remainingForSwap < 0) { - // Our swapping call was already delayed - // The real swap might happens on the following VSync, depending on driver settings - m_droppedFrames++; // Count as Real Time Error - droppedFrames.increment(); + int elapsed = m_timer.restart().toIntegerMicros(); + int sleepTimeMicros = m_syncIntervalTimeMicros - elapsed; + //qDebug() << "VsyncThread sleepTimeMicros" << sleepTimeMicros; + if (sleepTimeMicros > 100) { + usleep(sleepTimeMicros); + } else if (sleepTimeMicros < 0) { + m_droppedFrames++; } - // try to stay in right intervals - m_waitToSwapMicros = m_syncIntervalTimeMicros + - ((m_waitToSwapMicros - lastSwapTime) % m_syncIntervalTimeMicros); } } } - -// static -void VSyncThread::swapGl(QOpenGLWidget* glw, int index) { - Q_UNUSED(index); - // TODO: glw->swapBuffers() used to be called here, but it is not offered by the QOpenGLWidget -} - int VSyncThread::elapsed() { return static_cast(m_timer.elapsed().toIntegerMicros()); } diff --git a/src/waveform/vsyncthread.h b/src/waveform/vsyncthread.h index 8d1294469f80..8bc86137504e 100644 --- a/src/waveform/vsyncthread.h +++ b/src/waveform/vsyncthread.h @@ -28,6 +28,8 @@ #include "util/performancetimer.h" +// TODO(rryan): Rename to RenderThread or something, or possibly replace with a +// generic BlockingThreadTimer class. class VSyncThread : public QThread { Q_OBJECT public: @@ -40,8 +42,6 @@ class VSyncThread : public QThread { ST_COUNT // Dummy Type at last, counting possible types }; - static void swapGl(QOpenGLWidget* glw, int index); - VSyncThread(QObject* pParent); ~VSyncThread(); @@ -59,7 +59,6 @@ class VSyncThread : public QThread { signals: void vsyncRender(); - void vsyncSwap(); private: bool m_bDoRendering; diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 79fe32f22138..d9c0b160aa03 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -30,6 +30,7 @@ #include "waveform/vsyncthread.h" #include "util/cmdlineargs.h" #include "util/performancetimer.h" +#include "util/time.h" #include "util/timer.h" #include "util/math.h" @@ -465,19 +466,6 @@ void WaveformWidgetFactory::render() { if (!m_skipRender) { if (m_type) { // no regular updates for an empty waveform // next rendered frame is displayed after next buffer swap and than after VSync - QVarLengthArray shouldRenderWaveforms(m_waveformWidgetHolders.size()); - for (int i = 0; i < m_waveformWidgetHolders.size(); i++) { - WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget; - // Don't bother doing the pre-render work if we aren't going to - // render this widget. - bool shouldRender = shouldRenderWaveform(pWaveformWidget); - shouldRenderWaveforms[i] = shouldRender; - if (!shouldRender) { - continue; - } - // Calculate play position for the new Frame in following run - pWaveformWidget->preRender(m_vsyncThread); - } //qDebug() << "prerender" << m_vsyncThread->elapsed(); // It may happen that there is an artificially delayed due to @@ -485,10 +473,10 @@ void WaveformWidgetFactory::render() { // all render commands are delayed until the swap from the previous run is executed for (int i = 0; i < m_waveformWidgetHolders.size(); i++) { WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget; - if (!shouldRenderWaveforms[i]) { + if (!shouldRenderWaveform(pWaveformWidget)) { continue; } - pWaveformWidget->render(); + pWaveformWidget->renderOnNextTick(); //qDebug() << "render" << i << m_vsyncThread->elapsed(); } } @@ -520,39 +508,6 @@ void WaveformWidgetFactory::render() { m_vsyncThread->vsyncSlotFinished(); } -void WaveformWidgetFactory::swap() { - ScopedTimer t("WaveformWidgetFactory::swap() %1waveforms", m_waveformWidgetHolders.size()); - - // Do this in an extra slot to be sure to hit the desired interval - if (!m_skipRender) { - if (m_type) { // no regular updates for an empty waveform - // Show rendered buffer from last render() run - //qDebug() << "swap() start" << m_vsyncThread->elapsed(); - for (int i = 0; i < m_waveformWidgetHolders.size(); i++) { - WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget; - - // Don't swap invalid / invisible widgets or widgets with an - // unexposed window. Prevents continuous log spew of - // "QOpenGLContext::swapBuffers() called with non-exposed - // window, behavior is undefined" on Qt5. See Bug #1779487. - if (!shouldRenderWaveform(pWaveformWidget)) { - continue; - } - auto glw = dynamic_cast(pWaveformWidget->getWidget()); - if (glw != nullptr) { - VSyncThread::swapGl(glw, i); - } - //qDebug() << "swap x" << m_vsyncThread->elapsed(); - } - } - // WSpinnys are also double-buffered QOpenGLWidgets, like all the - // waveform renderers. Swap all the WSpinny widgets now. - emit(swapSpinnies()); - } - //qDebug() << "swap end" << m_vsyncThread->elapsed(); - m_vsyncThread->vsyncSlotFinished(); -} - WaveformWidgetType::Type WaveformWidgetFactory::autoChooseWidgetType() const { //default selection if (m_openGLAvailable) { @@ -761,8 +716,6 @@ void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick, VisualsManager* pVisua connect(m_vsyncThread, SIGNAL(vsyncRender()), this, SLOT(render())); - connect(m_vsyncThread, SIGNAL(vsyncSwap()), - this, SLOT(swap())); } void WaveformWidgetFactory::getAvailableVSyncTypes(QList >* pList) { diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index 27219390e5bd..880a6233bd3b 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -125,7 +125,6 @@ class WaveformWidgetFactory : public QObject, public Singleton +#include + +#include "util/duration.h" +#include "waveform/widgets/waveformwidgetabstract.h" + +class BaseQOpenGLWidget : public QOpenGLWidget, public WaveformWidgetAbstract { + Q_OBJECT + public: + BaseQOpenGLWidget(const char* group, QWidget* pParent); + virtual ~BaseQOpenGLWidget() = default; + + virtual mixxx::Duration render() override { + WaveformWidgetAbstract::render(); + return mixxx::Duration(); + } + + private slots: + void slotAboutToCompose(); + void slotFrameSwapped(); + + private: + mixxx::Duration m_lastRender; + mixxx::Duration m_lastSwapRender; + mixxx::Duration m_lastSwapDuration; + mixxx::Duration m_lastSwapDurationMovingAverage; +}; diff --git a/src/waveform/widgets/emptywaveformwidget.h b/src/waveform/widgets/emptywaveformwidget.h index 1e46d27ab1bb..0be1da7c9068 100644 --- a/src/waveform/widgets/emptywaveformwidget.h +++ b/src/waveform/widgets/emptywaveformwidget.h @@ -23,7 +23,9 @@ class EmptyWaveformWidget : public QWidget, public WaveformWidgetAbstract { protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: EmptyWaveformWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/glrgbwaveformwidget.cpp b/src/waveform/widgets/glrgbwaveformwidget.cpp index c2ac4db7a7f0..4c792aa1d39e 100644 --- a/src/waveform/widgets/glrgbwaveformwidget.cpp +++ b/src/waveform/widgets/glrgbwaveformwidget.cpp @@ -14,9 +14,7 @@ #include GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/glrgbwaveformwidget.h b/src/waveform/widgets/glrgbwaveformwidget.h index 272f21dae656..7de8a0a813dd 100644 --- a/src/waveform/widgets/glrgbwaveformwidget.h +++ b/src/waveform/widgets/glrgbwaveformwidget.h @@ -1,11 +1,9 @@ #ifndef GLRGBWAVEFORMWIDGET_H #define GLRGBWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class GLRGBWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class GLRGBWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLRGBWaveformWidget(const char* group, QWidget* parent); @@ -21,7 +19,9 @@ class GLRGBWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/glsimplewaveformwidget.cpp b/src/waveform/widgets/glsimplewaveformwidget.cpp index 6040fb9b2baf..dc217abddd5a 100644 --- a/src/waveform/widgets/glsimplewaveformwidget.cpp +++ b/src/waveform/widgets/glsimplewaveformwidget.cpp @@ -16,8 +16,7 @@ #include "util/performancetimer.h" GLSimpleWaveformWidget::GLSimpleWaveformWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/glsimplewaveformwidget.h b/src/waveform/widgets/glsimplewaveformwidget.h index 4ff9d7e75491..1cf0fa292b95 100644 --- a/src/waveform/widgets/glsimplewaveformwidget.h +++ b/src/waveform/widgets/glsimplewaveformwidget.h @@ -1,11 +1,9 @@ #ifndef GLSIMPLEWAVEFORMWIDGET_H #define GLSIMPLEWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class GLSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class GLSimpleWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLSimpleWaveformWidget(const char* group, QWidget* parent); @@ -21,7 +19,9 @@ class GLSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstra protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/glslwaveformwidget.cpp b/src/waveform/widgets/glslwaveformwidget.cpp index 715af86ac4e9..b25c3614ce7b 100644 --- a/src/waveform/widgets/glslwaveformwidget.cpp +++ b/src/waveform/widgets/glslwaveformwidget.cpp @@ -14,6 +14,7 @@ #include "waveform/renderers/waveformrenderbeat.h" #include "util/performancetimer.h" +#include "util/time.h" GLSLFilteredWaveformWidget::GLSLFilteredWaveformWidget(const char* group, QWidget* parent) @@ -26,8 +27,7 @@ GLSLRGBWaveformWidget::GLSLRGBWaveformWidget(const char* group, QWidget* parent) GLSLWaveformWidget::GLSLWaveformWidget(const char* group, QWidget* parent, bool rgbRenderer) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/glslwaveformwidget.h b/src/waveform/widgets/glslwaveformwidget.h index 7f7e39c3153e..4f40f96968fd 100644 --- a/src/waveform/widgets/glslwaveformwidget.h +++ b/src/waveform/widgets/glslwaveformwidget.h @@ -1,13 +1,12 @@ #ifndef GLWAVEFORMWIDGETSHADER_H #define GLWAVEFORMWIDGETSHADER_H -#include - -#include "waveformwidgetabstract.h" +#include "waveform/widgets/baseqopenglwidget.h" +#include "util/duration.h" class GLSLWaveformRendererSignal; -class GLSLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class GLSLWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLSLWaveformWidget(const char* group, QWidget* parent, @@ -20,11 +19,12 @@ class GLSLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { void castToQWidget() override; void paintEvent(QPaintEvent* event) override; void mouseDoubleClickEvent(QMouseEvent *) override; + + protected slots: mixxx::Duration render() override; private: GLSLWaveformRendererSignal* signalRenderer_; - friend class WaveformWidgetFactory; }; diff --git a/src/waveform/widgets/glvsynctestwidget.cpp b/src/waveform/widgets/glvsynctestwidget.cpp index 34d2d6eddfe3..ca57c314f74f 100644 --- a/src/waveform/widgets/glvsynctestwidget.cpp +++ b/src/waveform/widgets/glvsynctestwidget.cpp @@ -16,9 +16,7 @@ #include "util/performancetimer.h" GLVSyncTestWidget::GLVSyncTestWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { - + : BaseQOpenGLWidget(group, parent) { // addRenderer(); // 172 µs // addRenderer(); // 677 µs 1145 µs (active) // addRenderer(); // 652 µs 2034 µs (active) diff --git a/src/waveform/widgets/glvsynctestwidget.h b/src/waveform/widgets/glvsynctestwidget.h index 4e49f8a0a0dc..a562786164fb 100644 --- a/src/waveform/widgets/glvsynctestwidget.h +++ b/src/waveform/widgets/glvsynctestwidget.h @@ -1,11 +1,9 @@ #ifndef GLVSYNCTESTWIDGET_H #define GLVSYNCTESTWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class GLVSyncTestWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class GLVSyncTestWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLVSyncTestWidget(const char* group, QWidget* parent); @@ -21,7 +19,9 @@ class GLVSyncTestWidget : public QOpenGLWidget, public WaveformWidgetAbstract { protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/glwaveformwidget.cpp b/src/waveform/widgets/glwaveformwidget.cpp index a01bc0296125..39ad12a2fe05 100644 --- a/src/waveform/widgets/glwaveformwidget.cpp +++ b/src/waveform/widgets/glwaveformwidget.cpp @@ -15,9 +15,7 @@ #include "util/performancetimer.h" GLWaveformWidget::GLWaveformWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/glwaveformwidget.h b/src/waveform/widgets/glwaveformwidget.h index 9d51560ab1b0..4411ec829d85 100644 --- a/src/waveform/widgets/glwaveformwidget.h +++ b/src/waveform/widgets/glwaveformwidget.h @@ -1,11 +1,9 @@ #ifndef GLWAVEFORMWIDGET_H #define GLWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class GLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class GLWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLWaveformWidget(const char* group, QWidget* parent); @@ -21,7 +19,9 @@ class GLWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/qtsimplewaveformwidget.cpp b/src/waveform/widgets/qtsimplewaveformwidget.cpp index 9e1397ac6dbf..c0560f937fc6 100644 --- a/src/waveform/widgets/qtsimplewaveformwidget.cpp +++ b/src/waveform/widgets/qtsimplewaveformwidget.cpp @@ -16,8 +16,7 @@ #include "util/performancetimer.h" QtSimpleWaveformWidget::QtSimpleWaveformWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/qtsimplewaveformwidget.h b/src/waveform/widgets/qtsimplewaveformwidget.h index fc5ca316b947..4f7a5a33f97b 100644 --- a/src/waveform/widgets/qtsimplewaveformwidget.h +++ b/src/waveform/widgets/qtsimplewaveformwidget.h @@ -1,17 +1,14 @@ #ifndef QTSIMPLEWAVEFORMWIDGET_H #define QTSIMPLEWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class QtSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class QtSimpleWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: QtSimpleWaveformWidget(const char* group, QWidget* parent); virtual ~QtSimpleWaveformWidget(); - virtual WaveformWidgetType::Type getType() const { return WaveformWidgetType::GLSimpleWaveform; } static inline QString getWaveformWidgetName() { return tr("Simple") + " - Qt"; } @@ -22,7 +19,9 @@ class QtSimpleWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstra protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/qtwaveformwidget.cpp b/src/waveform/widgets/qtwaveformwidget.cpp index ee6a8ca497e1..f57ce336965f 100644 --- a/src/waveform/widgets/qtwaveformwidget.cpp +++ b/src/waveform/widgets/qtwaveformwidget.cpp @@ -16,8 +16,7 @@ #include "util/performancetimer.h" QtWaveformWidget::QtWaveformWidget(const char* group, QWidget* parent) - : QOpenGLWidget(parent), - WaveformWidgetAbstract(group) { + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); diff --git a/src/waveform/widgets/qtwaveformwidget.h b/src/waveform/widgets/qtwaveformwidget.h index 5121357571ff..f8ffe514b785 100644 --- a/src/waveform/widgets/qtwaveformwidget.h +++ b/src/waveform/widgets/qtwaveformwidget.h @@ -1,11 +1,9 @@ #ifndef QTWAVEFORMWIDGET_H #define QTWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class QtWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { +class QtWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: QtWaveformWidget(const char* group, QWidget* parent); @@ -21,7 +19,9 @@ class QtWaveformWidget : public QOpenGLWidget, public WaveformWidgetAbstract { protected: virtual void castToQWidget(); virtual void paintEvent(QPaintEvent* event); - virtual mixxx::Duration render(); + + protected slots: + mixxx::Duration render() override; private: friend class WaveformWidgetFactory; diff --git a/src/waveform/widgets/waveformwidgetabstract.cpp b/src/waveform/widgets/waveformwidgetabstract.cpp index 329b4fe77e11..959af950ec33 100644 --- a/src/waveform/widgets/waveformwidgetabstract.cpp +++ b/src/waveform/widgets/waveformwidgetabstract.cpp @@ -8,7 +8,8 @@ WaveformWidgetAbstract::WaveformWidgetAbstract(const char* group) : WaveformWidgetRenderer(group), m_widget(nullptr), - m_initSuccess(false) { + m_initSuccess(false), + m_shouldRenderOnNextTick(false) { } WaveformWidgetAbstract::~WaveformWidgetAbstract() { @@ -26,8 +27,8 @@ void WaveformWidgetAbstract::release() { } } -void WaveformWidgetAbstract::preRender(VSyncThread* vsyncThread) { - WaveformWidgetRenderer::onPreRender(vsyncThread); +void WaveformWidgetAbstract::preRender(mixxx::Duration estimatedTimeUntilSwap) { + WaveformWidgetRenderer::onPreRender(estimatedTimeUntilSwap); } mixxx::Duration WaveformWidgetAbstract::render() { diff --git a/src/waveform/widgets/waveformwidgetabstract.h b/src/waveform/widgets/waveformwidgetabstract.h index 2582dfce07b8..506c123814fa 100644 --- a/src/waveform/widgets/waveformwidgetabstract.h +++ b/src/waveform/widgets/waveformwidgetabstract.h @@ -9,8 +9,6 @@ #include "track/track.h" #include "util/duration.h" -class VSyncThread; - // NOTE(vRince) This class represent objects the waveformwidgetfactory can // holds, IMPORTANT all WaveformWidgetAbstract MUST inherist QWidget too !! we // can't do it here because QWidget and QOpenGLWidget are both QWidgets so they @@ -30,13 +28,18 @@ class WaveformWidgetAbstract : public WaveformWidgetRenderer { void hold(); void release(); - virtual void preRender(VSyncThread* vsyncThread); + virtual void preRender(mixxx::Duration estimatedTimeUntilSwap); virtual mixxx::Duration render(); + void renderOnNextTick() { + m_shouldRenderOnNextTick = true; + getWidget()->update(); + } virtual void resize(int width, int height, float devicePixelRatio) override; protected: QWidget* m_widget; bool m_initSuccess; + bool m_shouldRenderOnNextTick; //this is the factory resposability to trigger QWidget casting after constructor virtual void castToQWidget() = 0; diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index bc4c7b3da235..dae5fd242abb 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -10,6 +10,7 @@ #include "library/coverartcache.h" #include "util/dnd.h" #include "util/math.h" +#include "util/time.h" #include "waveform/visualplayposition.h" #include "waveform/vsyncthread.h" #include "vinylcontrol/vinylcontrol.h" @@ -58,7 +59,8 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, m_bGhostPlayback(false), m_pPlayer(pPlayer), m_pDlgCoverArt(new DlgCoverArtFullSize(parent, pPlayer)), - m_pCoverMenu(new WCoverArtMenu(this)) { + m_pCoverMenu(new WCoverArtMenu(this)), + m_shouldRenderOnNextTick(false) { #ifdef __VINYLCONTROL__ m_pVCManager = pVCMan; #endif @@ -89,7 +91,9 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoFillBackground(false); + + connect(this, SIGNAL(aboutToCompose()), this, SLOT(slotAboutToCompose())); + connect(this, SIGNAL(frameSwapped()), this, SLOT(slotFrameSwapped())); } WSpinny::~WSpinny() { @@ -298,7 +302,7 @@ void WSpinny::render() { } if (!m_pVisualPlayPos.isNull()) { - m_pVisualPlayPos->getPlaySlipAt(0, + m_pVisualPlayPos->getPlaySlipAt(m_lastSwapDurationMovingAverage, &m_dAngleCurrentPlaypos, &m_dGhostAngleCurrentPlaypos); } @@ -372,14 +376,6 @@ void WSpinny::render() { } } -void WSpinny::swap() { - if (!isValid() || !isVisible()) { - return; - } - VSyncThread::swapGl(this, 0); -} - - QPixmap WSpinny::scaledCoverArt(const QPixmap& normal) { if (normal.isNull()) { return QPixmap(); @@ -664,3 +660,27 @@ void WSpinny::dragEnterEvent(QDragEnterEvent* event) { void WSpinny::dropEvent(QDropEvent * event) { DragAndDropHelper::handleTrackDropEvent(event, *this, m_group, m_pConfig); } + +void WSpinny::slotAboutToCompose() { + if (m_shouldRenderOnNextTick) { + m_lastRender = mixxx::Time::elapsed(); + render(); + m_shouldRenderOnNextTick = false; + } +} + +void WSpinny::slotFrameSwapped() { + if (m_lastRender != m_lastSwapRender) { + m_lastSwapRender = m_lastRender; + m_lastSwapDuration = mixxx::Time::elapsed() - m_lastRender; + const double decay = 0.5; + m_lastSwapDurationMovingAverage = mixxx::Duration::fromNanos( + decay * m_lastSwapDurationMovingAverage.toDoubleNanos() + + (1.0 - decay) * m_lastSwapDuration.toDoubleNanos()); + } +} + +void WSpinny::slotShouldRenderOnNextTick() { + m_shouldRenderOnNextTick = true; + update(); +} diff --git a/src/widget/wspinny.h b/src/widget/wspinny.h index 50492ac7228c..cd03161b1524 100644 --- a/src/widget/wspinny.h +++ b/src/widget/wspinny.h @@ -17,6 +17,7 @@ #include "widget/wbasewidget.h" #include "widget/wcoverartmenu.h" #include "widget/wwidget.h" +#include "util/duration.h" class ControlProxy; class VisualPlayPosition; @@ -46,7 +47,6 @@ class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQual void updateVinylControlSignalEnabled(double enabled); void updateSlipEnabled(double enabled); void render(); - void swap(); protected slots: void slotCoverFound(const QObject* pRequestor, @@ -55,7 +55,6 @@ class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQual void slotReloadCoverArt(); void slotTrackCoverArtUpdated(); - signals: void trackDropped(QString filename, QString group); void cloneDeck(QString source_group, QString target_group); @@ -76,6 +75,11 @@ class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQual double calculatePositionFromAngle(double angle); QPixmap scaledCoverArt(const QPixmap& normal); + private slots: + void slotAboutToCompose(); + void slotFrameSwapped(); + void slotShouldRenderOnNextTick(); + private: QString m_group; UserSettingsPointer m_pConfig; @@ -131,6 +135,12 @@ class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQual BaseTrackPlayer* m_pPlayer; DlgCoverArtFullSize* m_pDlgCoverArt; WCoverArtMenu* m_pCoverMenu; + + bool m_shouldRenderOnNextTick; + mixxx::Duration m_lastRender; + mixxx::Duration m_lastSwapRender; + mixxx::Duration m_lastSwapDuration; + mixxx::Duration m_lastSwapDurationMovingAverage; }; #endif //_WSPINNY_H From a1a885749416cce35e31cb3832199fb5cd4d50f0 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sat, 9 Feb 2019 09:30:41 -0800 Subject: [PATCH 12/30] Render widgets immediately via WaveformWidgetAbstract::renderOnNextTick. BaseQOpenGLWidget overrides this method to call QWidget::update, setting the "render on next tick" flag. This fixes rendering for non-OpenGL waveforms, preserving the existing behavior of calling QWidget::repaint when the VSyncThread sent a render signal. --- src/waveform/widgets/baseqopenglwidget.cpp | 10 +++++++--- src/waveform/widgets/baseqopenglwidget.h | 13 ++++++++++--- src/waveform/widgets/waveformwidgetabstract.cpp | 3 +-- src/waveform/widgets/waveformwidgetabstract.h | 8 ++++---- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/waveform/widgets/baseqopenglwidget.cpp b/src/waveform/widgets/baseqopenglwidget.cpp index 34a55b94a748..4acf1af0f84e 100644 --- a/src/waveform/widgets/baseqopenglwidget.cpp +++ b/src/waveform/widgets/baseqopenglwidget.cpp @@ -3,9 +3,13 @@ #include "util/time.h" BaseQOpenGLWidget::BaseQOpenGLWidget(const char* group, QWidget* pParent) - : QOpenGLWidget(pParent), WaveformWidgetAbstract(group) { - connect(this, SIGNAL(aboutToCompose()), this, SLOT(slotAboutToCompose())); - connect(this, SIGNAL(frameSwapped()), this, SLOT(slotFrameSwapped())); + : QOpenGLWidget(pParent), + WaveformWidgetAbstract(group), + m_shouldRenderOnNextTick(false) { + connect(this, &QOpenGLWidget::aboutToCompose, + this, &BaseQOpenGLWidget::slotAboutToCompose); + connect(this, &QOpenGLWidget::frameSwapped, + this, &BaseQOpenGLWidget::slotFrameSwapped); } void BaseQOpenGLWidget::slotAboutToCompose() { diff --git a/src/waveform/widgets/baseqopenglwidget.h b/src/waveform/widgets/baseqopenglwidget.h index d5b468fb4a30..44ee47d7dc44 100644 --- a/src/waveform/widgets/baseqopenglwidget.h +++ b/src/waveform/widgets/baseqopenglwidget.h @@ -12,9 +12,15 @@ class BaseQOpenGLWidget : public QOpenGLWidget, public WaveformWidgetAbstract { BaseQOpenGLWidget(const char* group, QWidget* pParent); virtual ~BaseQOpenGLWidget() = default; - virtual mixxx::Duration render() override { - WaveformWidgetAbstract::render(); - return mixxx::Duration(); + // Each QOpenGLWidget must define its own render + // method. WaveformWidgetAbstract::render must not be called even though it + // is defined. + virtual mixxx::Duration render() = 0; + + void renderOnNextTick() override { + m_shouldRenderOnNextTick = true; + // Request a paint event from Qt. + update(); } private slots: @@ -22,6 +28,7 @@ class BaseQOpenGLWidget : public QOpenGLWidget, public WaveformWidgetAbstract { void slotFrameSwapped(); private: + bool m_shouldRenderOnNextTick; mixxx::Duration m_lastRender; mixxx::Duration m_lastSwapRender; mixxx::Duration m_lastSwapDuration; diff --git a/src/waveform/widgets/waveformwidgetabstract.cpp b/src/waveform/widgets/waveformwidgetabstract.cpp index 959af950ec33..614a298a4048 100644 --- a/src/waveform/widgets/waveformwidgetabstract.cpp +++ b/src/waveform/widgets/waveformwidgetabstract.cpp @@ -8,8 +8,7 @@ WaveformWidgetAbstract::WaveformWidgetAbstract(const char* group) : WaveformWidgetRenderer(group), m_widget(nullptr), - m_initSuccess(false), - m_shouldRenderOnNextTick(false) { + m_initSuccess(false) { } WaveformWidgetAbstract::~WaveformWidgetAbstract() { diff --git a/src/waveform/widgets/waveformwidgetabstract.h b/src/waveform/widgets/waveformwidgetabstract.h index 506c123814fa..30262c9ef238 100644 --- a/src/waveform/widgets/waveformwidgetabstract.h +++ b/src/waveform/widgets/waveformwidgetabstract.h @@ -30,16 +30,16 @@ class WaveformWidgetAbstract : public WaveformWidgetRenderer { virtual void preRender(mixxx::Duration estimatedTimeUntilSwap); virtual mixxx::Duration render(); - void renderOnNextTick() { - m_shouldRenderOnNextTick = true; - getWidget()->update(); + virtual void renderOnNextTick() { + // By default, render immediately. Non-QOpenGLWidgets take this path. + preRender(mixxx::Duration::fromSeconds(0)); + render(); } virtual void resize(int width, int height, float devicePixelRatio) override; protected: QWidget* m_widget; bool m_initSuccess; - bool m_shouldRenderOnNextTick; //this is the factory resposability to trigger QWidget casting after constructor virtual void castToQWidget() = 0; From 98bd81eb7f4432583224d4368ad2b1523c0fef70 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sat, 9 Feb 2019 21:49:05 -0800 Subject: [PATCH 13/30] Rename VSyncThread to RenderThread and delete some unused code. --- build/depends.py | 2 +- src/mixxx.cpp | 2 +- src/waveform/guitick.h | 2 +- src/waveform/renderthread.cpp | 92 ++++++++++++++ src/waveform/renderthread.h | 44 +++++++ src/waveform/visualplayposition.cpp | 1 - src/waveform/vsyncthread.cpp | 164 ------------------------- src/waveform/vsyncthread.h | 110 ----------------- src/waveform/waveformwidgetfactory.cpp | 56 ++++----- src/waveform/waveformwidgetfactory.h | 14 +-- src/widget/wspinny.cpp | 1 - 11 files changed, 169 insertions(+), 319 deletions(-) create mode 100644 src/waveform/renderthread.cpp create mode 100644 src/waveform/renderthread.h delete mode 100644 src/waveform/vsyncthread.cpp delete mode 100644 src/waveform/vsyncthread.h diff --git a/build/depends.py b/build/depends.py index 1c98ad2a53ba..628839ec5f52 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1065,7 +1065,7 @@ def sources(self, build): "src/waveform/waveform.cpp", "src/waveform/waveformfactory.cpp", "src/waveform/waveformwidgetfactory.cpp", - "src/waveform/vsyncthread.cpp", + "src/waveform/renderthread.cpp", "src/waveform/guitick.cpp", "src/waveform/visualsmanager.cpp", "src/waveform/visualplayposition.cpp", diff --git a/src/mixxx.cpp b/src/mixxx.cpp index f7ef4fede6a0..142dda835880 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -391,7 +391,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { launchProgress(47); WaveformWidgetFactory::createInstance(); // takes a long time - WaveformWidgetFactory::instance()->startVSync(m_pGuiTick, m_pVisualsManager); + WaveformWidgetFactory::instance()->startRenderThread(m_pGuiTick, m_pVisualsManager); WaveformWidgetFactory::instance()->setConfig(pConfig); launchProgress(52); diff --git a/src/waveform/guitick.h b/src/waveform/guitick.h index fc788e4aa121..01bae716c1ad 100644 --- a/src/waveform/guitick.h +++ b/src/waveform/guitick.h @@ -9,7 +9,7 @@ #include "util/performancetimer.h" // A helper class that manages the "guiTickTime" COs, that drive updates of the -// GUI from the VsyncThread at the user's configured FPS (possibly downsampled). +// GUI from the RenderThread at the user's configured FPS (possibly downsampled). class GuiTick { public: GuiTick(); diff --git a/src/waveform/renderthread.cpp b/src/waveform/renderthread.cpp new file mode 100644 index 000000000000..cb52fede45e3 --- /dev/null +++ b/src/waveform/renderthread.cpp @@ -0,0 +1,92 @@ +#include + +#include "renderthread.h" +#include "util/performancetimer.h" +#include "util/event.h" +#include "util/counter.h" +#include "util/math.h" +#include "util/time.h" + +RenderThread::RenderThread(QObject* pParent) + : QThread(pParent), + m_bDoRendering(true), + m_syncIntervalTimeMicros(33333), // 30 FPS + m_renderMode(ST_TIMER), + m_droppedFrames(0) { +} + +RenderThread::~RenderThread() { + m_bDoRendering = false; + m_semaRenderSlot.release(2); // Two slots + wait(); +} + +void RenderThread::stop() { + m_bDoRendering = false; +} + + +void RenderThread::run() { + Counter droppedFrames("RenderThread real time error"); + QThread::currentThread()->setObjectName("RenderThread"); + + m_timer.start(); + + while (m_bDoRendering) { + if (m_renderMode == ST_FREE) { + // for benchmark only! + + Event::start("RenderThread render"); + // renders the waveform, Possible delayed due to anti tearing + emit(render()); + m_semaRenderSlot.acquire(); + Event::end("RenderThread render"); + + m_timer.restart(); + usleep(1000); + } else { // if (m_renderMode == ST_TIMER) { + m_timer.restart(); + + Event::start("RenderThread render"); + emit(render()); // renders the new waveform. + + // wait until rendering was scheduled. It might be delayed due a + // pending swap (depends one driver render settings) + m_semaRenderSlot.acquire(); + Event::end("RenderThread render"); + + int elapsed = m_timer.restart().toIntegerMicros(); + int sleepTimeMicros = m_syncIntervalTimeMicros - elapsed; + //qDebug() << "RenderThread sleepTimeMicros" << sleepTimeMicros; + if (sleepTimeMicros > 100) { + usleep(sleepTimeMicros); + } else if (sleepTimeMicros < 0) { + m_droppedFrames++; + } + } + } +} + +int RenderThread::elapsed() { + return static_cast(m_timer.elapsed().toIntegerMicros()); +} + +void RenderThread::setSyncIntervalTimeMicros(int syncTime) { + m_syncIntervalTimeMicros = syncTime; +} + +void RenderThread::setRenderType(int type) { + if (type >= (int)RenderThread::ST_COUNT) { + type = RenderThread::ST_TIMER; + } + m_renderMode = (enum RenderMode)type; + m_droppedFrames = 0; +} + +int RenderThread::droppedFrames() { + return m_droppedFrames; +} + +void RenderThread::renderSlotFinished() { + m_semaRenderSlot.release(); +} diff --git a/src/waveform/renderthread.h b/src/waveform/renderthread.h new file mode 100644 index 000000000000..c143638a9d75 --- /dev/null +++ b/src/waveform/renderthread.h @@ -0,0 +1,44 @@ +#ifndef RENDERTHREAD_H +#define RENDERTHREAD_H + +#include +#include +#include + +#include "util/performancetimer.h" + +class RenderThread : public QThread { + Q_OBJECT + public: + enum RenderMode { + ST_TIMER = 0, + ST_FREE, + ST_COUNT // Dummy Type at last, counting possible types + }; + + RenderThread(QObject* pParent); + ~RenderThread(); + + void run(); + void stop(); + + int elapsed(); + void setSyncIntervalTimeMicros(int usSyncTimer); + void setRenderType(int mode); + int droppedFrames(); + void renderSlotFinished(); + + signals: + void render(); + + private: + bool m_bDoRendering; + int m_syncIntervalTimeMicros; + enum RenderMode m_renderMode; + int m_droppedFrames; + PerformanceTimer m_timer; + QSemaphore m_semaRenderSlot; +}; + + +#endif // RENDERTHREAD_H diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index 26334ceb2da2..2e1b4c527545 100644 --- a/src/waveform/visualplayposition.cpp +++ b/src/waveform/visualplayposition.cpp @@ -5,7 +5,6 @@ #include "control/controlproxy.h" #include "control/controlobject.h" #include "util/math.h" -#include "waveform/vsyncthread.h" namespace { // The offset is limited to two callback intervals. diff --git a/src/waveform/vsyncthread.cpp b/src/waveform/vsyncthread.cpp deleted file mode 100644 index 12bc72f5813a..000000000000 --- a/src/waveform/vsyncthread.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include -#include -#include -#include - -#include "vsyncthread.h" -#include "util/performancetimer.h" -#include "util/event.h" -#include "util/counter.h" -#include "util/math.h" -#include "util/time.h" -#include "waveform/guitick.h" - -#if defined(__APPLE__) -#elif defined(__WINDOWS__) -#else -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - extern const QX11Info *qt_x11Info(const QPaintDevice *pd); -#endif -#endif - -VSyncThread::VSyncThread(QObject* pParent) - : QThread(pParent), - m_bDoRendering(true), - m_vSyncTypeChanged(false), - m_syncIntervalTimeMicros(33333), // 30 FPS - m_waitToSwapMicros(0), - m_vSyncMode(ST_TIMER), - m_syncOk(false), - m_droppedFrames(0), - m_swapWait(0), - m_displayFrameRate(60.0), - m_vSyncPerRendering(1) { -} - -VSyncThread::~VSyncThread() { - m_bDoRendering = false; - m_semaVsyncSlot.release(2); // Two slots - wait(); - //delete m_glw; -} - -void VSyncThread::stop() { - m_bDoRendering = false; -} - - -void VSyncThread::run() { - Counter droppedFrames("VsyncThread real time error"); - QThread::currentThread()->setObjectName("VSyncThread"); - - m_waitToSwapMicros = m_syncIntervalTimeMicros; - m_timer.start(); - - while (m_bDoRendering) { - if (m_vSyncMode == ST_FREE) { - // for benchmark only! - - Event::start("VsyncThread vsync render"); - // renders the waveform, Possible delayed due to anti tearing - emit(vsyncRender()); - m_semaVsyncSlot.acquire(); - Event::end("VsyncThread vsync render"); - - m_timer.restart(); - m_waitToSwapMicros = 1000; - usleep(1000); - } else { // if (m_vSyncMode == ST_TIMER) { - m_timer.restart(); - - Event::start("VsyncThread vsync render"); - emit(vsyncRender()); // renders the new waveform. - - // wait until rendering was scheduled. It might be delayed due a - // pending swap (depends one driver vSync settings) - m_semaVsyncSlot.acquire(); - Event::end("VsyncThread vsync render"); - - int elapsed = m_timer.restart().toIntegerMicros(); - int sleepTimeMicros = m_syncIntervalTimeMicros - elapsed; - //qDebug() << "VsyncThread sleepTimeMicros" << sleepTimeMicros; - if (sleepTimeMicros > 100) { - usleep(sleepTimeMicros); - } else if (sleepTimeMicros < 0) { - m_droppedFrames++; - } - } - } -} - -int VSyncThread::elapsed() { - return static_cast(m_timer.elapsed().toIntegerMicros()); -} - -void VSyncThread::setSyncIntervalTimeMicros(int syncTime) { - m_syncIntervalTimeMicros = syncTime; - m_vSyncPerRendering = round(m_displayFrameRate * m_syncIntervalTimeMicros / 1000); -} - -void VSyncThread::setVSyncType(int type) { - if (type >= (int)VSyncThread::ST_COUNT) { - type = VSyncThread::ST_TIMER; - } - m_vSyncMode = (enum VSyncMode)type; - m_droppedFrames = 0; - m_vSyncTypeChanged = true; -} - -int VSyncThread::toNextSyncMicros() { - int rest = m_waitToSwapMicros - static_cast(m_timer.elapsed().toIntegerMicros()); - // int math is fine here, because we do not expect times > 4.2 s - if (rest < 0) { - rest %= m_syncIntervalTimeMicros; - rest += m_syncIntervalTimeMicros; - } - return rest; -} - -int VSyncThread::fromTimerToNextSyncMicros(const PerformanceTimer& timer) { - int difference = static_cast(m_timer.difference(timer).toIntegerMicros()); - // int math is fine here, because we do not expect times > 4.2 s - return difference + m_waitToSwapMicros; -} - -int VSyncThread::droppedFrames() { - return m_droppedFrames; -} - -void VSyncThread::vsyncSlotFinished() { - m_semaVsyncSlot.release(); -} - -void VSyncThread::getAvailableVSyncTypes(QList >* pList) { - for (int i = (int)VSyncThread::ST_TIMER; i < (int)VSyncThread::ST_COUNT; i++) { - //if (isAvailable(type)) // TODO - { - enum VSyncMode mode = (enum VSyncMode)i; - - QString name; - switch (mode) { - case VSyncThread::ST_TIMER: - name = tr("Timer (Fallback)"); - break; - case VSyncThread::ST_MESA_VBLANK_MODE_1: - name = tr("MESA vblank_mode = 1"); - break; - case VSyncThread::ST_SGI_VIDEO_SYNC: - name = tr("Wait for Video sync"); - break; - case VSyncThread::ST_OML_SYNC_CONTROL: - name = tr("Sync Control"); - break; - case VSyncThread::ST_FREE: - name = tr("Free + 1 ms (for benchmark only)"); - break; - default: - break; - } - QPair pair = QPair(i, name); - pList->append(pair); - } - } -} diff --git a/src/waveform/vsyncthread.h b/src/waveform/vsyncthread.h deleted file mode 100644 index 8bc86137504e..000000000000 --- a/src/waveform/vsyncthread.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef VSYNCTHREAD_H -#define VSYNCTHREAD_H - -#include -#include -#include -#include -#include - -#if defined(__APPLE__) - -#elif defined(__WINDOWS__) - -#else -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#ifndef QT_OPENGL_ES_2 - #include - #include - //#include "GL/glxext.h" - // clean up after Xlib.h, which #defines values that conflict with QT. - #undef Bool - #undef Unsorted - #undef None - #undef Status -#endif // QT_OPENGL_ES_2 -#endif // QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -#endif - -#include "util/performancetimer.h" - -// TODO(rryan): Rename to RenderThread or something, or possibly replace with a -// generic BlockingThreadTimer class. -class VSyncThread : public QThread { - Q_OBJECT - public: - enum VSyncMode { - ST_TIMER = 0, - ST_MESA_VBLANK_MODE_1, - ST_SGI_VIDEO_SYNC, - ST_OML_SYNC_CONTROL, - ST_FREE, - ST_COUNT // Dummy Type at last, counting possible types - }; - - VSyncThread(QObject* pParent); - ~VSyncThread(); - - void run(); - void stop(); - - int elapsed(); - int toNextSyncMicros(); - void setSyncIntervalTimeMicros(int usSyncTimer); - void setVSyncType(int mode); - int droppedFrames(); - int fromTimerToNextSyncMicros(const PerformanceTimer& timer); - void vsyncSlotFinished(); - void getAvailableVSyncTypes(QList >* list); - - signals: - void vsyncRender(); - - private: - bool m_bDoRendering; - -#if defined(__APPLE__) - -#elif defined(__WINDOWS__) - -#else - //bool glXExtensionSupported(Display *dpy, int screen, const char *extension); - - /* Currently unused, but probably part of later a hardware sync solution - PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI; - PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI; - - PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI; - - PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT; - - PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML; - PFNGLXGETMSCRATEOMLPROC glXGetMscRateOML; - PFNGLXSWAPBUFFERSMSCOMLPROC glXSwapBuffersMscOML; - PFNGLXWAITFORMSCOMLPROC glXWaitForMscOML; - PFNGLXWAITFORSBCOMLPROC glXWaitForSbcOML; - - PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA; - */ - - //int64_t m_target_msc; - //Display* m_dpy; - //GLXDrawable m_drawable; - -#endif - - bool m_vSyncTypeChanged; - int m_syncIntervalTimeMicros; - int m_waitToSwapMicros; - enum VSyncMode m_vSyncMode; - bool m_syncOk; - int m_droppedFrames; - int m_swapWait; - PerformanceTimer m_timer; - QSemaphore m_semaVsyncSlot; - double m_displayFrameRate; - int m_vSyncPerRendering; -}; - - -#endif // VSYNCTHREAD_H diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index d9c0b160aa03..1721af7d4a2d 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -27,7 +27,7 @@ #include "widget/wwaveformviewer.h" #include "waveform/guitick.h" #include "waveform/visualsmanager.h" -#include "waveform/vsyncthread.h" +#include "waveform/renderthread.h" #include "util/cmdlineargs.h" #include "util/performancetimer.h" #include "util/time.h" @@ -97,12 +97,12 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_openGLAvailable(false), m_openGLShaderAvailable(false), m_beatGridAlpha(90), - m_vsyncThread(NULL), + m_renderThread(NULL), m_pGuiTick(nullptr), m_pVisualsManager(nullptr), m_frameCnt(0), m_actualFrameRate(0), - m_vSyncType(0), + m_renderType(0), m_playMarkerPosition(WaveformWidgetRenderer::s_defaultPlayMarkerPosition) { m_visualGain[All] = 1.0; @@ -134,8 +134,8 @@ WaveformWidgetFactory::WaveformWidgetFactory() : } WaveformWidgetFactory::~WaveformWidgetFactory() { - if (m_vsyncThread) { - delete m_vsyncThread; + if (m_renderThread) { + delete m_renderThread; } } @@ -162,8 +162,8 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { ConfigValue(m_endOfTrackWarningTime)); } - int vsync = m_config->getValue(ConfigKey("[Waveform]","VSync"), 0); - setVSyncType(vsync); + int render = m_config->getValue(ConfigKey("[Waveform]","Render"), 0); + setRenderType(render); double defaultZoom = m_config->getValueString(ConfigKey("[Waveform]","DefaultZoom")).toDouble(&ok); if (ok) { @@ -273,7 +273,7 @@ void WaveformWidgetFactory::setFrameRate(int frameRate) { if (m_config) { m_config->set(ConfigKey("[Waveform]","FrameRate"), ConfigValue(m_frameRate)); } - m_vsyncThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); + m_renderThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); } void WaveformWidgetFactory::setEndOfTrackWarningTime(int endTime) { @@ -283,17 +283,13 @@ void WaveformWidgetFactory::setEndOfTrackWarningTime(int endTime) { } } -void WaveformWidgetFactory::setVSyncType(int type) { +void WaveformWidgetFactory::setRenderType(int type) { if (m_config) { - m_config->set(ConfigKey("[Waveform]","VSync"), ConfigValue((int)type)); + m_config->set(ConfigKey("[Waveform]","Render"), ConfigValue((int)type)); } - m_vSyncType = type; - m_vsyncThread->setVSyncType(type); -} - -int WaveformWidgetFactory::getVSyncType() { - return m_vSyncType; + m_renderType = type; + m_renderThread->setRenderType(type); } bool WaveformWidgetFactory::setWidgetType(WaveformWidgetType::Type type) { @@ -465,8 +461,8 @@ void WaveformWidgetFactory::render() { if (!m_skipRender) { if (m_type) { // no regular updates for an empty waveform - // next rendered frame is displayed after next buffer swap and than after VSync - //qDebug() << "prerender" << m_vsyncThread->elapsed(); + // next rendered frame is displayed after next buffer swap and than after Render + //qDebug() << "prerender" << m_renderThread->elapsed(); // It may happen that there is an artificially delayed due to // anti tearing driver settings @@ -477,7 +473,7 @@ void WaveformWidgetFactory::render() { continue; } pWaveformWidget->renderOnNextTick(); - //qDebug() << "render" << i << m_vsyncThread->elapsed(); + //qDebug() << "render" << i << m_renderThread->elapsed(); } } @@ -487,16 +483,16 @@ void WaveformWidgetFactory::render() { // Notify all other waveform-like widgets (e.g. WSpinny's) that they should // update. - //int t1 = m_vsyncThread->elapsed(); + //int t1 = m_renderThread->elapsed(); emit(waveformUpdateTick()); - //qDebug() << "emit" << m_vsyncThread->elapsed() - t1; + //qDebug() << "emit" << m_renderThread->elapsed() - t1; m_frameCnt += 1.0; mixxx::Duration timeCnt = m_time.elapsed(); if (timeCnt > mixxx::Duration::fromSeconds(1)) { m_time.start(); m_frameCnt = m_frameCnt * 1000 / timeCnt.toIntegerMillis(); // latency correction - emit(waveformMeasured(m_frameCnt, m_vsyncThread->droppedFrames())); + emit(waveformMeasured(m_frameCnt, m_renderThread->droppedFrames())); m_frameCnt = 0.0; } } @@ -504,8 +500,8 @@ void WaveformWidgetFactory::render() { m_pVisualsManager->process(m_endOfTrackWarningTime); m_pGuiTick->process(); - //qDebug() << "refresh end" << m_vsyncThread->elapsed(); - m_vsyncThread->vsyncSlotFinished(); + //qDebug() << "refresh end" << m_renderThread->elapsed(); + m_renderThread->renderSlotFinished(); } WaveformWidgetType::Type WaveformWidgetFactory::autoChooseWidgetType() const { @@ -708,20 +704,16 @@ int WaveformWidgetFactory::findIndexOf(WWaveformViewer* viewer) const { return -1; } -void WaveformWidgetFactory::startVSync(GuiTick* pGuiTick, VisualsManager* pVisualsManager) { +void WaveformWidgetFactory::startRenderThread(GuiTick* pGuiTick, VisualsManager* pVisualsManager) { m_pGuiTick = pGuiTick; m_pVisualsManager = pVisualsManager; - m_vsyncThread = new VSyncThread(this); - m_vsyncThread->start(QThread::NormalPriority); + m_renderThread = new RenderThread(this); + m_renderThread->start(QThread::NormalPriority); - connect(m_vsyncThread, SIGNAL(vsyncRender()), + connect(m_renderThread, SIGNAL(render()), this, SLOT(render())); } -void WaveformWidgetFactory::getAvailableVSyncTypes(QList >* pList) { - m_vsyncThread->getAvailableVSyncTypes(pList); -} - // static float WaveformWidgetFactory::getDevicePixelRatio() { float devicePixelRatio = 1.0; diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index 880a6233bd3b..fa0ae9ea5abe 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -7,6 +7,7 @@ #include "util/singleton.h" #include "preferences/usersettings.h" +#include "waveform/renderthread.h" #include "waveform/widgets/waveformwidgettype.h" #include "waveform/waveform.h" #include "skin/skincontext.h" @@ -15,7 +16,6 @@ class WWaveformViewer; class WaveformWidgetAbstract; class QTimer; -class VSyncThread; class GuiTick; class VisualsManager; @@ -71,7 +71,7 @@ class WaveformWidgetFactory : public QObject, public Singleton getAvailableTypes() const { return m_waveformWidgetHandles;} - void getAvailableVSyncTypes(QList >* list); void destroyWidgets(); void addTimerListener(QWidget* pWidget); - void startVSync(GuiTick* pGuiTick, VisualsManager* pVisualsManager); - void setVSyncType(int vsType); - int getVSyncType(); + void setRenderType(int vsType); + void startRenderThread(GuiTick* pGuiTick, VisualsManager* pVisualsManager); void setPlayMarkerPosition(double position); double getPlayMarkerPosition() const { return m_playMarkerPosition; } @@ -164,7 +162,7 @@ class WaveformWidgetFactory : public QObject, public Singleton Date: Sun, 10 Feb 2019 16:02:19 -0800 Subject: [PATCH 14/30] Use Qt 5-style connect function. --- src/widget/wspinny.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 4bb065c457eb..2a1cc1cd3da4 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -91,8 +91,10 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - connect(this, SIGNAL(aboutToCompose()), this, SLOT(slotAboutToCompose())); - connect(this, SIGNAL(frameSwapped()), this, SLOT(slotFrameSwapped())); + connect(this, &QOpenGLWidget::aboutToCompose, + this, &WSpinny::slotAboutToCompose); + connect(this, &QOpenGLWidget::frameSwapped, + this, &WSpinny::slotFrameSwapped); } WSpinny::~WSpinny() { From d4bdd92ffa215b21fce6f48225ca1ff6ce34e807 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sun, 10 Feb 2019 20:19:06 -0800 Subject: [PATCH 15/30] Disable the broken FormatKiloSeconds test. --- src/test/durationutiltest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/durationutiltest.cpp b/src/test/durationutiltest.cpp index 149b4b31ff54..69307bda1be6 100644 --- a/src/test/durationutiltest.cpp +++ b/src/test/durationutiltest.cpp @@ -132,7 +132,7 @@ TEST_F(DurationUtilTest, formatSecondsLong) { } -TEST_F(DurationUtilTest, FormatKiloSeconds) { +TEST_F(DurationUtilTest, DISABLED_FormatKiloSeconds) { formatKiloSeconds(QString::fromUtf8("0.000\u2009000"), 0); formatKiloSeconds(QString::fromUtf8("0.001\u2009000"), 1); formatKiloSeconds(QString::fromUtf8("0.001\u2009490"), 1.49); From 4de038f8ed308b84c4be066d967b9e3dbb332ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 24 Feb 2019 00:49:01 +0100 Subject: [PATCH 16/30] Fix and improve the OpenGL status info --- src/waveform/waveformwidgetfactory.cpp | 57 ++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 1721af7d4a2d..cb122ce2b919 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -6,8 +6,11 @@ #include #include #include +#include #include #include +#include +#include #include "waveform/waveformwidgetfactory.h" @@ -33,6 +36,7 @@ #include "util/time.h" #include "util/timer.h" #include "util/math.h" +#include "util/memory.h" namespace { // Returns true if the given waveform should be rendered. @@ -117,14 +121,51 @@ WaveformWidgetFactory::WaveformWidgetFactory() : m_openGLVersion = tr("Safe Mode"); } else if (pWindow && pWindow->supportsOpenGL()) { m_openGLAvailable = true; - const auto format = pWindow->format(); - const auto major_minor = format.version(); - m_openGLVersion = QString("%1 %2.%3").arg( - format.renderableType() == QSurfaceFormat::OpenGL ? "OpenGL" : "OpenGLES", - QString::number(major_minor.first), - QString::number(major_minor.second)); - // Mixxx requires GLSL 1.20, which corresponds to OpenGL version 2.1. - m_openGLShaderAvailable = major_minor.first > 2 || (major_minor.first == 2 && major_minor.second >= 1); + + QWidget* w = nullptr; + foreach(QWidget* widget, QApplication::topLevelWidgets()) + if (widget->inherits("QMainWindow")) { + w = widget; + break; + } + std::unique_ptr pGlW = std::make_unique(w); + //glw->makeCurrent(); // does not work here + pGlW->show(); // the context is only valid if the wiget is shown. + QOpenGLContext* pContext = pGlW->context(); + + QString version; + QString renderer; + if (pContext) { + version = QString::fromUtf8(reinterpret_cast( + pContext->functions()->glGetString(GL_VERSION))); + renderer = QString::fromUtf8(reinterpret_cast( + pContext->functions()->glGetString(GL_RENDERER))); + } + + m_openGLShaderAvailable = QOpenGLShaderProgram::hasOpenGLShaderPrograms(pContext); + + const QSurfaceFormat format = pWindow->format(); + + const QSurfaceFormat::RenderableType renderableType = format.renderableType(); + QString strRenderableType; + switch (renderableType) { + case QSurfaceFormat::DefaultRenderableType: + strRenderableType = "DefaultRenderableType"; + break; + case QSurfaceFormat::OpenGL: + strRenderableType = "OpenGL"; + break; + case QSurfaceFormat::OpenGLES: + strRenderableType = "OpenGLES"; + break; + case QSurfaceFormat::OpenVG: + strRenderableType = "OpenVG"; + break; + default: + strRenderableType = "Unknown Type"; + break; + } + m_openGLVersion = strRenderableType + ": " + version + " (" + renderer + ")"; } else { m_openGLVersion = tr("None"); } From d9e434cd8fe338b700ad06b40ce974b764d955f0 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sun, 12 Apr 2020 23:27:07 -0700 Subject: [PATCH 17/30] Update CMakeLists.txt to include added/removed files. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e26d77ce9f1b..b40a5c983b4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -643,14 +643,14 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/waveform/renderers/waveformrendermarkrange.cpp src/waveform/renderers/waveformsignalcolors.cpp src/waveform/renderers/waveformwidgetrenderer.cpp - src/waveform/sharedglcontext.cpp + src/waveform/renderthread.cpp src/waveform/visualplayposition.cpp src/waveform/visualsmanager.cpp - src/waveform/vsyncthread.cpp src/waveform/waveform.cpp src/waveform/waveformfactory.cpp src/waveform/waveformmarklabel.cpp src/waveform/waveformwidgetfactory.cpp + src/waveform/widgets/baseqopenglwidget.cpp src/waveform/widgets/emptywaveformwidget.cpp src/waveform/widgets/glrgbwaveformwidget.cpp src/waveform/widgets/glsimplewaveformwidget.cpp From c6ad608d95264ff5df5b933348fc19a6f22c84bf Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sun, 12 Apr 2020 23:27:28 -0700 Subject: [PATCH 18/30] Remove unused header inclusion. --- src/mixxx.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 2625b48c981f..4de74d92f260 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include From 28764112ad8603f207f7a438d7d433cb1ba53f68 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sun, 12 Apr 2020 23:27:45 -0700 Subject: [PATCH 19/30] Use a range-based for loop. --- src/waveform/waveformwidgetfactory.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 8fa5a2dfb218..9612c11938fc 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -125,10 +125,11 @@ WaveformWidgetFactory::WaveformWidgetFactory() m_openGlAvailable = true; QWidget* w = nullptr; - foreach(QWidget* widget, QApplication::topLevelWidgets()) - if (widget->inherits("QMainWindow")) { - w = widget; - break; + for (QWidget* widget : QApplication::topLevelWidgets()) { + if (widget->inherits("QMainWindow")) { + w = widget; + break; + } } std::unique_ptr pGlW = std::make_unique(w); //glw->makeCurrent(); // does not work here From f4500ac677b229046ec3166e4e865b7427e41272 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Sun, 12 Apr 2020 23:28:14 -0700 Subject: [PATCH 20/30] Rename getAtNextSwap to getPlayPositionAtNextSwap to be more explicit. --- src/waveform/renderers/waveformwidgetrenderer.cpp | 2 +- src/waveform/visualplayposition.cpp | 6 +++--- src/waveform/visualplayposition.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/waveform/renderers/waveformwidgetrenderer.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index c3804f1afc4d..d1c9ee43c1c9 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -124,7 +124,7 @@ void WaveformWidgetRenderer::onPreRender(mixxx::Duration estimatedTimeUntilSwap) } - double truePlayPos = m_visualPlayPosition->getAtNextSwap(estimatedTimeUntilSwap); + double truePlayPos = m_visualPlayPosition->getPlayPositionAtNextSwap(estimatedTimeUntilSwap); // m_playPos = -1 happens, when a new track is in buffer but m_visualPlayPosition was not updated if (m_audioSamplePerPixel && truePlayPos != -1) { diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index b2491443edcb..683c1c2d5bcf 100644 --- a/src/waveform/visualplayposition.cpp +++ b/src/waveform/visualplayposition.cpp @@ -49,7 +49,7 @@ void VisualPlayPosition::set(double playPos, double rate, double positionStep, m_valid = true; } -double VisualPlayPosition::getAtNextSwap(mixxx::Duration estimatedTimeUntilSwap) { +double VisualPlayPosition::getPlayPositionAtNextSwap(mixxx::Duration estimatedTimeUntilSwap) { //static double testPos = 0; //testPos += 0.000017759; //0.000016608; // 1.46257e-05; //return testPos; @@ -63,8 +63,8 @@ double VisualPlayPosition::getAtNextSwap(mixxx::Duration estimatedTimeUntilSwap) // first, offset will be negative so that playpos goes backward. int offsetMicros = microsUntilSwap - microsUntilDac; offsetMicros = math_clamp(offsetMicros, - -m_audioBufferMicros * kMaxOffsetBufferCnt, - m_audioBufferMicros * kMaxOffsetBufferCnt); + -m_audioBufferMicros * kMaxOffsetBufferCnt, + m_audioBufferMicros * kMaxOffsetBufferCnt); double playPos = data.m_enginePlayPos; // load playPos for the first sample in Buffer // add the offset for the position of the sample that will be transferred to the DAC // When the next display frame is displayed diff --git a/src/waveform/visualplayposition.h b/src/waveform/visualplayposition.h index ae610f465927..7d97bac00cc7 100644 --- a/src/waveform/visualplayposition.h +++ b/src/waveform/visualplayposition.h @@ -48,7 +48,7 @@ class VisualPlayPosition : public QObject { // engine thread. void set(double playPos, double rate, double positionStep, double pSlipPosition, double tempoTrackSeconds); - double getAtNextSwap(mixxx::Duration estimatedTimeUntilSwap); + double getPlayPositionAtNextSwap(mixxx::Duration estimatedTimeUntilSwap); void getPlaySlipAtNextSwap(mixxx::Duration estimatedTimeUntilSwap, double* playPosition, double* slipPosition); double getEnginePlayPos(); From 99f6e5bd5363b03e4647ab226b0ae4af148bef45 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 00:20:11 -0700 Subject: [PATCH 21/30] Fix mistakes made when merging. --- src/waveform/waveformwidgetfactory.cpp | 1 + src/widget/wspinny.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 9612c11938fc..3eaaf1a0384b 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -821,6 +821,7 @@ void WaveformWidgetFactory::startRenderThread(GuiTick* pGuiTick, VisualsManager* m_renderThread = new RenderThread(this); m_renderThread->start(QThread::NormalPriority); m_renderThread->setRenderType(m_renderType); + m_renderThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); connect(m_renderThread, SIGNAL(render()), this, SLOT(render())); diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 1778d31d76f2..50971d8048e2 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -93,6 +93,7 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); + setAutoFillBackground(false); connect(this, &QOpenGLWidget::aboutToCompose, this, &WSpinny::slotAboutToCompose); connect(this, &QOpenGLWidget::frameSwapped, From a1cc05dd4251617e705e73dce90986d04548cb56 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 00:20:31 -0700 Subject: [PATCH 22/30] No need to guard QWidget::update() with isVisible(), since update does this itself. --- src/widget/wspinny.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 50971d8048e2..c52cb59c7212 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -689,7 +689,5 @@ void WSpinny::slotFrameSwapped() { void WSpinny::slotShouldRenderOnNextTick() { m_shouldRenderOnNextTick = true; - if (isVisible()) { - update(); - } + update(); } From 1e5cafba05b263b563d5657d9b346ba368d9e34e Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 00:21:15 -0700 Subject: [PATCH 23/30] Clarify and update some comments. Remove commented debugging printlines. --- src/waveform/renderthread.cpp | 13 ++++++++----- src/waveform/waveformwidgetfactory.cpp | 23 +++++------------------ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/waveform/renderthread.cpp b/src/waveform/renderthread.cpp index 4087eefe0981..ac53c38323d2 100644 --- a/src/waveform/renderthread.cpp +++ b/src/waveform/renderthread.cpp @@ -39,7 +39,7 @@ void RenderThread::run() { // for benchmark only! Event::start(renderTag); - // renders the waveform, Possible delayed due to anti tearing + // Request for the main thread to schedule a render. emit(render()); m_semaRenderSlot.acquire(); Event::end(renderTag); @@ -50,16 +50,19 @@ void RenderThread::run() { m_timer.restart(); Event::start(renderTag); - emit(render()); // renders the new waveform. - // wait until rendering was scheduled. It might be delayed due a - // pending swap (depends one driver render settings) + // Request for the main thread to schedule a render. + emit(render()); + + // Wait until the main thread processed our rendering request. This + // means the main thread scheduled a render, not that it has already + // happened. Ultimately, Qt's compositor is in charge of when our + // QOpenGLWidgets render and swap. m_semaRenderSlot.acquire(); Event::end(renderTag); int elapsed = m_timer.restart().toIntegerMicros(); int sleepTimeMicros = m_syncIntervalTimeMicros - elapsed; - //qDebug() << "RenderThread sleepTimeMicros" << sleepTimeMicros; if (sleepTimeMicros > 100) { usleep(sleepTimeMicros); } else if (sleepTimeMicros < 0) { diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 3eaaf1a0384b..809030ee2c94 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -502,38 +502,27 @@ void WaveformWidgetFactory::notifyZoomChange(WWaveformViewer* viewer) { void WaveformWidgetFactory::render() { ScopedTimer t("WaveformWidgetFactory::render() %1waveforms", m_waveformWidgetHolders.size()); - //int paintersSetupTime0 = 0; - //int paintersSetupTime1 = 0; - - //qDebug() << "render()" << m_renderThread->elapsed(); - if (!m_skipRender) { if (m_type) { // no regular updates for an empty waveform - // next rendered frame is displayed after next buffer swap and than after Render - //qDebug() << "prerender" << m_renderThread->elapsed(); - - // It may happen that there is an artificially delayed due to - // anti tearing driver settings - // all render commands are delayed until the swap from the previous run is executed + // Tell all active waveform widgets to render themselves on the next + // tick. for (std::size_t i = 0; i < m_waveformWidgetHolders.size(); i++) { WaveformWidgetAbstract* pWaveformWidget = m_waveformWidgetHolders[i].m_waveformWidget; if (!shouldRenderWaveform(pWaveformWidget)) { continue; } pWaveformWidget->renderOnNextTick(); - //qDebug() << "render" << i << m_renderThread->elapsed(); } } // WSpinnys are also double-buffered QOpenGLWidgets, like all the - // waveform renderers. Render all the WSpinny widgets now. + // waveform renderers. Tell all the WSpinnys to render themselves on the + // next tick. emit renderSpinnies(); - // Notify all other waveform-like widgets (e.g. WSpinny's) that they should + // Notify all other waveform-like widgets (e.g. WVuMeter's) that they should // update. - //int t1 = m_renderThread->elapsed(); emit waveformUpdateTick(); - //qDebug() << "emit" << m_renderThread->elapsed() - t1; m_frameCnt += 1.0; mixxx::Duration timeCnt = m_time.elapsed(); @@ -547,8 +536,6 @@ void WaveformWidgetFactory::render() { m_pVisualsManager->process(m_endOfTrackWarningTime); m_pGuiTick->process(); - - //qDebug() << "refresh end" << m_renderThread->elapsed(); m_renderThread->renderSlotFinished(); } From 53f6e16264c31b5449d4c1241f119ff586d5289f Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 08:20:14 -0700 Subject: [PATCH 24/30] Restore QOpenGLWidget::makeCurrent() calls in constructors. This has no effect on macOS because the widget's QOpenGLContext is not created until the widget is shown or resized, but its removal may be causing segfaults on Linux. --- src/waveform/widgets/baseqopenglwidget.cpp | 7 +++++++ src/widget/wspinny.cpp | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/waveform/widgets/baseqopenglwidget.cpp b/src/waveform/widgets/baseqopenglwidget.cpp index 64478a1d3f98..786ece284b60 100644 --- a/src/waveform/widgets/baseqopenglwidget.cpp +++ b/src/waveform/widgets/baseqopenglwidget.cpp @@ -13,6 +13,13 @@ BaseQOpenGLWidget::BaseQOpenGLWidget(const char* group, QWidget* pParent) this, &BaseQOpenGLWidget::slotAboutToCompose); connect(this, &QOpenGLWidget::frameSwapped, this, &BaseQOpenGLWidget::slotFrameSwapped); + auto thisContext = context(); + qDebug() << "Created QOpenGLWidget. Context" + << "Valid:" << (thisContext && thisContext->isValid()); + // Make our context current for OpenGL work done in child constructors. + if (QOpenGLContext::currentContext() != thisContext) { + makeCurrent(); + } } void BaseQOpenGLWidget::slotAboutToCompose() { diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index c52cb59c7212..38965d5a83e7 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -63,6 +63,14 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, m_pDlgCoverArt(new DlgCoverArtFullSize(parent, pPlayer)), m_pCoverMenu(new WCoverArtMenu(this)), m_shouldRenderOnNextTick(false) { + auto thisContext = context(); + qDebug() << "Created QOpenGLWidget. Context" + << "Valid:" << (thisContext && thisContext->isValid()); + // Make our context current for OpenGL work done in child constructors. + if (QOpenGLContext::currentContext() != thisContext) { + makeCurrent(); + } + #ifdef __VINYLCONTROL__ m_pVCManager = pVCMan; #endif From 120976f66d9060577d2d132bfa83c854e98cfca8 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 09:02:22 -0700 Subject: [PATCH 25/30] Move all OpenGL work out of constructors. With QOpenGLWidget, no work should be done in constructors since our QOpenGLContext is not valid until the widget is shown. QAbstractOpenGLFunctions::initializeOpenGLFunctions is cheap (only does work if it has never been called), so we can call it on every draw() without a performance penalty. --- src/waveform/renderers/glslwaveformrenderersignal.cpp | 6 +++--- src/waveform/renderers/glslwaveformrenderersignal.h | 8 ++++---- src/waveform/renderers/glvsynctestrenderer.cpp | 3 +-- src/waveform/renderers/glvsynctestrenderer.h | 8 ++++---- .../renderers/glwaveformrendererfilteredsignal.cpp | 2 +- src/waveform/renderers/glwaveformrendererfilteredsignal.h | 6 +++--- src/waveform/renderers/glwaveformrendererrgb.cpp | 2 +- src/waveform/renderers/glwaveformrenderersimplesignal.cpp | 2 +- src/waveform/renderers/glwaveformrenderersimplesignal.h | 5 +++-- src/waveform/renderers/qtwaveformrenderersimplesignal.h | 6 +++--- src/waveform/renderers/waveformrenderersignalbase.h | 2 +- src/waveform/renderers/waveformwidgetrenderer.h | 2 +- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/waveform/renderers/glslwaveformrenderersignal.cpp b/src/waveform/renderers/glslwaveformrenderersignal.cpp index 13195d5631fd..4e1b2a9b1ac9 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.cpp +++ b/src/waveform/renderers/glslwaveformrenderersignal.cpp @@ -15,7 +15,6 @@ GLSLWaveformRendererSignal::GLSLWaveformRendererSignal(WaveformWidgetRenderer* w m_textureRenderedWaveformCompletion(0), m_bDumpPng(false), m_rgbShader(rgbShader) { - initializeOpenGLFunctions(); } GLSLWaveformRendererSignal::~GLSLWaveformRendererSignal() { @@ -29,6 +28,7 @@ GLSLWaveformRendererSignal::~GLSLWaveformRendererSignal() { } void GLSLWaveformRendererSignal::debugClick() { + initializeOpenGLFunctions(); loadShaders(); m_bDumpPng = true; } @@ -183,7 +183,6 @@ void GLSLWaveformRendererSignal::createFrameBuffers() { bool GLSLWaveformRendererSignal::onInit() { m_textureRenderedWaveformCompletion = 0; - createGeometry(); return true; } @@ -223,10 +222,11 @@ void GLSLWaveformRendererSignal::onResize() { void GLSLWaveformRendererSignal::slotWaveformUpdated() { m_textureRenderedWaveformCompletion = 0; - loadTexture(); } void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { + initializeOpenGLFunctions(); + createGeometry(); loadShaders(); createFrameBuffers(); if (!m_framebuffer || !m_framebuffer->isValid() || !m_frameShaderProgram) { diff --git a/src/waveform/renderers/glslwaveformrenderersignal.h b/src/waveform/renderers/glslwaveformrenderersignal.h index 90a22f6274ad..d9bb72ca0bce 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.h +++ b/src/waveform/renderers/glslwaveformrenderersignal.h @@ -11,9 +11,9 @@ #include "util/memory.h" #include "waveform/renderers/waveformrenderersignalbase.h" -class GLSLWaveformRendererSignal: public QObject, - public WaveformRendererSignalBase, - protected QOpenGLFunctions_2_1 { +class GLSLWaveformRendererSignal : public QObject, + public WaveformRendererSignalBase, + protected QOpenGLFunctions_2_1 { Q_OBJECT public: GLSLWaveformRendererSignal(WaveformWidgetRenderer* waveformWidgetRenderer, @@ -54,7 +54,7 @@ class GLSLWaveformRendererSignal: public QObject, std::unique_ptr m_frameShaderProgram; }; -class GLSLWaveformRendererFilteredSignal: public GLSLWaveformRendererSignal { +class GLSLWaveformRendererFilteredSignal : public GLSLWaveformRendererSignal { public: GLSLWaveformRendererFilteredSignal( WaveformWidgetRenderer* waveformWidgetRenderer) : diff --git a/src/waveform/renderers/glvsynctestrenderer.cpp b/src/waveform/renderers/glvsynctestrenderer.cpp index d1f06be01b71..7690365be155 100644 --- a/src/waveform/renderers/glvsynctestrenderer.cpp +++ b/src/waveform/renderers/glvsynctestrenderer.cpp @@ -10,7 +10,6 @@ GLVSyncTestRenderer::GLVSyncTestRenderer( WaveformWidgetRenderer* waveformWidgetRenderer) : WaveformRendererSignalBase(waveformWidgetRenderer), m_drawcount(0) { - initializeOpenGLFunctions(); } GLVSyncTestRenderer::~GLVSyncTestRenderer() { @@ -26,7 +25,7 @@ inline void setPoint(QPointF& point, qreal x, qreal y) { } void GLVSyncTestRenderer::draw(QPainter* painter, QPaintEvent* /*event*/) { - + initializeOpenGLFunctions(); PerformanceTimer timer; //mixxx::Duration t5, t6, t7, t8, t9, t10, t11, t12, t13; diff --git a/src/waveform/renderers/glvsynctestrenderer.h b/src/waveform/renderers/glvsynctestrenderer.h index b9a31049eb3f..c8b194e88071 100644 --- a/src/waveform/renderers/glvsynctestrenderer.h +++ b/src/waveform/renderers/glvsynctestrenderer.h @@ -7,16 +7,16 @@ class ControlObject; -class GLVSyncTestRenderer: public WaveformRendererSignalBase, - protected QOpenGLFunctions_2_1 { -public: +class GLVSyncTestRenderer : public WaveformRendererSignalBase, + protected QOpenGLFunctions_2_1 { + public: explicit GLVSyncTestRenderer( WaveformWidgetRenderer* waveformWidgetRenderer); virtual ~GLVSyncTestRenderer(); virtual void onSetup(const QDomNode &node); virtual void draw(QPainter* painter, QPaintEvent* event); -private: + private: int m_drawcount; }; diff --git a/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp b/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp index 5c65e48e5ac2..53a9b2d95f55 100644 --- a/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp +++ b/src/waveform/renderers/glwaveformrendererfilteredsignal.cpp @@ -12,7 +12,6 @@ GLWaveformRendererFilteredSignal::GLWaveformRendererFilteredSignal( WaveformWidgetRenderer* waveformWidgetRenderer) : WaveformRendererSignalBase(waveformWidgetRenderer) { - initializeOpenGLFunctions(); } GLWaveformRendererFilteredSignal::~GLWaveformRendererFilteredSignal() { @@ -24,6 +23,7 @@ void GLWaveformRendererFilteredSignal::onSetup(const QDomNode& /*node*/) { } void GLWaveformRendererFilteredSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { + initializeOpenGLFunctions(); TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); if (!pTrack) { diff --git a/src/waveform/renderers/glwaveformrendererfilteredsignal.h b/src/waveform/renderers/glwaveformrendererfilteredsignal.h index 807ee928eab0..5ee385eb99e1 100644 --- a/src/waveform/renderers/glwaveformrendererfilteredsignal.h +++ b/src/waveform/renderers/glwaveformrendererfilteredsignal.h @@ -9,9 +9,9 @@ class ControlObject; -class GLWaveformRendererFilteredSignal: public WaveformRendererSignalBase, - protected QOpenGLFunctions_2_1 { -public: +class GLWaveformRendererFilteredSignal : public WaveformRendererSignalBase, + protected QOpenGLFunctions_2_1 { + public: explicit GLWaveformRendererFilteredSignal( WaveformWidgetRenderer* waveformWidgetRenderer); virtual ~GLWaveformRendererFilteredSignal(); diff --git a/src/waveform/renderers/glwaveformrendererrgb.cpp b/src/waveform/renderers/glwaveformrendererrgb.cpp index 7620dae20038..16293f411d70 100644 --- a/src/waveform/renderers/glwaveformrendererrgb.cpp +++ b/src/waveform/renderers/glwaveformrendererrgb.cpp @@ -11,7 +11,6 @@ GLWaveformRendererRGB::GLWaveformRendererRGB( WaveformWidgetRenderer* waveformWidgetRenderer) : WaveformRendererSignalBase(waveformWidgetRenderer) { - initializeOpenGLFunctions(); } GLWaveformRendererRGB::~GLWaveformRendererRGB() { @@ -21,6 +20,7 @@ void GLWaveformRendererRGB::onSetup(const QDomNode& /* node */) { } void GLWaveformRendererRGB::draw(QPainter* painter, QPaintEvent* /*event*/) { + initializeOpenGLFunctions(); TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); if (!pTrack) { return; diff --git a/src/waveform/renderers/glwaveformrenderersimplesignal.cpp b/src/waveform/renderers/glwaveformrenderersimplesignal.cpp index 3a161f74f962..b9aa796fd45f 100644 --- a/src/waveform/renderers/glwaveformrenderersimplesignal.cpp +++ b/src/waveform/renderers/glwaveformrenderersimplesignal.cpp @@ -9,7 +9,6 @@ GLWaveformRendererSimpleSignal::GLWaveformRendererSimpleSignal( WaveformWidgetRenderer* waveformWidgetRenderer) : WaveformRendererSignalBase(waveformWidgetRenderer) { - initializeOpenGLFunctions(); } GLWaveformRendererSimpleSignal::~GLWaveformRendererSimpleSignal() { @@ -25,6 +24,7 @@ inline void setPoint(QPointF& point, qreal x, qreal y) { } void GLWaveformRendererSimpleSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { + initializeOpenGLFunctions(); TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); if (!pTrack) { return; diff --git a/src/waveform/renderers/glwaveformrenderersimplesignal.h b/src/waveform/renderers/glwaveformrenderersimplesignal.h index 48e698803d77..02183dd720fa 100644 --- a/src/waveform/renderers/glwaveformrenderersimplesignal.h +++ b/src/waveform/renderers/glwaveformrenderersimplesignal.h @@ -7,8 +7,9 @@ class ControlObject; -class GLWaveformRendererSimpleSignal : public WaveformRendererSignalBase, protected QOpenGLFunctions_2_1 { -public: +class GLWaveformRendererSimpleSignal : public WaveformRendererSignalBase, + protected QOpenGLFunctions_2_1 { + public: explicit GLWaveformRendererSimpleSignal(WaveformWidgetRenderer* waveformWidgetRenderer); virtual ~GLWaveformRendererSimpleSignal(); diff --git a/src/waveform/renderers/qtwaveformrenderersimplesignal.h b/src/waveform/renderers/qtwaveformrenderersimplesignal.h index a041fc9ca135..521af5474194 100644 --- a/src/waveform/renderers/qtwaveformrenderersimplesignal.h +++ b/src/waveform/renderers/qtwaveformrenderersimplesignal.h @@ -11,17 +11,17 @@ class ControlObject; class QtWaveformRendererSimpleSignal : public WaveformRendererSignalBase { -public: + public: explicit QtWaveformRendererSimpleSignal(WaveformWidgetRenderer* waveformWidgetRenderer); virtual ~QtWaveformRendererSimpleSignal(); virtual void onSetup(const QDomNode &node); virtual void draw(QPainter* painter, QPaintEvent* event); -protected: + protected: virtual void onResize(); -private: + private: QBrush m_brush; QPen m_borderPen; QVector m_polygon; diff --git a/src/waveform/renderers/waveformrenderersignalbase.h b/src/waveform/renderers/waveformrenderersignalbase.h index ab47b753d94e..c468979a8aba 100644 --- a/src/waveform/renderers/waveformrenderersignalbase.h +++ b/src/waveform/renderers/waveformrenderersignalbase.h @@ -9,7 +9,7 @@ class ControlObject; class ControlProxy; class WaveformRendererSignalBase : public WaveformRendererAbstract { -public: + public: explicit WaveformRendererSignalBase(WaveformWidgetRenderer* waveformWidgetRenderer); virtual ~WaveformRendererSignalBase(); diff --git a/src/waveform/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 0e5798d494e1..5ca618323752 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.h +++ b/src/waveform/renderers/waveformwidgetrenderer.h @@ -148,7 +148,7 @@ class WaveformWidgetRenderer { int currentFrame; #endif -private: + private: DISALLOW_COPY_AND_ASSIGN(WaveformWidgetRenderer); friend class WaveformWidgetFactory; }; From 8644fc6a10934b3b57eae35d00057eeaa246487a Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 09:04:29 -0700 Subject: [PATCH 26/30] Revert "Restore QOpenGLWidget::makeCurrent() calls in constructors." This reverts commit 53f6e16264c31b5449d4c1241f119ff586d5289f. --- src/waveform/widgets/baseqopenglwidget.cpp | 7 ------- src/widget/wspinny.cpp | 8 -------- 2 files changed, 15 deletions(-) diff --git a/src/waveform/widgets/baseqopenglwidget.cpp b/src/waveform/widgets/baseqopenglwidget.cpp index 786ece284b60..64478a1d3f98 100644 --- a/src/waveform/widgets/baseqopenglwidget.cpp +++ b/src/waveform/widgets/baseqopenglwidget.cpp @@ -13,13 +13,6 @@ BaseQOpenGLWidget::BaseQOpenGLWidget(const char* group, QWidget* pParent) this, &BaseQOpenGLWidget::slotAboutToCompose); connect(this, &QOpenGLWidget::frameSwapped, this, &BaseQOpenGLWidget::slotFrameSwapped); - auto thisContext = context(); - qDebug() << "Created QOpenGLWidget. Context" - << "Valid:" << (thisContext && thisContext->isValid()); - // Make our context current for OpenGL work done in child constructors. - if (QOpenGLContext::currentContext() != thisContext) { - makeCurrent(); - } } void BaseQOpenGLWidget::slotAboutToCompose() { diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 38965d5a83e7..c52cb59c7212 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -63,14 +63,6 @@ WSpinny::WSpinny(QWidget* parent, const QString& group, m_pDlgCoverArt(new DlgCoverArtFullSize(parent, pPlayer)), m_pCoverMenu(new WCoverArtMenu(this)), m_shouldRenderOnNextTick(false) { - auto thisContext = context(); - qDebug() << "Created QOpenGLWidget. Context" - << "Valid:" << (thisContext && thisContext->isValid()); - // Make our context current for OpenGL work done in child constructors. - if (QOpenGLContext::currentContext() != thisContext) { - makeCurrent(); - } - #ifdef __VINYLCONTROL__ m_pVCManager = pVCMan; #endif From ea9f91d421f4ffe9aa9db9cc4a99328c6e46b9ab Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 10:16:51 -0700 Subject: [PATCH 27/30] Rework WaveformWidgetFactory initialization so that it has access to the QMainWindow. This removes the need to use QGuiApplication::focusWindow() or to walk the list of top level windows to get the QMainWindow. It also hides some implementation details of WaveformWidgetFactory from the rest of Mixxx. --- src/mixxx.cpp | 9 +++-- src/waveform/waveformwidgetfactory.cpp | 52 ++++++++++++++++++-------- src/waveform/waveformwidgetfactory.h | 13 ++++++- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 4de74d92f260..6edf33f817f5 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -407,9 +407,12 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { launchProgress(47); - WaveformWidgetFactory::createInstance(); // takes a long time - WaveformWidgetFactory::instance()->startRenderThread(m_pGuiTick, m_pVisualsManager); - WaveformWidgetFactory::instance()->setConfig(pConfig); + WaveformWidgetFactory::createInstance(); + + // Initialization can take a long time, since we create a QOpenGLWidget and + // show it. + WaveformWidgetFactory::instance()->initialize( + this, pConfig, m_pGuiTick, m_pVisualsManager); launchProgress(52); diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 809030ee2c94..67508a498110 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -115,23 +115,39 @@ WaveformWidgetFactory::WaveformWidgetFactory() m_visualGain[Low] = 1.0; m_visualGain[Mid] = 1.0; m_visualGain[High] = 1.0; +} +void WaveformWidgetFactory::detectOpenGLVersion(QMainWindow* pMainWindow) { const bool safeMode = CmdlineArgs::Instance().getSafeMode(); - QWindow* pWindow = QGuiApplication::focusWindow(); + m_openGlAvailable = false; + m_openGlesAvailable = false; + m_openGLShaderAvailable = false; + // Do not create any QOpenGLWidgets since we're in safe mode. if (safeMode) { m_openGLVersion = tr("Safe Mode"); - } else if (pWindow && pWindow->supportsOpenGL()) { - m_openGlAvailable = true; + return; + } - QWidget* w = nullptr; - for (QWidget* widget : QApplication::topLevelWidgets()) { - if (widget->inherits("QMainWindow")) { - w = widget; - break; - } + QWindow* pWindow = pMainWindow->windowHandle(); + if (!pWindow) { + pWindow = QGuiApplication::focusWindow(); + + if (!pWindow) { + qWarning() << "Couldn't find the current QWindow. Aborting OpenGL detection."; + m_openGLVersion = tr("Unknown"); + return; } - std::unique_ptr pGlW = std::make_unique(w); + } + + const QSurfaceFormat windowFormat = pWindow->format(); + qDebug() << "Found window:" << pWindow << "with surface format:" + << windowFormat + << "and supportsOpenGL=" << pWindow->supportsOpenGL(); + + if (pWindow->supportsOpenGL()) { + m_openGlAvailable = true; + std::unique_ptr pGlW = std::make_unique(pMainWindow); //glw->makeCurrent(); // does not work here pGlW->show(); // the context is only valid if the wiget is shown. QOpenGLContext* pContext = pGlW->context(); @@ -140,16 +156,14 @@ WaveformWidgetFactory::WaveformWidgetFactory() QString renderer; if (pContext) { version = QString::fromUtf8(reinterpret_cast( - pContext->functions()->glGetString(GL_VERSION))); + pContext->functions()->glGetString(GL_VERSION))); renderer = QString::fromUtf8(reinterpret_cast( - pContext->functions()->glGetString(GL_RENDERER))); + pContext->functions()->glGetString(GL_RENDERER))); } m_openGLShaderAvailable = QOpenGLShaderProgram::hasOpenGLShaderPrograms(pContext); - const QSurfaceFormat format = pWindow->format(); - - const QSurfaceFormat::RenderableType renderableType = format.renderableType(); + const QSurfaceFormat::RenderableType renderableType = windowFormat.renderableType(); QString strRenderableType; switch (renderableType) { case QSurfaceFormat::DefaultRenderableType: @@ -173,9 +187,17 @@ WaveformWidgetFactory::WaveformWidgetFactory() } else { m_openGLVersion = tr("None"); } +} +void WaveformWidgetFactory::initialize(QMainWindow* pMainWindow, + UserSettingsPointer pConfig, + GuiTick* pGuiTick, + VisualsManager* pVisualsManager) { + detectOpenGLVersion(pMainWindow); evaluateWidgets(); m_time.start(); + startRenderThread(pGuiTick, pVisualsManager); + setConfig(pConfig); } WaveformWidgetFactory::~WaveformWidgetFactory() { diff --git a/src/waveform/waveformwidgetfactory.h b/src/waveform/waveformwidgetfactory.h index 0464a30baff4..ca458ec10a3d 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -64,7 +65,13 @@ class WaveformWidgetFactory : public QObject, public Singleton Date: Mon, 13 Apr 2020 10:21:33 -0700 Subject: [PATCH 28/30] Fix the Windows build with Qt 5.14.2. --- appveyor.yml | 4 ++-- build/appveyor/build_mixxx.bat | 8 +++++--- src/mixxx.cpp | 5 +++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7dbf61367dde..678c151d0814 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -149,8 +149,8 @@ for: environment: ENVIRONMENTS_URL: https://downloads.mixxx.org/builds/buildserver/2.3.x-windows/ ENVIRONMENTS_PATH: C:\mixxx-buildserver - ENVIRONMENT_NAME: 2.3-j00013-PLATFORM-CONFIGURATION-static-36f44bd2-minimal - QT_VERSION: 5.12.0 + ENVIRONMENT_NAME: 2.3-j00019-PLATFORM-CONFIGURATION-static-55e94982-minimal + QT_VERSION: 5.14.2 MSVC_PATH: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community" PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%' diff --git a/build/appveyor/build_mixxx.bat b/build/appveyor/build_mixxx.bat index a520c471bc8c..30fa73e80524 100644 --- a/build/appveyor/build_mixxx.bat +++ b/build/appveyor/build_mixxx.bat @@ -94,9 +94,11 @@ set WINLIB_DIR=%3 SET BIN_DIR=%WINLIB_DIR%\bin SET LIB_DIR=%WINLIB_DIR%\lib SET INCLUDE_DIR=%WINLIB_DIR%\include -REM TODO(rryan): Remove hard-coding of Qt version. -set QT_VERSION=5.12.0 -SET QTDIR=%WINLIB_DIR%\Qt-%QT_VERSION% +FOR /D %%G IN (%WINLIB_DIR%\Qt-*) DO SET QTDIR=%%G +IF "!QTDIR!" EQU "" ( +echo QT not found on %WINLIB_DIR% +exit /b 1 +) if NOT EXIST "%BIN_DIR%\scons.py" ( echo. diff --git a/src/mixxx.cpp b/src/mixxx.cpp index 6edf33f817f5..3fbaf5db1ef8 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -94,6 +94,8 @@ // with references to std::max and std::min #undef max #undef min +#elif defined(Q_OS_WINDOWS) + #include #endif namespace { @@ -215,6 +217,9 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { XESetWireToError(QX11Info::display(), i, &__xErrorHandler); } } +#elif defined(Q_OS_WINDOWS) + QWindowsWindowFunctions::setHasBorderInFullScreen(this->windowHandle(), true); + QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true); #endif UserSettingsPointer pConfig = m_pSettingsManager->settings(); From 6860728914750654855e4bc2bd058323c7c03229 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 11:37:48 -0700 Subject: [PATCH 29/30] Attempt to fix the AppVeyor build when mkdir fails due to %ENVIRONMENTS_PATH% existing. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 678c151d0814..a075510fe85c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -162,7 +162,7 @@ for: - IF EXIST %WINLIB_PATH% ( echo Using cached environment %WINLIB_PATH%... ) else ( - mkdir %ENVIRONMENTS_PATH% && + mkdir %ENVIRONMENTS_PATH% & echo Downloading environment %ENVIRONMENT_NAME%... && curl -fsS -L -o%ENVIRONMENTS_PATH%\%ENVIRONMENT_NAME%.zip %ENVIRONMENTS_URL%/%ENVIRONMENT_NAME%.zip && echo Unpacking environment %ENVIRONMENT_NAME% to %ENVIRONMENTS_PATH%... && From 44b20307b79d480527337964c5309d9ef4c11629 Mon Sep 17 00:00:00 2001 From: RJ Skerry-Ryan Date: Mon, 13 Apr 2020 15:19:12 -0700 Subject: [PATCH 30/30] Use setFrameRate to set the configured FPS in WaveformWidgetFactory::setConfig. --- src/waveform/waveformwidgetfactory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 67508a498110..c2b2e38d45ac 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -215,8 +215,7 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { bool ok = false; int frameRate = m_config->getValue(ConfigKey("[Waveform]","FrameRate"), m_frameRate); - m_frameRate = math_clamp(frameRate, 1, 120); - + setFrameRate(frameRate); int endTime = m_config->getValueString(ConfigKey("[Waveform]","EndOfTrackWarningTime")).toInt(&ok); if (ok) {