summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-06-01 11:44:37 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-06-01 13:38:14 +0000
commit78e335408303380310dd59fab421e495cf517ead (patch)
tree2c76bdaccd566792a23e766569043fc2800b2c2c
parent069be1654359ab93f89d339775795508d106153a (diff)
Clip QOpenGLWidget and QQuickWidget correctly
Introduce support for the widgets' clipRect(). Right now render-to-texture widgets in scroll areas placed close to each other result in broken (non-existent) clipping. Similarly, stack-on-top widgets fail to clip when placed inside a scroll area. This is now corrected and the qopenglwidget example is enhanced to utilize a scroll area. Task-number: QTBUG-45860 Change-Id: I859a63d61a50d64ba9e87244f83c5969dce12337 Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
-rw-r--r--examples/opengl/qopenglwidget/glwidget.cpp6
-rw-r--r--examples/opengl/qopenglwidget/mainwindow.cpp20
-rw-r--r--examples/opengl/qopenglwidget/mainwindow.h2
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp59
-rw-r--r--src/gui/painting/qplatformbackingstore.h4
-rw-r--r--src/platformsupport/platformcompositor/qopenglcompositor.cpp31
-rw-r--r--src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp3
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp3
8 files changed, 99 insertions, 29 deletions
diff --git a/examples/opengl/qopenglwidget/glwidget.cpp b/examples/opengl/qopenglwidget/glwidget.cpp
index f93e667615..df52e3efbf 100644
--- a/examples/opengl/qopenglwidget/glwidget.cpp
+++ b/examples/opengl/qopenglwidget/glwidget.cpp
@@ -537,14 +537,14 @@ void GLWidget::setTransparent(bool transparent)
window()->update();
}
-void GLWidget::resizeGL(int w, int h)
+void GLWidget::resizeGL(int, int)
{
if (m_hasButton) {
if (!m_btn) {
- m_btn = new QPushButton("A widget on top.\nPress me!", this);
+ m_btn = new QPushButton("A widget on top.\nPress for more widgets.", this);
connect(m_btn, &QPushButton::clicked, this, &GLWidget::handleButtonPress);
}
- m_btn->move(w / 2, h / 2);
+ m_btn->move(20, 80);
}
}
diff --git a/examples/opengl/qopenglwidget/mainwindow.cpp b/examples/opengl/qopenglwidget/mainwindow.cpp
index 6cf1d5d6e2..22111afdcb 100644
--- a/examples/opengl/qopenglwidget/mainwindow.cpp
+++ b/examples/opengl/qopenglwidget/mainwindow.cpp
@@ -47,6 +47,7 @@
#include <QLabel>
#include <QCheckBox>
#include <QSpinBox>
+#include <QScrollArea>
#include "glwidget.h"
@@ -69,7 +70,7 @@ MainWindow::MainWindow()
"and therefore an interval < 16 ms will likely lead to a 60 FPS update rate.");
QGroupBox *updateGroupBox = new QGroupBox(this);
QCheckBox *timerBased = new QCheckBox("Use timer", this);
- timerBased->setChecked(true);
+ timerBased->setChecked(false);
timerBased->setToolTip("Toggles using a timer to trigger update().\n"
"When not set, each paintGL() schedules the next update immediately,\n"
"expecting the blocking swap to throttle the thread.\n"
@@ -87,7 +88,7 @@ MainWindow::MainWindow()
slider->setRange(0, 50);
slider->setSliderPosition(30);
m_timer->setInterval(10);
- label->setText("A QOpenGLWidget");
+ label->setText("A scrollable QOpenGLWidget");
label->setAlignment(Qt::AlignHCenter);
QGroupBox * groupBox = new QGroupBox(this);
@@ -96,7 +97,10 @@ MainWindow::MainWindow()
m_layout = new QGridLayout(groupBox);
- m_layout->addWidget(glwidget,1,0,8,1);
+ QScrollArea *scrollArea = new QScrollArea;
+ scrollArea->setWidget(glwidget);
+
+ m_layout->addWidget(scrollArea,1,0,8,1);
m_layout->addWidget(label,9,0,1,1);
m_layout->addWidget(updateGroupBox, 10, 0, 1, 1);
m_layout->addWidget(slider, 11,0,1,1);
@@ -134,7 +138,10 @@ MainWindow::MainWindow()
connect(timerBased, &QCheckBox::toggled, this, &MainWindow::timerUsageChanged);
connect(timerBased, &QCheckBox::toggled, updateInterval, &QWidget::setEnabled);
- m_timer->start();
+ if (timerBased->isChecked())
+ m_timer->start();
+ else
+ updateInterval->setEnabled(false);
}
void MainWindow::updateIntervalChanged(int value)
@@ -170,3 +177,8 @@ void MainWindow::timerUsageChanged(bool enabled)
w->update();
}
}
+
+void MainWindow::resizeEvent(QResizeEvent *)
+{
+ m_glWidgets[0]->setMinimumSize(size() + QSize(128, 128));
+}
diff --git a/examples/opengl/qopenglwidget/mainwindow.h b/examples/opengl/qopenglwidget/mainwindow.h
index f1b2c51e53..9ad8a01339 100644
--- a/examples/opengl/qopenglwidget/mainwindow.h
+++ b/examples/opengl/qopenglwidget/mainwindow.h
@@ -56,6 +56,8 @@ public:
void addNew();
bool timerEnabled() const { return m_timer->isActive(); }
+ void resizeEvent(QResizeEvent *);
+
private slots:
void updateIntervalChanged(int value);
void timerUsageChanged(bool enabled);
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 14a9429c71..83077f38ca 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -86,6 +86,7 @@ struct QBackingstoreTextureInfo
QWidget *widget; // may be null
GLuint textureId;
QRect rect;
+ QRect clipRect;
QPlatformTextureList::Flags flags;
};
@@ -142,6 +143,12 @@ QRect QPlatformTextureList::geometry(int index) const
return d->textures.at(index).rect;
}
+QRect QPlatformTextureList::clipRect(int index) const
+{
+ Q_D(const QPlatformTextureList);
+ return d->textures.at(index).clipRect;
+}
+
void QPlatformTextureList::lock(bool on)
{
Q_D(QPlatformTextureList);
@@ -157,13 +164,15 @@ bool QPlatformTextureList::isLocked() const
return d->locked;
}
-void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags)
+void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry,
+ const QRect &clipRect, Flags flags)
{
Q_D(QPlatformTextureList);
QBackingstoreTextureInfo bi;
bi.widget = widget;
bi.textureId = textureId;
bi.rect = geometry;
+ bi.clipRect = clipRect;
bi.flags = flags;
d->textures.append(bi);
}
@@ -198,7 +207,7 @@ void QPlatformTextureList::clear()
#ifndef QT_NO_OPENGL
-static QRect deviceRect(const QRect &rect, QWindow *window)
+static inline QRect deviceRect(const QRect &rect, QWindow *window)
{
QRect deviceRect(rect.topLeft() * window->devicePixelRatio(),
rect.size() * window->devicePixelRatio());
@@ -219,6 +228,32 @@ static QRegion deviceRegion(const QRegion &region, QWindow *window)
return deviceRegion;
}
+static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
+{
+ return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
+ topLeftRect.width(), topLeftRect.height());
+}
+
+static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect,
+ QOpenGLTextureBlitter *blitter)
+{
+ const QRect rectInWindow = textures->geometry(idx);
+ QRect clipRect = textures->clipRect(idx);
+ if (clipRect.isEmpty())
+ clipRect = QRect(QPoint(0, 0), rectInWindow.size());
+ const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
+ const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
+
+ const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window),
+ deviceWindowRect);
+
+ const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window),
+ deviceRect(rectInWindow, window).size(),
+ QOpenGLTextureBlitter::OriginBottomLeft);
+
+ blitter->blit(textures->textureId(idx), target, source);
+}
+
/*!
Flushes the given \a region from the specified \a window onto the
screen, and composes it with the specified \a textures.
@@ -254,15 +289,12 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
d_ptr->blitter->bind();
- QRect windowRect(QPoint(), window->size() * window->devicePixelRatio());
+ const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
// Textures for renderToTexture widgets.
for (int i = 0; i < textures->count(); ++i) {
- if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
- QRect targetRect = deviceRect(textures->geometry(i), window);
- QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect);
- d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft);
- }
+ if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
+ blit(textures, i, window, deviceWindowRect, d_ptr->blitter);
}
funcs->glEnable(GL_BLEND);
@@ -272,6 +304,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
// semi-transparency even when it is not wanted.
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
+ // Backingstore texture with the normal widgets.
GLuint textureId = 0;
QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) {
@@ -307,7 +340,6 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
origin = QOpenGLTextureBlitter::OriginBottomLeft;
textureId = d_ptr->textureId;
} else {
- // Backingstore texture with the normal widgets.
TextureFlags flags = 0;
textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &flags);
d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0;
@@ -316,7 +348,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
}
if (textureId) {
- QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), windowRect);
+ QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), deviceWindowRect);
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(true);
d_ptr->blitter->blit(textureId, target, origin);
@@ -326,11 +358,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
for (int i = 0; i < textures->count(); ++i) {
- if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
- QRect targetRect = deviceRect(textures->geometry(i), window);
- QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect);
- d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft);
- }
+ if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
+ blit(textures, i, window, deviceWindowRect, d_ptr->blitter);
}
funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index ae7314b6d0..5fa7e6dac0 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -82,12 +82,14 @@ public:
bool isEmpty() const { return count() == 0; }
GLuint textureId(int index) const;
QRect geometry(int index) const;
+ QRect clipRect(int index) const;
QWidget *widget(int index);
Flags flags(int index) const;
void lock(bool on);
bool isLocked() const;
- void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0);
+ void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry,
+ const QRect &clipRect = QRect(), Flags flags = 0);
void clear();
Q_SIGNALS:
diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp
index 3fd6c999a2..2e386532e2 100644
--- a/src/platformsupport/platformcompositor/qopenglcompositor.cpp
+++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp
@@ -169,6 +169,29 @@ struct BlendStateBinder
bool m_blend;
};
+static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
+{
+ return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
+ topLeftRect.width(), topLeftRect.height());
+}
+
+static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter)
+{
+ const QRect rectInWindow = textures->geometry(idx);
+ QRect clipRect = textures->clipRect(idx);
+ if (clipRect.isEmpty())
+ clipRect = QRect(QPoint(0, 0), rectInWindow.size());
+
+ const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
+ const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
+
+ const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(clippedRectInWindow, targetWindowRect);
+ const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(),
+ QOpenGLTextureBlitter::OriginBottomLeft);
+
+ blitter->blit(textures->textureId(idx), target, source);
+}
+
void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
{
const QPlatformTextureList *textures = window->textures();
@@ -181,7 +204,6 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
for (int i = 0; i < textures->count(); ++i) {
uint textureId = textures->textureId(i);
- QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
const float opacity = window->sourceWindow()->opacity();
if (opacity != currentOpacity) {
currentOpacity = opacity;
@@ -191,24 +213,25 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
if (textures->count() > 1 && i == textures->count() - 1) {
// Backingstore for a widget with QOpenGLWidget subwidgets
blend.set(true);
+ const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
} else if (textures->count() == 1) {
// A regular QWidget window
const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
blend.set(translucent);
+ const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
} else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
// Texture from an FBO belonging to a QOpenGLWidget
blend.set(false);
- m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
+ clippedBlit(textures, i, targetWindowRect, &m_blitter);
}
}
for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
- QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
blend.set(true);
- m_blitter.blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft);
+ clippedBlit(textures, i, targetWindowRect, &m_blitter);
}
}
diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
index 3caec468a6..4cf64e61da 100644
--- a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
+++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp
@@ -175,7 +175,8 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi
m_textures->clear();
for (int i = 0; i < textures->count(); ++i)
- m_textures->appendTexture(textures->widget(i), textures->textureId(i), textures->geometry(i), textures->flags(i));
+ m_textures->appendTexture(textures->widget(i), textures->textureId(i), textures->geometry(i),
+ textures->clipRect(i), textures->flags(i));
updateTexture();
m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry());
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index 485cf82078..5752317924 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -962,7 +962,8 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatfo
QPlatformTextureList::Flags flags = 0;
if (widget->testAttribute(Qt::WA_AlwaysStackOnTop))
flags |= QPlatformTextureList::StacksOnTop;
- widgetTextures->appendTexture(widget, wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), flags);
+ const QRect rect(widget->mapTo(tlw, QPoint()), widget->size());
+ widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags);
}
for (int i = 0; i < wd->children.size(); ++i) {