From b63e0069a18e9d49a8c961d5fa27325c527507a1 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 17 Aug 2016 13:30:12 +0300 Subject: Fix antialiasing support of OpenGL accelerated series MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenGL accelerated series are now antialiased similarly to non-accelerated series. Task-number: QTRD-2172 Change-Id: Ie8bc014c82d5fa645cf41ab56bebb99fcf8ad301 Reviewed-by: Mika Salmela Reviewed-by: Tomi Korpipää Reviewed-by: Miikka Heikkinen --- .../qml/qmloscilloscope/ControlPanel.qml | 2 +- .../qmloscilloscope/qml/qmloscilloscope/main.qml | 2 - src/charts/chartpresenter.cpp | 5 +++ src/charts/glwidget.cpp | 17 ++++++-- src/charts/glwidget_p.h | 7 ++- src/charts/qabstractseries.cpp | 2 - src/chartsqml2/declarativeabstractrendernode.h | 1 + src/chartsqml2/declarativechart.cpp | 2 + src/chartsqml2/declarativeopenglrendernode.cpp | 51 +++++++++++++++++----- src/chartsqml2/declarativeopenglrendernode.h | 3 ++ tests/manual/openglseriestest/mainwindow.cpp | 7 +++ tests/manual/openglseriestest/mainwindow.h | 1 + tests/manual/openglseriestest/mainwindow.ui | 16 +++++++ 13 files changed, 94 insertions(+), 22 deletions(-) diff --git a/examples/charts/qmloscilloscope/qml/qmloscilloscope/ControlPanel.qml b/examples/charts/qmloscilloscope/qml/qmloscilloscope/ControlPanel.qml index 19277a09..fe3bc869 100644 --- a/examples/charts/qmloscilloscope/qml/qmloscilloscope/ControlPanel.qml +++ b/examples/charts/qmloscilloscope/qml/qmloscilloscope/ControlPanel.qml @@ -96,7 +96,7 @@ ColumnLayout { id: antialiasButton text: "Antialias: " items: ["OFF", "ON"] - enabled: false + enabled: true currentSelection: 0 onSelectionChanged: antialiasingEnabled(currentSelection == 1); } diff --git a/examples/charts/qmloscilloscope/qml/qmloscilloscope/main.qml b/examples/charts/qmloscilloscope/qml/qmloscilloscope/main.qml index 7c6b2cd7..a8260564 100644 --- a/examples/charts/qmloscilloscope/qml/qmloscilloscope/main.qml +++ b/examples/charts/qmloscilloscope/qml/qmloscilloscope/main.qml @@ -56,8 +56,6 @@ Item { onAntialiasingEnabled: scopeView.antialiasing = enabled; onOpenGlChanged: { scopeView.openGL = enabled; - antialiasButton.enabled = !enabled; - antialiasButton.currentSelection = 0; } } diff --git a/src/charts/chartpresenter.cpp b/src/charts/chartpresenter.cpp index e6d38db7..d9b1f03d 100644 --- a/src/charts/chartpresenter.cpp +++ b/src/charts/chartpresenter.cpp @@ -562,6 +562,11 @@ void ChartPresenter::updateGLWidget() #ifndef QT_NO_OPENGL // GLWidget pointer is wrapped in QPointer as its parent is not in our control, and therefore // can potentially get deleted unexpectedly. + if (!m_glWidget.isNull() && m_glWidget->needsReset()) { + m_glWidget->hide(); + delete m_glWidget.data(); + m_glWidget.clear(); + } if (m_glWidget.isNull() && m_glUseWidget && m_chart->scene()) { // Find the view of the scene. If the scene has multiple views, only the first view is // chosen. diff --git a/src/charts/glwidget.cpp b/src/charts/glwidget.cpp index c0070dcd..ea2734fc 100644 --- a/src/charts/glwidget.cpp +++ b/src/charts/glwidget.cpp @@ -42,7 +42,7 @@ QT_CHARTS_BEGIN_NAMESPACE -GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent) +GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QGraphicsView *parent) : QOpenGLWidget(parent), m_program(0), m_shaderAttribLoc(-1), @@ -50,7 +50,9 @@ GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent) m_minUniformLoc(-1), m_deltaUniformLoc(-1), m_pointSizeUniformLoc(-1), - m_xyDataManager(xyDataManager) + m_xyDataManager(xyDataManager), + m_antiAlias(parent->renderHints().testFlag(QPainter::Antialiasing)), + m_view(parent) { setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_AlwaysStackOnTop); @@ -65,6 +67,7 @@ GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent) surfaceFormat.setAlphaBufferSize(8); surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); surfaceFormat.setRenderableType(QSurfaceFormat::DefaultRenderableType); + surfaceFormat.setSamples(m_antiAlias ? 4 : 0); setFormat(surfaceFormat); connect(xyDataManager, &GLXYSeriesDataManager::seriesRemoved, @@ -182,14 +185,15 @@ void GLWidget::paintGL() m_program->setUniformValue(m_minUniformLoc, data->min); m_program->setUniformValue(m_deltaUniformLoc, data->delta); m_program->setUniformValue(m_matrixUniformLoc, data->matrix); - + bool dirty = data->dirty; if (!vbo) { vbo = new QOpenGLBuffer; m_seriesBufferMap.insert(i.key(), vbo); vbo->create(); + dirty = true; } vbo->bind(); - if (data->dirty) { + if (dirty) { vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat)); data->dirty = false; } @@ -231,6 +235,11 @@ void GLWidget::resizeGL(int w, int h) Q_UNUSED(h) } +bool GLWidget::needsReset() const +{ + return m_view->renderHints().testFlag(QPainter::Antialiasing) != m_antiAlias; +} + QT_CHARTS_END_NAMESPACE #endif diff --git a/src/charts/glwidget_p.h b/src/charts/glwidget_p.h index 024e096a..1ec0fd3d 100644 --- a/src/charts/glwidget_p.h +++ b/src/charts/glwidget_p.h @@ -42,6 +42,7 @@ #ifndef QT_NO_OPENGL #include +#include #include #include #include @@ -60,9 +61,11 @@ class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions Q_OBJECT public: - GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent = 0); + GLWidget(GLXYSeriesDataManager *xyDataManager, QGraphicsView *parent = 0); ~GLWidget(); + bool needsReset() const; + public Q_SLOTS: void cleanup(); void cleanXYSeriesResources(const QXYSeries *series); @@ -84,6 +87,8 @@ private: QHash m_seriesBufferMap; GLXYSeriesDataManager *m_xyDataManager; + bool m_antiAlias; + QGraphicsView *m_view; }; QT_CHARTS_END_NAMESPACE diff --git a/src/charts/qabstractseries.cpp b/src/charts/qabstractseries.cpp index b5c7d8a7..f35bef08 100644 --- a/src/charts/qabstractseries.cpp +++ b/src/charts/qabstractseries.cpp @@ -168,7 +168,6 @@ QT_CHARTS_BEGIN_NAMESPACE \list \li Series animations are not supported for accelerated series. - \li Antialiasing is not supported for accelerated series. \li Point labels are not supported for accelerated series. \li Pen styles and marker shapes are ignored for accelerated series. Only solid lines and plain scatter dots are supported. @@ -224,7 +223,6 @@ QT_CHARTS_BEGIN_NAMESPACE \list \li Series animations are not supported for accelerated series. - \li Antialiasing is not supported for accelerated series. \li Point labels are not supported for accelerated series. \li Marker shapes are ignored for accelerated series. Only plain scatter dots are supported. diff --git a/src/chartsqml2/declarativeabstractrendernode.h b/src/chartsqml2/declarativeabstractrendernode.h index afc8c354..554445ba 100644 --- a/src/chartsqml2/declarativeabstractrendernode.h +++ b/src/chartsqml2/declarativeabstractrendernode.h @@ -46,6 +46,7 @@ public: virtual QSize textureSize() const = 0; virtual void setRect(const QRectF &rect) = 0; virtual void setSeriesData(bool mapDirty, const GLXYDataMap &dataMap) = 0; + virtual void setAntialiasing(bool enable) = 0; }; diff --git a/src/chartsqml2/declarativechart.cpp b/src/chartsqml2/declarativechart.cpp index 4dfc3d5d..4600f655 100644 --- a/src/chartsqml2/declarativechart.cpp +++ b/src/chartsqml2/declarativechart.cpp @@ -549,6 +549,7 @@ QSGNode *DeclarativeChart::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdateP node->renderNode()->setRect(adjustedPlotArea); node->renderNode()->setSeriesData(m_glXYDataManager->mapDirty(), m_glXYDataManager->dataMap()); + node->renderNode()->setAntialiasing(antialiasing()); // Clear dirty flags from original xy data m_glXYDataManager->clearAllDirty(); @@ -720,6 +721,7 @@ void DeclarativeChart::mouseDoubleClickEvent(QMouseEvent *event) void DeclarativeChart::handleAntialiasingChanged(bool enable) { setAntialiasing(enable); + emit needRender(); } void DeclarativeChart::setTheme(DeclarativeChart::Theme theme) diff --git a/src/chartsqml2/declarativeopenglrendernode.cpp b/src/chartsqml2/declarativeopenglrendernode.cpp index 0799e36c..9b07a912 100644 --- a/src/chartsqml2/declarativeopenglrendernode.cpp +++ b/src/chartsqml2/declarativeopenglrendernode.cpp @@ -47,20 +47,22 @@ QT_CHARTS_BEGIN_NAMESPACE // It is used as a child node of the chart node. DeclarativeOpenGLRenderNode::DeclarativeOpenGLRenderNode(QQuickWindow *window) : QObject(), - m_texture(0), + m_texture(nullptr), m_imageNode(nullptr), m_window(window), m_textureOptions(QQuickWindow::TextureHasAlphaChannel), m_textureSize(1, 1), m_recreateFbo(false), - m_fbo(0), - m_program(0), + m_fbo(nullptr), + m_resolvedFbo(nullptr), + m_program(nullptr), m_shaderAttribLoc(-1), m_colorUniformLoc(-1), m_minUniformLoc(-1), m_deltaUniformLoc(-1), m_pointSizeUniformLoc(-1), - m_renderNeeded(true) + m_renderNeeded(true), + m_antialiasing(false) { initializeOpenGLFunctions(); @@ -70,13 +72,12 @@ DeclarativeOpenGLRenderNode::DeclarativeOpenGLRenderNode(QQuickWindow *window) : DeclarativeOpenGLRenderNode::~DeclarativeOpenGLRenderNode() { + cleanXYSeriesResources(0); + delete m_texture; delete m_fbo; - + delete m_resolvedFbo; delete m_program; - m_program = 0; - - cleanXYSeriesResources(0); } static const char *vertexSource = @@ -138,13 +139,25 @@ void DeclarativeOpenGLRenderNode::recreateFBO() { QOpenGLFramebufferObjectFormat fboFormat; fboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment); + + int samples = 0; + QOpenGLContext *context = QOpenGLContext::currentContext(); + + if (m_antialiasing && (!context->isOpenGLES() || context->format().majorVersion() >= 3)) + samples = 4; + fboFormat.setSamples(samples); + delete m_fbo; - m_fbo = new QOpenGLFramebufferObject(m_textureSize.width(), - m_textureSize.height(), - fboFormat); + delete m_resolvedFbo; + m_resolvedFbo = nullptr; + + m_fbo = new QOpenGLFramebufferObject(m_textureSize, fboFormat); + if (samples > 0) + m_resolvedFbo = new QOpenGLFramebufferObject(m_textureSize); delete m_texture; - m_texture = m_window->createTextureFromId(m_fbo->texture(), m_textureSize, m_textureOptions); + uint textureId = m_resolvedFbo ? m_resolvedFbo->texture() : m_fbo->texture(); + m_texture = m_window->createTextureFromId(textureId, m_textureSize, m_textureOptions); if (!m_imageNode) { m_imageNode = m_window->createImageNode(); m_imageNode->setFiltering(QSGTexture::Linear); @@ -218,6 +231,15 @@ void DeclarativeOpenGLRenderNode::setRect(const QRectF &rect) m_imageNode->setRect(rect); } +void DeclarativeOpenGLRenderNode::setAntialiasing(bool enable) +{ + if (m_antialiasing != enable) { + m_antialiasing = enable; + m_recreateFbo = true; + m_renderNeeded = true; + } +} + void DeclarativeOpenGLRenderNode::renderGL() { glClearColor(0, 0, 0, 0); @@ -281,6 +303,11 @@ void DeclarativeOpenGLRenderNode::renderGL() } #endif + if (m_resolvedFbo) { + QRect rect(QPoint(0, 0), m_fbo->size()); + QOpenGLFramebufferObject::blitFramebuffer(m_resolvedFbo, rect, m_fbo, rect); + } + markDirty(DirtyMaterial); m_window->resetOpenGLState(); } diff --git a/src/chartsqml2/declarativeopenglrendernode.h b/src/chartsqml2/declarativeopenglrendernode.h index 09ce64c6..f058fd3f 100644 --- a/src/chartsqml2/declarativeopenglrendernode.h +++ b/src/chartsqml2/declarativeopenglrendernode.h @@ -57,6 +57,7 @@ public: void setSeriesData(bool mapDirty, const GLXYDataMap &dataMap) override; void setRect(const QRectF &rect) override; + void setAntialiasing(bool enable) override; public Q_SLOTS: void render(); @@ -74,6 +75,7 @@ private: bool m_recreateFbo; GLXYDataMap m_xyDataMap; QOpenGLFramebufferObject *m_fbo; + QOpenGLFramebufferObject *m_resolvedFbo; QOpenGLShaderProgram *m_program; int m_shaderAttribLoc; int m_colorUniformLoc; @@ -85,6 +87,7 @@ private: QHash m_seriesBufferMap; bool m_renderNeeded; QRectF m_rect; + bool m_antialiasing; }; QT_CHARTS_END_NAMESPACE diff --git a/tests/manual/openglseriestest/mainwindow.cpp b/tests/manual/openglseriestest/mainwindow.cpp index e653e483..8b20c7e8 100644 --- a/tests/manual/openglseriestest/mainwindow.cpp +++ b/tests/manual/openglseriestest/mainwindow.cpp @@ -104,6 +104,8 @@ MainWindow::MainWindow(QWidget *parent) : this, SLOT(colorIndexChanged(int))); connect(ui->widthComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(widthIndexChanged(int))); + connect(ui->antiAliasCheckBox, SIGNAL(clicked(bool)), + this, SLOT(antiAliasCheckBoxClicked(bool))); ui->chartView->setChart(m_chart); ui->chartView->setRenderHint(QPainter::Antialiasing); @@ -419,6 +421,11 @@ void MainWindow::widthIndexChanged(int index) } } +void MainWindow::antiAliasCheckBoxClicked(bool checked) +{ + ui->chartView->setRenderHint(QPainter::Antialiasing, checked); +} + void MainWindow::backgroundIndexChanged(int index) { delete m_backgroundBrush; diff --git a/tests/manual/openglseriestest/mainwindow.h b/tests/manual/openglseriestest/mainwindow.h index 6ad297f3..8590fea3 100644 --- a/tests/manual/openglseriestest/mainwindow.h +++ b/tests/manual/openglseriestest/mainwindow.h @@ -73,6 +73,7 @@ public slots: void countIndexChanged(int index); void colorIndexChanged(int index); void widthIndexChanged(int index); + void antiAliasCheckBoxClicked(bool checked); private: enum AxisMode { diff --git a/tests/manual/openglseriestest/mainwindow.ui b/tests/manual/openglseriestest/mainwindow.ui index e5ca1514..ac52ff7f 100644 --- a/tests/manual/openglseriestest/mainwindow.ui +++ b/tests/manual/openglseriestest/mainwindow.ui @@ -545,6 +545,22 @@ + + + + 10 + 370 + 91 + 17 + + + + Antialiasing + + + true + + -- cgit v1.2.3