diff --git a/CMakeLists.txt b/CMakeLists.txt index e26d77ce9f1..b40a5c983b4 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 diff --git a/appveyor.yml b/appveyor.yml index 7dbf61367dd..a075510fe85 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%' @@ -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%... && diff --git a/build/appveyor/build_mixxx.bat b/build/appveyor/build_mixxx.bat index a520c471bc8..30fa73e8052 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/build/depends.py b/build/depends.py index 0d41ee7da9e..391f2011439 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1147,11 +1147,10 @@ def sources(self, build): "src/widget/wwaveformviewer.cpp", - "src/waveform/sharedglcontext.cpp", "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", @@ -1183,6 +1182,7 @@ def sources(self, build): "src/waveform/renderers/glslwaveformrenderersignal.cpp", "src/waveform/renderers/glvsynctestrenderer.cpp", + "src/waveform/widgets/baseqopenglwidget.cpp", "src/waveform/waveformmarklabel.cpp", "src/waveform/widgets/waveformwidgetabstract.cpp", "src/waveform/widgets/emptywaveformwidget.cpp", diff --git a/res/shaders/passthrough.vert b/res/shaders/passthrough.vert index 38ce32d8f83..07fd12edfec 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 fe63dad0a4c..178b1be56c2 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 @@ -73,6 +74,7 @@ int main(int argc, char * argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #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/mixxx.cpp b/src/mixxx.cpp index caaaa2fbe4b..3fbaf5db1ef 100644 --- a/src/mixxx.cpp +++ b/src/mixxx.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -57,7 +56,6 @@ #include "track/track.h" #include "waveform/waveformwidgetfactory.h" #include "waveform/visualsmanager.h" -#include "waveform/sharedglcontext.h" #include "database/mixxxdb.h" #include "util/debug.h" #include "util/statsmanager.h" @@ -96,6 +94,8 @@ // with references to std::max and std::min #undef max #undef min +#elif defined(Q_OS_WINDOWS) + #include #endif namespace { @@ -217,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(); @@ -409,39 +412,12 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) { launchProgress(47); - // 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() && 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); - - QGLWidget* pContextWidget = new QGLWidget(this); - pContextWidget->setGeometry(QRect(0, 0, 3, 3)); - pContextWidget->hide(); - SharedGLContext::setWidget(pContextWidget); - } + WaveformWidgetFactory::createInstance(); - WaveformWidgetFactory::createInstance(); // takes a long time - WaveformWidgetFactory::instance()->setConfig(pConfig); - WaveformWidgetFactory::instance()->startVSync(m_pGuiTick, m_pVisualsManager); + // 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/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 30cd1c3ae7d..b433425d4e8 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -1196,11 +1196,10 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) { m_pVCManager, pPlayer); commonWidgetSetup(node, spinny); - connect(waveformWidgetFactory, SIGNAL(renderSpinnies(VSyncThread*)), spinny, SLOT(render(VSyncThread*))); - connect(waveformWidgetFactory, SIGNAL(swapSpinnies()), - spinny, SLOT(swap())); - connect(spinny, SIGNAL(trackDropped(QString, QString)), - m_pPlayerManager, SLOT(slotLoadToPlayer(QString, QString))); + connect(waveformWidgetFactory, &WaveformWidgetFactory::renderSpinnies, + spinny, &WSpinny::slotShouldRenderOnNextTick); + connect(spinny, &WSpinny::trackDropped, + m_pPlayerManager, &PlayerManager::slotLoadToPlayer); connect(spinny, &WSpinny::cloneDeck, m_pPlayerManager, &PlayerManager::slotCloneDeck); diff --git a/src/test/durationutiltest.cpp b/src/test/durationutiltest.cpp index a47649e4dbe..84f743f9e4f 100644 --- a/src/test/durationutiltest.cpp +++ b/src/test/durationutiltest.cpp @@ -151,4 +151,5 @@ TEST_F(DurationUtilTest, FormatKiloSeconds) { } + } // anonymous namespace diff --git a/src/waveform/guitick.h b/src/waveform/guitick.h index fc788e4aa12..01bae716c1a 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/renderers/glslwaveformrenderersignal.cpp b/src/waveform/renderers/glslwaveformrenderersignal.cpp index 709ee46ff14..4e1b2a9b1ac 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.cpp +++ b/src/waveform/renderers/glslwaveformrenderersignal.cpp @@ -1,7 +1,7 @@ #include "waveform/renderers/glslwaveformrenderersignal.h" #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -#include +#include #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/waveform.h" @@ -14,9 +14,7 @@ GLSLWaveformRendererSignal::GLSLWaveformRendererSignal(WaveformWidgetRenderer* w m_textureId(0), m_textureRenderedWaveformCompletion(0), m_bDumpPng(false), - m_shadersValid(false), m_rgbShader(rgbShader) { - initializeOpenGLFunctions(); } GLSLWaveformRendererSignal::~GLSLWaveformRendererSignal() { @@ -30,48 +28,41 @@ GLSLWaveformRendererSignal::~GLSLWaveformRendererSignal() { } void GLSLWaveformRendererSignal::debugClick() { + initializeOpenGLFunctions(); loadShaders(); m_bDumpPng = true; } 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(); - return false; - } - - if (!m_frameShaderProgram->link()) { - 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->bind()) { - qDebug() << "GLWaveformRendererSignalShader::loadShaders - shaders binding failed"; + if (!frameShaderProgram->link()) { + qDebug() << "GLWaveformRendererSignalShader::loadShaders link failed " + << frameShaderProgram->log(); return false; } - m_shadersValid = true; + m_frameShaderProgram = std::move(frameShaderProgram); return true; } @@ -170,6 +161,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. @@ -177,29 +171,18 @@ 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; } @@ -234,16 +217,19 @@ void GLSLWaveformRendererSignal::onSetTrack() { } void GLSLWaveformRendererSignal::onResize() { - createFrameBuffers(); + m_framebuffer.reset(); } void GLSLWaveformRendererSignal::slotWaveformUpdated() { m_textureRenderedWaveformCompletion = 0; - loadTexture(); } void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/) { - if (!m_framebuffer || !m_framebuffer->isValid() || !m_shadersValid) { + initializeOpenGLFunctions(); + createGeometry(); + 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 fc409fb8f49..d9bb72ca0bc 100644 --- a/src/waveform/renderers/glslwaveformrenderersignal.h +++ b/src/waveform/renderers/glslwaveformrenderersignal.h @@ -3,17 +3,17 @@ #include #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -#include -#include +#include +#include #include #include "track/track.h" #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, @@ -45,17 +45,16 @@ class GLSLWaveformRendererSignal: public QObject, 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 { +class GLSLWaveformRendererFilteredSignal : public GLSLWaveformRendererSignal { public: GLSLWaveformRendererFilteredSignal( WaveformWidgetRenderer* waveformWidgetRenderer) : diff --git a/src/waveform/renderers/glvsynctestrenderer.cpp b/src/waveform/renderers/glvsynctestrenderer.cpp index d1f06be01b7..7690365be15 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 b9a31049eb3..c8b194e8807 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 5c65e48e5ac..53a9b2d95f5 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 807ee928eab..5ee385eb99e 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 7620dae2003..16293f411d7 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 3a161f74f96..b9aa796fd45 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 48e698803d7..02183dd720f 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 a041fc9ca13..521af547419 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 ab47b753d94..c468979a8ab 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.cpp b/src/waveform/renderers/waveformwidgetrenderer.cpp index 8c37c2d2cdb..d1c9ee43c1c 100644 --- a/src/waveform/renderers/waveformwidgetrenderer.cpp +++ b/src/waveform/renderers/waveformwidgetrenderer.cpp @@ -94,7 +94,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) { @@ -124,7 +124,7 @@ void WaveformWidgetRenderer::onPreRender(VSyncThread* vsyncThread) { } - double truePlayPos = m_visualPlayPosition->getAtNextVSync(vsyncThread); + 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/renderers/waveformwidgetrenderer.h b/src/waveform/renderers/waveformwidgetrenderer.h index 9cab36f6c8b..5ca61832375 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;} @@ -148,7 +148,7 @@ class WaveformWidgetRenderer { int currentFrame; #endif -private: + private: DISALLOW_COPY_AND_ASSIGN(WaveformWidgetRenderer); friend class WaveformWidgetFactory; }; diff --git a/src/waveform/renderthread.cpp b/src/waveform/renderthread.cpp new file mode 100644 index 00000000000..ac53c38323d --- /dev/null +++ b/src/waveform/renderthread.cpp @@ -0,0 +1,97 @@ +#include + +#include "renderthread.h" +#include "util/performancetimer.h" +#include "util/event.h" +#include "util/counter.h" +#include "util/math.h" +#include "util/time.h" + +static const QString renderTag("RenderThread render"); + +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(renderTag); + // Request for the main thread to schedule a render. + emit(render()); + m_semaRenderSlot.acquire(); + Event::end(renderTag); + + m_timer.restart(); + usleep(1000); + } else { // if (m_renderMode == ST_TIMER) { + m_timer.restart(); + + Event::start(renderTag); + + // 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; + 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 00000000000..c143638a9d7 --- /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/sharedglcontext.cpp b/src/waveform/sharedglcontext.cpp deleted file mode 100644 index 2aee773ede6..00000000000 --- a/src/waveform/sharedglcontext.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "waveform/sharedglcontext.h" - -#include -#include -#include -#include - -QGLWidget* SharedGLContext::s_pSharedGLWidget = nullptr; - -// static -void SharedGLContext::setWidget(QGLWidget* pWidget) { - s_pSharedGLWidget = pWidget; - qDebug() << "Set root GL Context widget valid:" - << pWidget << (pWidget && pWidget->isValid()); - if (pWidget) { - const QGLContext* pContext = pWidget->context(); - qDebug() << "Created root GL Context valid:" << pContext - << (pContext && pContext->isValid()); - 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 -QGLWidget* SharedGLContext::getWidget() { - return s_pSharedGLWidget; -} diff --git a/src/waveform/sharedglcontext.h b/src/waveform/sharedglcontext.h deleted file mode 100644 index d14897cac30..00000000000 --- 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 QGLWidget* getWidget(); - static void setWidget(QGLWidget* pWidget); - private: - SharedGLContext() { } - static QGLWidget* s_pSharedGLWidget; -}; - -#endif /* WAVEFORM_SHAREDGLCONTEXT_H */ diff --git a/src/waveform/visualplayposition.cpp b/src/waveform/visualplayposition.cpp index 008a7fc61c7..683c1c2d5bc 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. @@ -50,38 +49,53 @@ void VisualPlayPosition::set(double playPos, double rate, double positionStep, m_valid = true; } -double VisualPlayPosition::getAtNextVSync(VSyncThread* vSyncThread) { +double VisualPlayPosition::getPlayPositionAtNextSwap(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::getPlaySlipAtNextVSync(VSyncThread* vSyncThread, double* pPlayPosition, double* pSlipPosition) { +void VisualPlayPosition::getPlaySlipAtNextSwap(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 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(); + 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 badbf6b77e6..7d97bac00cc 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 { @@ -47,9 +47,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 getPlaySlipAtNextVSync(VSyncThread* vSyncThread, double* playPosition, double* slipPosition); + double pSlipPosition, double tempoTrackSeconds); + double getPlayPositionAtNextSwap(mixxx::Duration estimatedTimeUntilSwap); + void getPlaySlipAtNextSwap(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 deleted file mode 100644 index 31034336396..00000000000 --- a/src/waveform/vsyncthread.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include -#include -#include -#include -#include - -#include "vsyncthread.h" -#include "util/performancetimer.h" -#include "util/math.h" -#include "waveform/guitick.h" - -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::run() { - QThread::currentThread()->setObjectName("VSyncThread"); - - m_waitToSwapMicros = m_syncIntervalTimeMicros; - m_timer.start(); - - //qDebug() << "VSyncThread::run()"; - while (m_bDoRendering) { - if (m_vSyncMode == ST_FREE) { - // for benchmark only! - - // renders the waveform, Possible delayed due to anti tearing - emit vsyncRender(); - m_semaVsyncSlot.acquire(); - - emit vsyncSwap(); // swaps the new waveform to front - m_semaVsyncSlot.acquire(); - - m_timer.restart(); - m_waitToSwapMicros = 1000; - usleep(1000); - } else { // if (m_vSyncMode == ST_TIMER) { - 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(); - - // qDebug() << "ST_TIMER " << lastMicros << restMicros; - int remainingForSwap = m_waitToSwapMicros - static_cast( - m_timer.elapsed().toIntegerMicros()); - // waiting for interval by sleep - if (remainingForSwap > 100) { - usleep(remainingForSwap); - } - - // 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(); - - // <- 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 - } - // try to stay in right intervals - m_waitToSwapMicros = m_syncIntervalTimeMicros + - ((m_waitToSwapMicros - lastSwapTime) % m_syncIntervalTimeMicros); - } - } -} - -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 7d110f87154..00000000000 --- a/src/waveform/vsyncthread.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef VSYNCTHREAD_H -#define VSYNCTHREAD_H - -#include -#include -#include -#include -#include - -#include "util/performancetimer.h" - -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(); - - 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(); - void vsyncSwap(); - - private: - bool m_bDoRendering; - 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 5dade621b96..c2b2e38d45a 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -4,15 +4,17 @@ #include #include #include -#include +#include #include +#include #include +#include #include +#include #include "waveform/waveformwidgetfactory.h" #include "control/controlpotmeter.h" -#include "waveform/sharedglcontext.h" #include "waveform/widgets/emptywaveformwidget.h" #include "waveform/widgets/softwarewaveformwidget.h" #include "waveform/widgets/hsvwaveformwidget.h" @@ -31,11 +33,13 @@ #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" #include "util/timer.h" #include "util/math.h" +#include "util/memory.h" namespace { // Returns true if the given waveform should be rendered. @@ -46,9 +50,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(); } @@ -57,13 +61,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 @@ -107,166 +104,105 @@ WaveformWidgetFactory::WaveformWidgetFactory() m_openGlesAvailable(false), m_openGLShaderAvailable(false), m_beatGridAlpha(90), - m_vsyncThread(nullptr), + m_renderThread(nullptr), 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; m_visualGain[Low] = 1.0; m_visualGain[Mid] = 1.0; m_visualGain[High] = 1.0; +} - QGLWidget* pGlWidget = SharedGLContext::getWidget(); - if (pGlWidget && pGlWidget->isValid()) { - // will be false if SafeMode is enabled - - pGlWidget->show(); - // Without a makeCurrent, hasOpenGLShaderPrograms returns false on Qt 5. - // and QGLFormat::openGLVersionFlags() returns the maximum known version - pGlWidget->makeCurrent(); - - QGLFormat::OpenGLVersionFlags version = QGLFormat::openGLVersionFlags(); - - auto rendererString = QString(); - if (QOpenGLContext::currentContext()) { - auto glFunctions = QOpenGLFunctions(); +void WaveformWidgetFactory::detectOpenGLVersion(QMainWindow* pMainWindow) { + const bool safeMode = CmdlineArgs::Instance().getSafeMode(); + m_openGlAvailable = false; + m_openGlesAvailable = false; + m_openGLShaderAvailable = false; - glFunctions.initializeOpenGLFunctions(); - QString versionString(QLatin1String( - reinterpret_cast(glFunctions.glGetString(GL_VERSION)))); - QString vendorString(QLatin1String( - reinterpret_cast(glFunctions.glGetString(GL_VENDOR)))); - rendererString = QString(QLatin1String( - reinterpret_cast(glFunctions.glGetString(GL_RENDERER)))); + // Do not create any QOpenGLWidgets since we're in safe mode. + if (safeMode) { + m_openGLVersion = tr("Safe Mode"); + return; + } - // Either GL or GL ES Version is set, not both. - qDebug() << QString("openGLVersionFlags 0x%1").arg(version, 0, 16) << versionString << vendorString << rendererString; - } else { - qDebug() << "QOpenGLContext::currentContext() returns nullptr"; - qDebug() << "pGlWidget->->windowHandle() =" << pGlWidget->windowHandle(); - } + QWindow* pWindow = pMainWindow->windowHandle(); + if (!pWindow) { + pWindow = QGuiApplication::focusWindow(); - int majorGlVersion = 0; - int minorGlVersion = 0; - int majorGlesVersion = 0; - int minorGlesVersion = 0; - if (version == QGLFormat::OpenGL_Version_None) { - m_openGLVersion = "None"; - } else if (version & QGLFormat::OpenGL_Version_4_3) { - majorGlVersion = 4; - minorGlVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_4_2) { - majorGlVersion = 4; - minorGlVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_4_1) { - majorGlVersion = 4; - minorGlVersion = 1; - } else if (version & QGLFormat::OpenGL_Version_4_0) { - majorGlVersion = 4; - minorGlVersion = 0; - } else if (version & QGLFormat::OpenGL_Version_3_3) { - majorGlVersion = 3; - minorGlVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_3_2) { - majorGlVersion = 3; - minorGlVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_3_1) { - majorGlVersion = 3; - minorGlVersion = 1; - } else if (version & QGLFormat::OpenGL_Version_3_0) { - majorGlVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_2_1) { - majorGlVersion = 2; - minorGlVersion = 1; - } else if (version & QGLFormat::OpenGL_Version_2_0) { - majorGlVersion = 2; - minorGlVersion = 0; - } else if (version & QGLFormat::OpenGL_Version_1_5) { - majorGlVersion = 1; - minorGlVersion = 5; - } else if (version & QGLFormat::OpenGL_Version_1_4) { - majorGlVersion = 1; - minorGlVersion = 4; - } else if (version & QGLFormat::OpenGL_Version_1_3) { - majorGlVersion = 1; - minorGlVersion = 3; - } else if (version & QGLFormat::OpenGL_Version_1_2) { - majorGlVersion = 1; - minorGlVersion = 2; - } else if (version & QGLFormat::OpenGL_Version_1_1) { - majorGlVersion = 1; - minorGlVersion = 1; - } else if (version & QGLFormat::OpenGL_ES_Version_2_0) { - m_openGLVersion = "ES 2.0"; - majorGlesVersion = 2; - minorGlesVersion = 0; - } else if (version & QGLFormat::OpenGL_ES_CommonLite_Version_1_1) { - if (version & QGLFormat::OpenGL_ES_Common_Version_1_1) { - m_openGLVersion = "ES 1.1"; - } else { - m_openGLVersion = "ES Common Lite 1.1"; - } - majorGlesVersion = 1; - minorGlesVersion = 1; - } else if (version & QGLFormat::OpenGL_ES_Common_Version_1_1) { - m_openGLVersion = "ES Common Lite 1.1"; - majorGlesVersion = 1; - minorGlesVersion = 1; - } else if (version & QGLFormat::OpenGL_ES_CommonLite_Version_1_0) { - if (version & QGLFormat::OpenGL_ES_Common_Version_1_0) { - m_openGLVersion = "ES 1.0"; - } else { - m_openGLVersion = "ES Common Lite 1.0"; - } - majorGlesVersion = 1; - minorGlesVersion = 0; - } else if (version & QGLFormat::OpenGL_ES_Common_Version_1_0) { - m_openGLVersion = "ES Common Lite 1.0"; - majorGlesVersion = 1; - minorGlesVersion = 0; - } else { - m_openGLVersion = QString("Unknown 0x%1") - .arg(version, 0, 16); + if (!pWindow) { + qWarning() << "Couldn't find the current QWindow. Aborting OpenGL detection."; + m_openGLVersion = tr("Unknown"); + return; } + } - if (majorGlVersion != 0) { - m_openGLVersion = QString::number(majorGlVersion) + "." - + QString::number(minorGlVersion); - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - if (majorGlVersion * 100 + minorGlVersion >= 201) { - // Qt5 requires at least OpenGL 2.1 or OpenGL ES 2.0 - m_openGlAvailable = true; - } -#endif - } else { - if (majorGlesVersion * 100 + minorGlesVersion >= 200) { - // Qt5 requires at least OpenGL 2.1 or OpenGL ES 2.0 - m_openGlesAvailable = true; - } + 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(); + + 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 = - QGLShaderProgram::hasOpenGLShaderPrograms( - pGlWidget->context()); + m_openGLShaderAvailable = QOpenGLShaderProgram::hasOpenGLShaderPrograms(pContext); - if (!rendererString.isEmpty()) { - m_openGLVersion += " (" + rendererString + ")"; + const QSurfaceFormat::RenderableType renderableType = windowFormat.renderableType(); + QString strRenderableType; + switch (renderableType) { + case QSurfaceFormat::DefaultRenderableType: + strRenderableType = "DefaultRenderableType"; + break; + case QSurfaceFormat::OpenGL: + strRenderableType = "OpenGL"; + break; + case QSurfaceFormat::OpenGLES: + strRenderableType = "OpenGLES"; + m_openGlesAvailable = true; + break; + case QSurfaceFormat::OpenVG: + strRenderableType = "OpenVG"; + break; + default: + strRenderableType = "Unknown Type"; + break; } - - pGlWidget->hide(); + m_openGLVersion = strRenderableType + ": " + version + " (" + renderer + ")"; + } 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() { - if (m_vsyncThread) { - delete m_vsyncThread; + if (m_renderThread) { + delete m_renderThread; } } @@ -279,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) { @@ -290,7 +225,8 @@ bool WaveformWidgetFactory::setConfig(UserSettingsPointer config) { ConfigValue(m_endOfTrackWarningTime)); } - m_vSyncType = m_config->getValue(ConfigKey("[Waveform]","VSync"), 0); + int render = m_config->getValue(ConfigKey("[Waveform]","Render"), 0); + setRenderType(render); double defaultZoom = m_config->getValueString(ConfigKey("[Waveform]","DefaultZoom")).toDouble(&ok); if (ok) { @@ -402,8 +338,8 @@ void WaveformWidgetFactory::setFrameRate(int frameRate) { if (m_config) { m_config->set(ConfigKey("[Waveform]","FrameRate"), ConfigValue(m_frameRate)); } - if (m_vsyncThread) { - m_vsyncThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); + if (m_renderThread) { + m_renderThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); } } @@ -414,21 +350,17 @@ 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; - if (m_vsyncThread) { - m_vsyncThread->setVSyncType(type); + m_renderType = type; + if (m_renderThread) { + m_renderThread->setRenderType(type); } } -int WaveformWidgetFactory::getVSyncType() { - return m_vSyncType; -} - bool WaveformWidgetFactory::setWidgetType(WaveformWidgetType::Type type) { if (type == m_type) return true; @@ -591,100 +523,41 @@ 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_vsyncThread->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 VSync - QVarLengthArray shouldRenderWaveforms(m_waveformWidgetHolders.size()); - for (std::size_t 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 - // 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 (!shouldRenderWaveforms[i]) { + if (!shouldRenderWaveform(pWaveformWidget)) { continue; } - pWaveformWidget->render(); - //qDebug() << "render" << i << m_vsyncThread->elapsed(); + pWaveformWidget->renderOnNextTick(); } } - // WSpinnys are also double-buffered QGLWidgets, like all the waveform - // renderers. Render all the WSpinny widgets now. - emit renderSpinnies(m_vsyncThread); + // WSpinnys are also double-buffered QOpenGLWidgets, like all the + // 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_vsyncThread->elapsed(); emit waveformUpdateTick(); - //qDebug() << "emit" << m_vsyncThread->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; } } m_pVisualsManager->process(m_endOfTrackWarningTime); m_pGuiTick->process(); - - //qDebug() << "refresh end" << m_vsyncThread->elapsed(); - 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 (std::size_t 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; - } - QGLWidget* glw = dynamic_cast(pWaveformWidget->getWidget()); - if (glw != nullptr) { - glw->swapBuffers(); - } - //qDebug() << "swap x" << m_vsyncThread->elapsed(); - } - } - // WSpinnys are also double-buffered QGLWidgets, like all the waveform - // renderers. Swap all the WSpinny widgets now. - emit swapSpinnies(); - } - //qDebug() << "swap end" << m_vsyncThread->elapsed(); - m_vsyncThread->vsyncSlotFinished(); + m_renderThread->renderSlotFinished(); } WaveformWidgetType::Type WaveformWidgetFactory::autoChooseWidgetType() const { @@ -847,7 +720,7 @@ void WaveformWidgetFactory::evaluateWidgets() { } } } else { - // No sufficiant GL supptor + // No sufficiant GL support if (useOpenGles || useOpenGl || useOpenGLShaders) { active = false; } @@ -926,12 +799,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; @@ -950,26 +823,25 @@ 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->setVSyncType(m_vSyncType); - m_vsyncThread->setSyncIntervalTimeMicros(1e6 / m_frameRate); - - connect(m_vsyncThread, - &VSyncThread::vsyncRender, - this, - &WaveformWidgetFactory::render); - connect(m_vsyncThread, - &VSyncThread::vsyncSwap, - this, - &WaveformWidgetFactory::swap); - - m_vsyncThread->start(QThread::NormalPriority); -} - -void WaveformWidgetFactory::getAvailableVSyncTypes(QList >* pList) { - m_vsyncThread->getAvailableVSyncTypes(pList); + 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())); +} + +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 ad00e02c322..ca458ec10a3 100644 --- a/src/waveform/waveformwidgetfactory.h +++ b/src/waveform/waveformwidgetfactory.h @@ -2,12 +2,14 @@ #include +#include #include #include #include #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" @@ -16,7 +18,6 @@ class WWaveformViewer; class WaveformWidgetAbstract; class QTimer; -class VSyncThread; class GuiTick; class VisualsManager; @@ -62,7 +63,15 @@ 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 setPlayMarkerPosition(double position); double getPlayMarkerPosition() const { return m_playMarkerPosition; } @@ -122,8 +128,7 @@ class WaveformWidgetFactory : public QObject, public Singleton +#include + +#include "waveform/widgets/baseqopenglwidget.h" + +#include "util/time.h" + +BaseQOpenGLWidget::BaseQOpenGLWidget(const char* group, QWidget* pParent) + : QOpenGLWidget(pParent), + WaveformWidgetAbstract(group), + m_shouldRenderOnNextTick(false) { + connect(this, &QOpenGLWidget::aboutToCompose, + this, &BaseQOpenGLWidget::slotAboutToCompose); + connect(this, &QOpenGLWidget::frameSwapped, + this, &BaseQOpenGLWidget::slotFrameSwapped); +} + +void BaseQOpenGLWidget::slotAboutToCompose() { + if (m_shouldRenderOnNextTick) { + m_lastRender = mixxx::Time::elapsed(); + preRender(m_lastSwapDurationMovingAverage); + render(); + m_shouldRenderOnNextTick = false; + } +} + +void BaseQOpenGLWidget::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()); + } +} diff --git a/src/waveform/widgets/baseqopenglwidget.h b/src/waveform/widgets/baseqopenglwidget.h new file mode 100644 index 00000000000..bfe4c8e4557 --- /dev/null +++ b/src/waveform/widgets/baseqopenglwidget.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "util/duration.h" +#include "waveform/widgets/waveformwidgetabstract.h" + +class BaseQOpenGLWidget : public QOpenGLWidget, public WaveformWidgetAbstract { + Q_OBJECT + public: + // Makes the QOpenGLContext current to facilitate setup logic in child + // constructors. + BaseQOpenGLWidget(const char* group, QWidget* pParent); + virtual ~BaseQOpenGLWidget() = default; + + // 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: + void slotAboutToCompose(); + void slotFrameSwapped(); + + private: + bool m_shouldRenderOnNextTick; + 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 614dda843bc..8ab75be42d2 100644 --- a/src/waveform/widgets/emptywaveformwidget.h +++ b/src/waveform/widgets/emptywaveformwidget.h @@ -24,7 +24,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 13a3464656f..c27c68df574 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,17 +11,10 @@ #include "util/performancetimer.h" -GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } +#include +GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -36,8 +28,6 @@ GLRGBWaveformWidget::GLRGBWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -46,7 +36,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) { @@ -58,7 +48,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 0cfbc5efac2..34f4e7115ef 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 QGLWidget, public WaveformWidgetAbstract { +class GLRGBWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLRGBWaveformWidget(const char* group, QWidget* parent); @@ -22,7 +20,9 @@ class GLRGBWaveformWidget : public QGLWidget, 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 54c4e4fc317..88d08f56d94 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,15 +16,7 @@ #include "util/performancetimer.h" GLSimpleWaveformWidget::GLSimpleWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -38,19 +30,17 @@ GLSimpleWaveformWidget::GLSimpleWaveformWidget(const char* group, QWidget* paren setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - 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) { @@ -62,7 +52,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 786b9f72914..ebf434798ed 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 QGLWidget, public WaveformWidgetAbstract { +class GLSimpleWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLSimpleWaveformWidget(const char* group, QWidget* parent); @@ -22,7 +20,9 @@ class GLSimpleWaveformWidget : public QGLWidget, 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/glslwaveformwidget.cpp b/src/waveform/widgets/glslwaveformwidget.cpp index c1b6f746848..5e4b916b855 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,9 +12,9 @@ #include "waveform/renderers/waveformrendermarkrange.h" #include "waveform/renderers/waveformrendererendoftrack.h" #include "waveform/renderers/waveformrenderbeat.h" -#include "waveform/sharedglcontext.h" #include "util/performancetimer.h" +#include "util/time.h" GLSLFilteredWaveformWidget::GLSLFilteredWaveformWidget(const char* group, QWidget* parent) @@ -26,15 +27,7 @@ GLSLRGBWaveformWidget::GLSLRGBWaveformWidget(const char* group, QWidget* parent) GLSLWaveformWidget::GLSLWaveformWidget(const char* group, QWidget* parent, bool rgbRenderer) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -54,8 +47,6 @@ GLSLWaveformWidget::GLSLWaveformWidget(const char* group, QWidget* parent, setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -64,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) { @@ -76,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 2a28d3944b6..87ecd91c4c4 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 QGLWidget, public WaveformWidgetAbstract { +class GLSLWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLSLWaveformWidget(const char* group, QWidget* parent, @@ -20,6 +19,8 @@ class GLSLWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { void castToQWidget() override; void paintEvent(QPaintEvent* event) override; void mouseDoubleClickEvent(QMouseEvent *) override; + + protected slots: mixxx::Duration render() override; private: diff --git a/src/waveform/widgets/glvsynctestwidget.cpp b/src/waveform/widgets/glvsynctestwidget.cpp index 3a788d1f9bc..26e31b8dd30 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,15 +16,7 @@ #include "util/performancetimer.h" GLVSyncTestWidget::GLVSyncTestWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); // 172 µs // addRenderer(); // 677 µs 1145 µs (active) // addRenderer(); // 652 µs 2034 µs (active) @@ -40,20 +32,17 @@ GLVSyncTestWidget::GLVSyncTestWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - 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) { @@ -65,7 +54,7 @@ mixxx::Duration GLVSyncTestWidget::render() { mixxx::Duration t1; //mixxx::Duration t2; 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 8480f99a31f..e2176e387cb 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 QGLWidget, public WaveformWidgetAbstract { +class GLVSyncTestWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLVSyncTestWidget(const char* group, QWidget* parent); @@ -22,7 +20,9 @@ class GLVSyncTestWidget : public QGLWidget, 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 b24de85ee9a..c6a832de2af 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,19 +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()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -38,8 +29,6 @@ GLWaveformWidget::GLWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -47,7 +36,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) { @@ -59,7 +48,7 @@ mixxx::Duration GLWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2; 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 0e13ff01ba5..99d6912c0c6 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 QGLWidget, public WaveformWidgetAbstract { +class GLWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: GLWaveformWidget(const char* group, QWidget* parent); @@ -22,7 +20,9 @@ class GLWaveformWidget : public QGLWidget, 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/hsvwaveformwidget.cpp b/src/waveform/widgets/hsvwaveformwidget.cpp index 14d7ec1670f..c4c920d1e2c 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/qthsvwaveformwidget.cpp b/src/waveform/widgets/qthsvwaveformwidget.cpp index 01b0df51243..eab7e891869 100644 --- a/src/waveform/widgets/qthsvwaveformwidget.cpp +++ b/src/waveform/widgets/qthsvwaveformwidget.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include "waveform/widgets/qthsvwaveformwidget.h" @@ -14,8 +14,7 @@ #include "waveform/renderers/waveformrenderbeat.h" QtHSVWaveformWidget::QtHSVWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent), - WaveformWidgetAbstract(group) { + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -34,7 +33,7 @@ QtHSVWaveformWidget::~QtHSVWaveformWidget() { } void QtHSVWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void QtHSVWaveformWidget::paintEvent(QPaintEvent* event) { @@ -46,7 +45,7 @@ mixxx::Duration QtHSVWaveformWidget::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/qthsvwaveformwidget.h b/src/waveform/widgets/qthsvwaveformwidget.h index f273f2cb253..70bf7df2865 100644 --- a/src/waveform/widgets/qthsvwaveformwidget.h +++ b/src/waveform/widgets/qthsvwaveformwidget.h @@ -1,11 +1,9 @@ #ifndef QTHSVWAVEFORMWIDGET_H #define QTHSVWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class QtHSVWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class QtHSVWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: virtual ~QtHSVWaveformWidget(); diff --git a/src/waveform/widgets/qtrgbwaveformwidget.cpp b/src/waveform/widgets/qtrgbwaveformwidget.cpp index ec56ccc3e2f..146c2e420fe 100644 --- a/src/waveform/widgets/qtrgbwaveformwidget.cpp +++ b/src/waveform/widgets/qtrgbwaveformwidget.cpp @@ -1,5 +1,4 @@ #include -#include #include #include "waveform/widgets/qtrgbwaveformwidget.h" @@ -12,18 +11,9 @@ #include "waveform/renderers/waveformrendererpreroll.h" #include "waveform/renderers/waveformrendererendoftrack.h" #include "waveform/renderers/waveformrenderbeat.h" -#include "waveform/sharedglcontext.h" QtRGBWaveformWidget::QtRGBWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -35,8 +25,6 @@ QtRGBWaveformWidget::QtRGBWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -44,7 +32,7 @@ QtRGBWaveformWidget::~QtRGBWaveformWidget() { } void QtRGBWaveformWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void QtRGBWaveformWidget::paintEvent(QPaintEvent* event) { @@ -56,7 +44,7 @@ mixxx::Duration QtRGBWaveformWidget::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/qtrgbwaveformwidget.h b/src/waveform/widgets/qtrgbwaveformwidget.h index b502dc2c418..a41b61509b3 100644 --- a/src/waveform/widgets/qtrgbwaveformwidget.h +++ b/src/waveform/widgets/qtrgbwaveformwidget.h @@ -1,11 +1,9 @@ #ifndef QTRGBWAVEFORMWIDGET_H #define QTRGBWAVEFORMWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class QtRGBWaveformWidget : public QGLWidget, public WaveformWidgetAbstract { +class QtRGBWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: virtual ~QtRGBWaveformWidget(); diff --git a/src/waveform/widgets/qtsimplewaveformwidget.cpp b/src/waveform/widgets/qtsimplewaveformwidget.cpp index 59ca4e9ab55..8363c253ad2 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,15 +16,7 @@ #include "util/performancetimer.h" QtSimpleWaveformWidget::QtSimpleWaveformWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -36,19 +28,17 @@ QtSimpleWaveformWidget::QtSimpleWaveformWidget(const char* group, QWidget* paren setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - 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) { @@ -61,7 +51,7 @@ mixxx::Duration QtSimpleWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2; 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 5104418381c..5aa89e0a6c7 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 QGLWidget, 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"; } @@ -23,7 +20,9 @@ class QtSimpleWaveformWidget : public QGLWidget, 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/qtvsynctestwidget.cpp b/src/waveform/widgets/qtvsynctestwidget.cpp index f54906543b2..4b32e296d33 100644 --- a/src/waveform/widgets/qtvsynctestwidget.cpp +++ b/src/waveform/widgets/qtvsynctestwidget.cpp @@ -1,10 +1,8 @@ #include -#include #include #include "waveform/widgets/qtvsynctestwidget.h" -#include "waveform/sharedglcontext.h" #include "waveform/renderers/waveformwidgetrenderer.h" #include "waveform/renderers/waveformrenderbackground.h" #include "waveform/renderers/qtvsynctestrenderer.h" @@ -17,22 +15,12 @@ #include "util/performancetimer.h" QtVSyncTestWidget::QtVSyncTestWidget(const char* group, QWidget* parent) - : QGLWidget(parent, SharedGLContext::getWidget()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -40,7 +28,7 @@ QtVSyncTestWidget::~QtVSyncTestWidget() { } void QtVSyncTestWidget::castToQWidget() { - m_widget = static_cast(static_cast(this)); + m_widget = static_cast(static_cast(this)); } void QtVSyncTestWidget::paintEvent(QPaintEvent* event) { @@ -52,7 +40,7 @@ mixxx::Duration QtVSyncTestWidget::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/qtvsynctestwidget.h b/src/waveform/widgets/qtvsynctestwidget.h index 07f9872ae47..afe80ac6489 100644 --- a/src/waveform/widgets/qtvsynctestwidget.h +++ b/src/waveform/widgets/qtvsynctestwidget.h @@ -1,11 +1,9 @@ #ifndef QTVSYNCTESTWIDGET_H #define QTVSYNCTESTWIDGET_H -#include +#include "waveform/widgets/baseqopenglwidget.h" -#include "waveformwidgetabstract.h" - -class QtVSyncTestWidget : public QGLWidget, public WaveformWidgetAbstract { +class QtVSyncTestWidget : public BaseQOpenGLWidget { Q_OBJECT public: QtVSyncTestWidget(const char* group, QWidget* parent); diff --git a/src/waveform/widgets/qtwaveformwidget.cpp b/src/waveform/widgets/qtwaveformwidget.cpp index 2a8f62ad94a..af75b2c09ed 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,20 +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()), - WaveformWidgetAbstract(group) { - qDebug() << "Created QGLWidget. Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - + : BaseQOpenGLWidget(group, parent) { addRenderer(); addRenderer(); addRenderer(); @@ -37,8 +28,6 @@ QtWaveformWidget::QtWaveformWidget(const char* group, QWidget* parent) setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_OpaquePaintEvent); - setAutoBufferSwap(false); - m_initSuccess = init(); } @@ -46,7 +35,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) { @@ -58,7 +47,7 @@ mixxx::Duration QtWaveformWidget::render() { mixxx::Duration t1; //mixxx::Duration t2; 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 c9c108c2fcf..090b6c71c02 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 QGLWidget, public WaveformWidgetAbstract { +class QtWaveformWidget : public BaseQOpenGLWidget { Q_OBJECT public: QtWaveformWidget(const char* group, QWidget* parent); @@ -22,7 +20,9 @@ class QtWaveformWidget : public QGLWidget, 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 6149e194941..03fad00bff7 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() { @@ -26,8 +26,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 41ee222a6f7..5a3f0d3581e 100644 --- a/src/waveform/widgets/waveformwidgetabstract.h +++ b/src/waveform/widgets/waveformwidgetabstract.h @@ -9,11 +9,9 @@ #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 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 { @@ -24,14 +22,19 @@ 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(); void release(); - virtual void preRender(VSyncThread* vsyncThread); + virtual void preRender(mixxx::Duration estimatedTimeUntilSwap); virtual mixxx::Duration render(); + 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); protected: diff --git a/src/widget/wspinny.cpp b/src/widget/wspinny.cpp index 2dc4f2eecfc..c52cb59c721 100644 --- a/src/widget/wspinny.cpp +++ b/src/widget/wspinny.cpp @@ -1,9 +1,10 @@ -#include #include -#include #include +#include #include +#include #include +#include #include "control/controlobject.h" #include "control/controlproxy.h" @@ -11,23 +12,20 @@ #include "library/coverartutils.h" #include "util/compatibility.h" #include "util/dnd.h" -#include "waveform/sharedglcontext.h" #include "util/math.h" +#include "util/time.h" #include "waveform/visualplayposition.h" -#include "waveform/vsyncthread.h" #include "vinylcontrol/vinylcontrol.h" #include "vinylcontrol/vinylcontrolmanager.h" #include "widget/wspinny.h" #include "wimagestore.h" // The SampleBuffers format enables antialiasing. -WSpinny::WSpinny( - QWidget* parent, - const QString& group, - UserSettingsPointer pConfig, - VinylControlManager* pVCMan, - BaseTrackPlayer* pPlayer) - : QGLWidget(parent, SharedGLContext::getWidget()), +WSpinny::WSpinny(QWidget* parent, const QString& group, + UserSettingsPointer pConfig, + VinylControlManager* pVCMan, + BaseTrackPlayer* pPlayer) + : QOpenGLWidget(parent), WBaseWidget(this), m_group(group), m_pConfig(pConfig), @@ -63,19 +61,13 @@ WSpinny::WSpinny( 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 //Drag and drop setAcceptDrops(true); - qDebug() << "WSpinny(): Created QGLWidget, Context" - << "Valid:" << context()->isValid() - << "Sharing:" << context()->isSharing(); - if (QGLContext::currentContext() != context()) { - makeCurrent(); - } - CoverArtCache* pCache = CoverArtCache::instance(); if (pCache) { connect(pCache, @@ -102,7 +94,10 @@ WSpinny::WSpinny( setAttribute(Qt::WA_OpaquePaintEvent); setAutoFillBackground(false); - setAutoBufferSwap(false); + connect(this, &QOpenGLWidget::aboutToCompose, + this, &WSpinny::slotAboutToCompose); + connect(this, &QOpenGLWidget::frameSwapped, + this, &WSpinny::slotFrameSwapped); } WSpinny::~WSpinny() { @@ -304,21 +299,15 @@ void WSpinny::paintEvent(QPaintEvent *e) { Q_UNUSED(e); } -void WSpinny::render(VSyncThread* vSyncThread) { +void WSpinny::render() { if (!isValid() || !isVisible()) { return; } - auto window = windowHandle(); - if (window == nullptr || !window->isExposed()) { - return; - } - - if (!m_pVisualPlayPos.isNull() && vSyncThread != nullptr) { - m_pVisualPlayPos->getPlaySlipAtNextVSync( - vSyncThread, - &m_dAngleCurrentPlaypos, - &m_dGhostAngleCurrentPlaypos); + if (!m_pVisualPlayPos.isNull()) { + m_pVisualPlayPos->getPlaySlipAtNextSwap(m_lastSwapDurationMovingAverage, + &m_dAngleCurrentPlaypos, + &m_dGhostAngleCurrentPlaypos); } double scaleFactor = getDevicePixelRatioF(this); @@ -391,18 +380,6 @@ void WSpinny::render(VSyncThread* vSyncThread) { } } -void WSpinny::swap() { - if (!isValid() || !isVisible()) { - return; - } - auto window = windowHandle(); - if (window == nullptr || !window->isExposed()) { - return; - } - swapBuffers(); -} - - QPixmap WSpinny::scaledCoverArt(const QPixmap& normal) { if (normal.isNull()) { return QPixmap(); @@ -413,7 +390,8 @@ QPixmap WSpinny::scaledCoverArt(const QPixmap& normal) { return scaled; } -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( @@ -679,7 +657,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) { @@ -689,3 +667,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 5ae7a28c895..bfba80f136f 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 @@ -17,13 +17,14 @@ #include "widget/wbasewidget.h" #include "widget/wcoverartmenu.h" #include "widget/wwidget.h" +#include "util/duration.h" class ControlProxy; class VisualPlayPosition; class VinylControlManager; class VSyncThread; -class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityListener, +class WSpinny : public QOpenGLWidget, public WBaseWidget, public VinylSignalQualityListener, public TrackDropTarget { Q_OBJECT public: @@ -46,8 +47,7 @@ class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityL void updateVinylControlEnabled(double enabled); void updateVinylControlSignalEnabled(double enabled); void updateSlipEnabled(double enabled); - void render(VSyncThread* vSyncThread); - void swap(); + void slotShouldRenderOnNextTick(); protected slots: void slotCoverFound( @@ -60,7 +60,6 @@ class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityL void slotReloadCoverArt(); void slotTrackCoverArtUpdated(); - signals: void trackDropped(QString filename, QString group) override; void cloneDeck(QString source_group, QString target_group) override; @@ -71,7 +70,7 @@ class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityL 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; @@ -81,7 +80,13 @@ class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityL double calculatePositionFromAngle(double angle); QPixmap scaledCoverArt(const QPixmap& normal); + private slots: + void slotAboutToCompose(); + void slotFrameSwapped(); + private: + void render(); + QString m_group; UserSettingsPointer m_pConfig; std::shared_ptr m_pBgImage; @@ -136,6 +141,12 @@ class WSpinny : public QGLWidget, public WBaseWidget, public VinylSignalQualityL 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