summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-08-04 11:47:11 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2014-10-27 11:54:39 +0100
commit5adbb9cc576546c42249099e549f1947cca54610 (patch)
tree0454a5e9ff21651fe4bc1fac6ab7424914d53a3e
parentda72e5538ebcc7e6008d0c4b3538d2a994f02a7e (diff)
Support Alpha8 and Grayscale8 natively in the OpenGL paint engine
Adds special shaders for the Alpha8 and Grayscale8 formats so that they do not need to rely on the support of GL_ALPHA and GL_LUMINANCE that has been removed from core in recent OpenGL versions. Change-Id: Ie370379b458abf2a50e252bc5099aefc1b11fb1d Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
-rw-r--r--src/gui/opengl/qopenglengineshadermanager.cpp12
-rw-r--r--src/gui/opengl/qopenglengineshadermanager_p.h6
-rw-r--r--src/gui/opengl/qopenglengineshadersource_p.h16
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp5
-rw-r--r--src/gui/opengl/qopenglfunctions.h3
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp14
-rw-r--r--src/gui/opengl/qopengltexturecache.cpp25
-rw-r--r--src/gui/opengl/qopengltexturecache_p.h1
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp64
9 files changed, 139 insertions, 7 deletions
diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp
index 5bdb2f35ac..93425b0b3a 100644
--- a/src/gui/opengl/qopenglengineshadermanager.cpp
+++ b/src/gui/opengl/qopenglengineshadermanager.cpp
@@ -154,6 +154,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader;
code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader;
code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader;
+ code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader;
+ code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader;
code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader;
if (context->isOpenGLES())
@@ -700,6 +702,16 @@ bool QOpenGLEngineShaderManager::useCorrectShaderProg()
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
texCoords = true;
break;
+ case QOpenGLEngineShaderManager::GrayscaleImageSrc:
+ requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::GrayscaleImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
+ case QOpenGLEngineShaderManager::AlphaImageSrc:
+ requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::AlphaImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
case QOpenGLEngineShaderManager::PatternSrc:
requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader;
diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h
index 2ae0ae0866..56aa18cb6b 100644
--- a/src/gui/opengl/qopenglengineshadermanager_p.h
+++ b/src/gui/opengl/qopenglengineshadermanager_p.h
@@ -288,6 +288,8 @@ public:
ImageSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
+ GrayscaleImageSrcFragmentShader,
+ AlphaImageSrcFragmentShader,
CustomImageSrcFragmentShader,
SolidBrushSrcFragmentShader,
TextureBrushSrcFragmentShader,
@@ -414,7 +416,9 @@ public:
ImageSrc = Qt::TexturePattern+1,
NonPremultipliedImageSrc = Qt::TexturePattern+2,
PatternSrc = Qt::TexturePattern+3,
- TextureSrcWithPattern = Qt::TexturePattern+4
+ TextureSrcWithPattern = Qt::TexturePattern+4,
+ GrayscaleImageSrc = Qt::TexturePattern+5,
+ AlphaImageSrc = Qt::TexturePattern+6,
};
enum Uniform {
diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h
index bc81fe4c77..acda09a8ee 100644
--- a/src/gui/opengl/qopenglengineshadersource_p.h
+++ b/src/gui/opengl/qopenglengineshadersource_p.h
@@ -367,6 +367,22 @@ static const char* const qopenglslNonPremultipliedImageSrcFragmentShader = "\n\
return sample; \n\
}\n";
+static const char* const qopenglslGrayscaleImageSrcFragmentShader = "\n\
+ varying highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return texture2D(imageTexture, textureCoords).rrra; \n\
+ }\n";
+
+static const char* const qopenglslAlphaImageSrcFragmentShader = "\n\
+ varying highp vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ lowp vec4 srcPixel() \n\
+ { \n\
+ return vec4(0, 0, 0, texture2D(imageTexture, textureCoords).r); \n\
+ }\n";
+
static const char* const qopenglslShockingPinkSrcFragmentShader = "\n\
lowp vec4 srcPixel() \n\
{ \n\
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index 44b56699df..67b978a570 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -173,6 +173,7 @@ QT_BEGIN_NAMESPACE
\value NPOTTextures Non power of two textures are available.
\value NPOTTextureRepeat Non power of two textures can use GL_REPEAT as wrap parameter.
\value FixedFunctionPipeline The fixed function pipeline is available.
+ \value TextureRGFormats The GL_RED and GL_RG texture formats are available.
*/
// Hidden private fields for additional extension data.
@@ -284,10 +285,12 @@ static int qt_gl_resolve_features()
if (extensions.match("GL_OES_texture_npot"))
features |= QOpenGLFunctions::NPOTTextures |
QOpenGLFunctions::NPOTTextureRepeat;
+ if (ctx->format().majorVersion() >= 3 || extensions.match("GL_EXT_texture_rg"))
+ features |= QOpenGLFunctions::TextureRGFormats;
return features;
} else {
// OpenGL
- int features = 0;
+ int features = QOpenGLFunctions::TextureRGFormats;
QSurfaceFormat format = QOpenGLContext::currentContext()->format();
QOpenGLExtensionMatcher extensions;
diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h
index 479a280abe..85d255fe61 100644
--- a/src/gui/opengl/qopenglfunctions.h
+++ b/src/gui/opengl/qopenglfunctions.h
@@ -240,7 +240,8 @@ public:
StencilSeparate = 0x0800,
NPOTTextures = 0x1000,
NPOTTextureRepeat = 0x2000,
- FixedFunctionPipeline = 0x4000
+ FixedFunctionPipeline = 0x4000,
+ TextureRGFormats = 0x8000
};
Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature)
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index c490726359..299d3da73d 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -1421,6 +1421,20 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc);
bindOption = 0;
break;
+ case QImage::Format_Alpha8:
+ if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
+ d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc);
+ bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ } else
+ d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
+ break;
+ case QImage::Format_Grayscale8:
+ if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
+ d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc);
+ bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ } else
+ d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
+ break;
default:
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
break;
diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp
index 5ac5eb94b6..f85a26cd6e 100644
--- a/src/gui/opengl/qopengltexturecache.cpp
+++ b/src/gui/opengl/qopengltexturecache.cpp
@@ -41,6 +41,10 @@
QT_BEGIN_NAMESPACE
+#ifndef GL_RED
+#define GL_RED 0x1903
+#endif
+
#ifndef GL_RGB10_A2
#define GL_RGB10_A2 0x8059
#endif
@@ -273,21 +277,34 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, con
pixelType = GL_UNSIGNED_BYTE;
targetFormat = image.format();
break;
+ case QImage::Format_Indexed8:
+ if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
case QImage::Format_Alpha8:
- if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
externalFormat = internalFormat = GL_ALPHA;
pixelType = GL_UNSIGNED_BYTE;
targetFormat = image.format();
}
- // ### add support for core profiles.
break;
case QImage::Format_Grayscale8:
- if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
externalFormat = internalFormat = GL_LUMINANCE;
pixelType = GL_UNSIGNED_BYTE;
targetFormat = image.format();
}
- // ### add support for core profiles.
break;
default:
break;
diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h
index f856054a85..45dc20e146 100644
--- a/src/gui/opengl/qopengltexturecache_p.h
+++ b/src/gui/opengl/qopengltexturecache_p.h
@@ -78,6 +78,7 @@ public:
enum BindOption {
NoBindOption = 0x0000,
PremultipliedAlphaBindOption = 0x0001,
+ UseRedFor8BitBindOption = 0x0002,
};
Q_DECLARE_FLAGS(BindOptions, BindOption)
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 89ad66c1e8..a8834563a1 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -98,6 +98,8 @@ private slots:
void textureblitterPartTargetRectTransform();
void defaultSurfaceFormat();
+ void imageFormatPainting();
+
#ifdef USE_GLX
void glxContextWrap();
#endif
@@ -718,6 +720,68 @@ void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
QCOMPARE(fbo->handle(), 0U);
}
+void tst_QOpenGL::imageFormatPainting()
+{
+ QScopedPointer<QSurface> surface(createSurface(QSurface::Window));
+
+ QOpenGLContext ctx;
+ QVERIFY(ctx.create());
+
+ QVERIFY(ctx.makeCurrent(surface.data()));
+
+ if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QOpenGLFramebufferObject not supported on this platform");
+
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+
+ const QSize size(128, 128);
+ QOpenGLFramebufferObject fbo(size, fboFormat);
+
+ if (fbo.attachment() != QOpenGLFramebufferObject::CombinedDepthStencil)
+ QSKIP("FBOs missing combined depth~stencil support");
+
+ QVERIFY(fbo.bind());
+
+ QImage alpha(128, 128, QImage::Format_Alpha8);
+ alpha.fill(127);
+
+ QPainter fboPainter;
+ QOpenGLPaintDevice device(fbo.width(), fbo.height());
+
+ QVERIFY(fboPainter.begin(&device));
+ fboPainter.fillRect(0, 0, 128, 128, qRgb(255, 0, 255));
+ fboPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ fboPainter.drawImage(0, 0, alpha);
+ fboPainter.end();
+
+ QImage fb = fbo.toImage();
+ QCOMPARE(fb.pixel(0, 0), qRgba(127, 0, 127, 127));
+
+ QImage grayscale(128, 128, QImage::Format_Grayscale8);
+ grayscale.fill(128);
+
+ QVERIFY(fboPainter.begin(&device));
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Plus);
+ fboPainter.drawImage(0, 0, grayscale);
+ fboPainter.end();
+
+ fb = fbo.toImage();
+ QCOMPARE(fb.pixel(0, 0), qRgb(255, 128, 255));
+
+ QImage argb(128, 128, QImage::Format_ARGB32);
+ argb.fill(qRgba(255, 255, 255, 128));
+
+ QVERIFY(fboPainter.begin(&device));
+ fboPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ fboPainter.drawImage(0, 0, argb);
+ fboPainter.end();
+
+ fb = fbo.toImage();
+ QCOMPARE(fb.pixel(0, 0), qRgb(255, 192, 255));
+
+}
+
void tst_QOpenGL::openGLPaintDevice_data()
{
QTest::addColumn<int>("surfaceClass");