summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp35
-rw-r--r--src/gui/opengl/qopengltexturecache.cpp31
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp110
3 files changed, 172 insertions, 4 deletions
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 0c05b61e76..16094804c2 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -104,10 +104,18 @@ QT_BEGIN_NAMESPACE
#define GL_RGB8 0x8051
#endif
+#ifndef GL_RGB10
+#define GL_RGB10 0x8052
+#endif
+
#ifndef GL_RGBA8
#define GL_RGBA8 0x8058
#endif
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -116,6 +124,10 @@ QT_BEGIN_NAMESPACE
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#endif
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+
/*!
\class QOpenGLFramebufferObjectFormat
@@ -539,8 +551,12 @@ void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal
funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ GLuint pixelType = GL_UNSIGNED_BYTE;
+ if (internal_format == GL_RGB10_A2 || internal_format == GL_RGB10)
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+
funcs.glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ GL_RGBA, pixelType, NULL);
if (mipmap) {
int width = size.width();
int height = size.height();
@@ -550,7 +566,7 @@ void QOpenGLFramebufferObjectPrivate::initTexture(GLenum target, GLenum internal
height = qMax(1, height >> 1);
++level;
funcs.glTexImage2D(target, level, internal_format, width, height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ GL_RGBA, pixelType, NULL);
}
}
funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -1142,6 +1158,14 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
return rgbaImage;
}
+static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool include_alpha, QOpenGLContext *context)
+{
+ // We assume OpenGL 1.2+ or ES 3.0+ here.
+ QImage img(size, include_alpha ? QImage::Format_A2BGR30_Premultiplied : QImage::Format_BGR30);
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits());
+ return img;
+}
+
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@@ -1152,6 +1176,10 @@ static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format,
case GL_RGB:
case GL_RGB8:
return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip);
+ case GL_RGB10:
+ return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
+ case GL_RGB10_A2:
+ return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGBA:
case GL_RGBA8:
default:
@@ -1177,7 +1205,8 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
of QOpenGLPaintDevice::paintFlipped().
Will try to return a premultiplied ARBG32 or RGB32 image. Since 5.2 it will fall back to
- a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported.
+ a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported. Since 5.4 an
+ A2BGR30 image is returned if the internal format is RGB10_A2.
For multisampled framebuffer objects the samples are resolved using the
\c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents
diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp
index 4a4a36d7e5..055974d5a4 100644
--- a/src/gui/opengl/qopengltexturecache.cpp
+++ b/src/gui/opengl/qopengltexturecache.cpp
@@ -49,6 +49,10 @@
QT_BEGIN_NAMESPACE
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
#ifndef GL_BGR
#define GL_BGR 0x80E0
#endif
@@ -61,6 +65,10 @@ QT_BEGIN_NAMESPACE
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#endif
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+
class QOpenGLTextureCacheWrapper
{
public:
@@ -228,6 +236,29 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, con
}
targetFormat = image.format();
break;
+ case QImage::Format_BGR30:
+ case QImage::Format_A2BGR30_Premultiplied:
+ if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_RGB30:
+ case QImage::Format_A2RGB30_Premultiplied:
+ if (isOpenGL12orBetter) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() && context->format().majorVersion() >= 3) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = QImage::Format_A2BGR30_Premultiplied;
+ }
+ break;
case QImage::Format_RGB444:
case QImage::Format_RGB555:
case QImage::Format_RGB16:
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 972c2a7ea4..6d83defdeb 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -43,6 +43,7 @@
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLFunctions_4_2_Core>
#include <QtGui/QOpenGLVertexArrayObject>
#include <QtGui/QOpenGLPaintDevice>
#include <QtGui/QPainter>
@@ -88,6 +89,8 @@ private slots:
void fboTextureOwnership();
void fboRendering_data();
void fboRendering();
+ void fboRenderingRGB30_data();
+ void fboRenderingRGB30();
void fboHandleNulledAfterContextDestroyed();
void openGLPaintDevice_data();
void openGLPaintDevice();
@@ -563,7 +566,7 @@ void tst_QOpenGL::fboRendering()
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- // Uncomplicate things by using NPOT:
+ // Uncomplicate things by using POT:
const QSize size(256, 128);
QOpenGLFramebufferObject fbo(size, fboFormat);
@@ -587,6 +590,111 @@ void tst_QOpenGL::fboRendering()
qt_opengl_check_test_pattern(fb);
}
+void tst_QOpenGL::fboRenderingRGB30_data()
+{
+ common_data();
+}
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
+#ifndef GL_FRAMEBUFFER_RENDERABLE
+#define GL_FRAMEBUFFER_RENDERABLE 0x8289
+#endif
+
+#ifndef GL_FULL_SUPPORT
+#define GL_FULL_SUPPORT 0x82B7
+#endif
+
+void tst_QOpenGL::fboRenderingRGB30()
+{
+#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
+ QSKIP("QTBUG-22617");
+#endif
+
+ QFETCH(int, surfaceClass);
+ QScopedPointer<QSurface> surface(createSurface(surfaceClass));
+
+ QOpenGLContext ctx;
+ QVERIFY(ctx.create());
+
+ QVERIFY(ctx.makeCurrent(surface.data()));
+
+ if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QOpenGLFramebufferObject not supported on this platform");
+
+ if (ctx.format().majorVersion() < 3)
+ QSKIP("An internal RGB30_A2 format is not guaranteed on this platform");
+
+#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)
+ // NVidia currently only supports RGB30 and RGB30_A2 in their Quadro drivers,
+ // but they do provide an extension for querying the support. We use the query
+ // in case they implement the required formats later.
+ if (!ctx.isOpenGLES() && ctx.format().majorVersion() >= 4) {
+ GLint value = -1;
+ QOpenGLFunctions_4_2_Core* vFuncs = ctx.versionFunctions<QOpenGLFunctions_4_2_Core>();
+ if (vFuncs && vFuncs->initializeOpenGLFunctions()) {
+ vFuncs->glGetInternalformativ(GL_TEXTURE_2D, GL_RGB10_A2, GL_FRAMEBUFFER_RENDERABLE, 1, &value);
+ if (value != GL_FULL_SUPPORT)
+ QSKIP("The required RGB30_A2 format is not supported by this driver");
+ }
+ }
+#endif
+
+ // No multisample with combined depth/stencil attachment:
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fboFormat.setInternalTextureFormat(GL_RGB10_A2);
+
+ // Uncomplicate things by using POT:
+ const QSize size(256, 128);
+ QOpenGLFramebufferObject fbo(size, fboFormat);
+
+ if (fbo.attachment() != QOpenGLFramebufferObject::CombinedDepthStencil)
+ QSKIP("FBOs missing combined depth~stencil support");
+
+ QVERIFY(fbo.bind());
+
+ QPainter fboPainter;
+ QOpenGLPaintDevice device(fbo.width(), fbo.height());
+ bool painterBegun = fboPainter.begin(&device);
+ QVERIFY(painterBegun);
+
+ qt_opengl_draw_test_pattern(&fboPainter, fbo.width(), fbo.height());
+
+ fboPainter.end();
+
+ QImage fb = fbo.toImage();
+ QCOMPARE(fb.format(), QImage::Format_A2BGR30_Premultiplied);
+ QCOMPARE(fb.size(), size);
+
+ qt_opengl_check_test_pattern(fb);
+
+ // Check rendering can handle color values below 1/256.
+ fboPainter.begin(&device);
+ fboPainter.fillRect(QRect(0, 0, 256, 128), QColor::fromRgbF(1.0/512, 1.0/512, 1.0/512));
+ fboPainter.end();
+ fb = fbo.toImage();
+ uint pixel = ((uint*)fb.bits())[0];
+ QVERIFY((pixel & 0x3f) > 0);
+ QVERIFY(((pixel >> 10) & 0x3f) > 0);
+ QVERIFY(((pixel >> 20) & 0x3f) > 0);
+
+ pixel = (3U << 30) | (2U << 20) | (2U << 10) | 2U;
+ fb.fill(pixel);
+
+ fboPainter.begin(&device);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ fboPainter.drawImage(0, 0, fb);
+ fboPainter.end();
+ fb = fbo.toImage();
+ pixel = ((uint*)fb.bits())[0];
+ QVERIFY((pixel & 0x3f) > 0);
+ QVERIFY(((pixel >> 10) & 0x3f) > 0);
+ QVERIFY(((pixel >> 20) & 0x3f) > 0);
+}
+
void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
{
QWindow window;