Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UI performance with QOpenGLWidget. #1974

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
650114d
Replace usage of deprecated QGLWidget with QOpenGLWidget.
sgielen Oct 22, 2018
893596b
Merge branch 'master' into qopenglwidget
rryan Dec 27, 2018
a4cdf99
Merge remote-tracking branch 'mixxxdj/master' into qopenglwidget2
rryan Jan 3, 2019
ad89986
Merge remote-tracking branch 'mixxxdj/master' into qopenglwidget2
rryan Feb 9, 2019
e6e2305
Fix method collision between WaveformWidgetAbstract and QOpenGLWidget.
rryan Dec 28, 2018
eb7b2b1
Fix more QGLWidget references that were added in 2.2.
rryan Dec 28, 2018
fe011ae
Remove WSpinny "No OpenGL" fallback.
rryan Dec 28, 2018
793af64
Migrate GLSLWaveformRendererSignal to QtOpenGL.
rryan Dec 29, 2018
6f0d70d
Remove checks that QWidget::windowHandle()->isExposed() for QtOpenGLW…
rryan Dec 29, 2018
00b8e7c
Remove setAutoBufferSwap.
rryan Dec 29, 2018
1fcc1b5
Replace QGLFormat::setDefaultFormat with QSurfaceFormat::setDefaultFo…
rryan Dec 29, 2018
95933b1
Update OpenGL version detection to use QSurfaceFormat.
rryan Dec 29, 2018
569a99f
Call QOpenGLWidget::resizeEvent from WSpinny::resizeEvent.
rryan Jan 3, 2019
0d78720
Restructure the flow of rendering QOpenGLWidgets.
rryan Dec 31, 2018
a1a8857
Render widgets immediately via WaveformWidgetAbstract::renderOnNextTick.
rryan Feb 9, 2019
98bd81e
Rename VSyncThread to RenderThread and delete some unused code.
rryan Feb 10, 2019
05f5fb2
Use Qt 5-style connect function.
rryan Feb 11, 2019
d4bdd92
Disable the broken FormatKiloSeconds test.
rryan Feb 11, 2019
76f9b1f
Merge remote-tracking branch 'upstream/master' into qopenglwidget
daschuer Feb 21, 2019
4de038f
Fix and improve the OpenGL status info
daschuer Feb 23, 2019
bd90b75
Merge branch 'star-co' of https://github.com/ronso0/mixxx into qopeng…
daschuer Feb 24, 2019
319d5fd
Merge pull request #15 from daschuer/qopenglwidget
rryan Apr 12, 2020
35a11cc
Merge branch 'master' into qopenglwidget
rryan Apr 13, 2020
d9e434c
Update CMakeLists.txt to include added/removed files.
rryan Apr 13, 2020
c6ad608
Remove unused header inclusion.
rryan Apr 13, 2020
2876411
Use a range-based for loop.
rryan Apr 13, 2020
f4500ac
Rename getAtNextSwap to getPlayPositionAtNextSwap to be more explicit.
rryan Apr 13, 2020
99f6e5b
Fix mistakes made when merging.
rryan Apr 13, 2020
a1cc05d
No need to guard QWidget::update() with isVisible(), since update doe…
rryan Apr 13, 2020
1e5cafb
Clarify and update some comments. Remove commented debugging printlines.
rryan Apr 13, 2020
53f6e16
Restore QOpenGLWidget::makeCurrent() calls in constructors.
rryan Apr 13, 2020
120976f
Move all OpenGL work out of constructors.
rryan Apr 13, 2020
8644fc6
Revert "Restore QOpenGLWidget::makeCurrent() calls in constructors."
rryan Apr 13, 2020
ea9f91d
Rework WaveformWidgetFactory initialization so that it has access to …
rryan Apr 13, 2020
ada2b2a
Fix the Windows build with Qt 5.14.2.
JosepMaJAZ Apr 13, 2020
6860728
Attempt to fix the AppVeyor build when mkdir fails due to %ENVIRONMEN…
rryan Apr 13, 2020
44b2030
Use setFrameRate to set the configured FPS in WaveformWidgetFactory::…
rryan Apr 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Be-ing marked this conversation as resolved.
Show resolved Hide resolved
MSVC_PATH: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community"
PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%'

Expand Down
8 changes: 5 additions & 3 deletions build/appveyor/build_mixxx.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions build/depends.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 1 addition & 2 deletions res/shaders/passthrough.vert
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//#version 100
#version 120

void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

2 changes: 2 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <X11/Xlib.h>
Expand Down Expand Up @@ -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
Expand Down
44 changes: 10 additions & 34 deletions src/mixxx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include <QStandardPaths>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QGLWidget>
#include <QUrl>
#include <QtDebug>
#include <QLocale>
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -96,6 +94,8 @@
// with references to std::max and std::min
#undef max
#undef min
#elif defined(Q_OS_WINDOWS)
#include <QtPlatformHeaders/QWindowsWindowFunctions>
#endif

namespace {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);

Expand Down
9 changes: 4 additions & 5 deletions src/skin/legacyskinparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/test/durationutiltest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,5 @@ TEST_F(DurationUtilTest, FormatKiloSeconds) {
}



} // anonymous namespace
2 changes: 1 addition & 1 deletion src/waveform/guitick.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
78 changes: 32 additions & 46 deletions src/waveform/renderers/glslwaveformrenderersignal.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "waveform/renderers/glslwaveformrenderersignal.h"
#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)

#include <QGLFramebufferObject>
#include <QOpenGLFramebufferObject>

#include "waveform/renderers/waveformwidgetrenderer.h"
#include "waveform/waveform.h"
Expand All @@ -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() {
Expand All @@ -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<QOpenGLShaderProgram>();

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;
}

Expand Down Expand Up @@ -170,36 +161,28 @@ 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.
const int oversamplingFactor = 4;
const int bufferWidth = oversamplingFactor * m_waveformRenderer->getWidth() * devicePixelRatio;
const int bufferHeight = oversamplingFactor * m_waveformRenderer->getHeight() * devicePixelRatio;

m_framebuffer = std::make_unique<QGLFramebufferObject>(bufferWidth,
bufferHeight);
auto framebuffer = std::make_unique<QOpenGLFramebufferObject>(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<QGLShaderProgram>();
}

if (!loadShaders()) {
return false;
}
createGeometry();
if (!loadTexture()) {
return false;
}

return true;
}

Expand Down Expand Up @@ -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;
}

Expand Down
19 changes: 9 additions & 10 deletions src/waveform/renderers/glslwaveformrenderersignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
#include <QOpenGLFunctions_2_1>
#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)

#include <QGLFramebufferObject>
#include <QGLShaderProgram>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QtOpenGL>

#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,
Expand Down Expand Up @@ -45,17 +45,16 @@ class GLSLWaveformRendererSignal: public QObject,
int m_textureRenderedWaveformCompletion;

// Frame buffer for two pass rendering.
std::unique_ptr<QGLFramebufferObject> m_framebuffer;
std::unique_ptr<QOpenGLFramebufferObject> m_framebuffer;

bool m_bDumpPng;

// shaders
bool m_shadersValid;
bool m_rgbShader;
std::unique_ptr<QGLShaderProgram> m_frameShaderProgram;
const bool m_rgbShader;
std::unique_ptr<QOpenGLShaderProgram> m_frameShaderProgram;
};

class GLSLWaveformRendererFilteredSignal: public GLSLWaveformRendererSignal {
class GLSLWaveformRendererFilteredSignal : public GLSLWaveformRendererSignal {
public:
GLSLWaveformRendererFilteredSignal(
WaveformWidgetRenderer* waveformWidgetRenderer) :
Expand Down
Loading