Add support for custom texture format in QOpenGLWidget

...in order to support sRGB framebuffers.

Add a --srgb option to the qopenglwidget example to allow testing.

[ChangeLog][QtWidgets][QOpenGLWidget] Added support for specifying
custom internal texture formats in QOpenGLWidget in order to make it
possible to have the widget backed by an sRGB-capable framebuffer.

Task-number: QTBUG-50987
Change-Id: I112e2f0ab0b1478c69e601031aa0bafaa87fa847
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2017-02-20 15:19:49 +01:00
parent 931e4ae665
commit 5bb4d06494
5 changed files with 64 additions and 3 deletions

View File

@ -61,6 +61,10 @@
const int bubbleNum = 8;
#ifndef GL_SRGB8_ALPHA8
#define GL_SRGB8_ALPHA8 0x8C43
#endif
GLWidget::GLWidget(MainWindow *mw, bool button, const QColor &background)
: m_mainWindow(mw),
m_showBubbles(true),
@ -75,6 +79,8 @@ GLWidget::GLWidget(MainWindow *mw, bool button, const QColor &background)
m_background(background)
{
setMinimumSize(300, 250);
if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
setTextureFormat(GL_SRGB8_ALPHA8);
}
GLWidget::~GLWidget()

View File

@ -61,6 +61,8 @@ int main( int argc, char ** argv )
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
if (QCoreApplication::arguments().contains(QStringLiteral("--srgb")))
format.setColorSpace(QSurfaceFormat::sRGBColorSpace);
if (QCoreApplication::arguments().contains(QStringLiteral("--multisample")))
format.setSamples(4);
QSurfaceFormat::setDefaultFormat(format);

View File

@ -566,7 +566,8 @@ public:
paintDevice(0),
updateBehavior(QOpenGLWidget::NoPartialUpdate),
requestedSamples(0),
inPaintGL(false)
inPaintGL(false),
textureFormat(0)
{
requestedFormat = QSurfaceFormat::defaultFormat();
}
@ -610,6 +611,7 @@ public:
QOpenGLWidget::UpdateBehavior updateBehavior;
int requestedSamples;
bool inPaintGL;
GLenum textureFormat;
};
void QOpenGLWidgetPaintDevicePrivate::beginPaint()
@ -703,12 +705,16 @@ void QOpenGLWidgetPrivate::recreateFbo()
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setSamples(samples);
if (textureFormat)
format.setInternalTextureFormat(textureFormat);
const QSize deviceSize = q->size() * q->devicePixelRatioF();
fbo = new QOpenGLFramebufferObject(deviceSize, format);
if (samples > 0)
resolvedFbo = new QOpenGLFramebufferObject(deviceSize);
textureFormat = fbo->format().internalTextureFormat();
fbo->bind();
context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@ -767,7 +773,9 @@ void QOpenGLWidgetPrivate::initialize()
return;
}
// Propagate settings that make sense only for the tlw.
// Propagate settings that make sense only for the tlw. Note that this only
// makes sense for properties that get picked up even after the native
// window is created.
QSurfaceFormat tlwFormat = tlw->windowHandle()->format();
if (requestedFormat.swapInterval() != tlwFormat.swapInterval()) {
// Most platforms will pick up the changed swap interval on the next
@ -990,7 +998,6 @@ QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const
*/
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
{
Q_UNUSED(format);
Q_D(QOpenGLWidget);
if (Q_UNLIKELY(d->initialized)) {
qWarning("QOpenGLWidget: Already initialized, setting the format has no effect");
@ -1022,6 +1029,47 @@ QSurfaceFormat QOpenGLWidget::format() const
return d->initialized ? d->context->format() : d->requestedFormat;
}
/*!
Sets a custom internal texture format.
When working with sRGB framebuffers, it will be necessary to specify a
format like \c{GL_SRGB8_ALPHA8}. This can be achieved by calling this
function.
\note This function has no effect if called after the widget has already
been shown and thus it performed initialization.
\note This function will typically have to be used in combination with a
QSurfaceFormat::setDefaultFormat() call that sets the color space to
QSurfaceFormat::sRGBColorSpace.
\since 5.10
*/
void QOpenGLWidget::setTextureFormat(GLenum texFormat)
{
Q_D(QOpenGLWidget);
if (Q_UNLIKELY(d->initialized)) {
qWarning("QOpenGLWidget: Already initialized, setting the internal texture format has no effect");
return;
}
d->textureFormat = texFormat;
}
/*!
\return the active internal texture format if the widget has already
initialized, the requested format if one was set but the widget has not yet
been made visible, or 0 if setTextureFormat() was not called and the widget
has not yet been made visible.
\since 5.10
*/
GLenum QOpenGLWidget::textureFormat() const
{
Q_D(const QOpenGLWidget);
return d->textureFormat;
}
/*!
\return \e true if the widget and OpenGL resources, like the context, have
been successfully initialized. Note that the return value is always false

View File

@ -72,6 +72,9 @@ public:
void setFormat(const QSurfaceFormat &format);
QSurfaceFormat format() const;
GLenum textureFormat() const;
void setTextureFormat(GLenum texFormat);
bool isValid() const;
void makeCurrent();

View File

@ -64,6 +64,7 @@ void tst_QOpenGLWidget::create()
{
QScopedPointer<QOpenGLWidget> w(new QOpenGLWidget);
QVERIFY(!w->isValid());
QVERIFY(w->textureFormat() == 0);
QSignalSpy frameSwappedSpy(w.data(), SIGNAL(frameSwapped()));
w->show();
QTest::qWaitForWindowExposed(w.data());
@ -73,6 +74,7 @@ void tst_QOpenGLWidget::create()
QVERIFY(w->context());
QCOMPARE(w->context()->format(), w->format());
QVERIFY(w->defaultFramebufferObject() != 0);
QVERIFY(w->textureFormat() != 0);
}
class ClearWidget : public QOpenGLWidget, protected QOpenGLFunctions