summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Cooksey <thomas.cooksey@nokia.com>2009-07-23 15:03:24 (GMT)
committerTom Cooksey <thomas.cooksey@nokia.com>2009-07-23 15:03:24 (GMT)
commit140ce8705f47a65bac32e804421b63d0c7b97d7d (patch)
tree5dfafd1cfe2d489ac2edd771e46385a4a7a748a1
parenta2d64535d011a47cb2bdf91002f9210cf6b656b1 (diff)
downloadQt-140ce8705f47a65bac32e804421b63d0c7b97d7d.zip
Qt-140ce8705f47a65bac32e804421b63d0c7b97d7d.tar.gz
Qt-140ce8705f47a65bac32e804421b63d0c7b97d7d.tar.bz2
Initial stab at a custom shader stage API
-rw-r--r--src/gui/painting/qpaintengine.h1
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp143
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h30
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp6
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h4
-rw-r--r--src/opengl/opengl.pro6
6 files changed, 134 insertions, 56 deletions
diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h
index 57c9e2d..5298b6a 100644
--- a/src/gui/painting/qpaintengine.h
+++ b/src/gui/painting/qpaintengine.h
@@ -210,6 +210,7 @@ public:
Direct3D,
Pdf,
OpenVG,
+ OpenGL2,
User = 50, // first user type id
MaxUser = 100 // last user type id
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index d7c91b8..327a699 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -308,6 +308,37 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
shaderProgNeedsChanging = true; //###
}
+void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
+{
+ customSrcStage = stage;
+ shaderProgNeedsChanging = true;
+}
+
+void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
+{
+ Q_UNUSED(stage); // Currently we only support one at a time...
+
+ QGLShader* compiledShader = compiledShaders[CustomImageSrcFragmentShader];
+
+ if (!compiledShader)
+ return;
+
+ // Remove any shader programs which has this as the srcPixel shader:
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg &prog = cachedPrograms[i];
+ if (prog.srcPixelFragShader == compiledShader) {
+ delete prog.program;
+ cachedPrograms.removeOne(prog);
+ break;
+ }
+ }
+
+ delete compiledShader;
+ compiledShaders[CustomImageSrcFragmentShader] = 0;
+ shaderProgNeedsChanging = true;
+}
+
+
QGLShaderProgram* QGLEngineShaderManager::currentProgram()
{
return currentShaderProg->program;
@@ -332,6 +363,12 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
if (!shaderProgNeedsChanging)
return false;
+ bool useCustomSrc = customSrcStage != 0;
+ if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc) {
+ useCustomSrc = false;
+ qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
+ }
+
QGLEngineShaderProg requiredProgram;
requiredProgram.program = 0;
@@ -363,7 +400,11 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set");
break;
case QGLEngineShaderManager::ImageSrc:
- srcPixelFragShaderName = ImageSrcFragmentShader;
+ srcPixelFragShaderName = useCustomSrc ? CustomImageSrcFragmentShader : ImageSrcFragmentShader;
+ positionVertexShaderName = PositionOnlyVertexShader;
+ break;
+ case QGLEngineShaderManager::NonPremultipliedImageSrc:
+ srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader;
positionVertexShaderName = PositionOnlyVertexShader;
break;
case QGLEngineShaderManager::PatternSrc:
@@ -375,10 +416,6 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader
: PositionWithTextureBrushVertexShader;
break;
- case QGLEngineShaderManager::NonPremultipliedImageSrc:
- srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
- break;
case Qt::SolidPattern:
srcPixelFragShaderName = SolidBrushSrcFragmentShader;
positionVertexShaderName = PositionOnlyVertexShader;
@@ -500,60 +537,63 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
// At this point, requiredProgram is fully populated so try to find the program in the cache
+ bool foundProgramInCache = false;
for (int i = 0; i < cachedPrograms.size(); ++i) {
- QGLEngineShaderProg &prog = cachedPrograms[i];
- if ( (prog.mainVertexShader == requiredProgram.mainVertexShader)
- && (prog.positionVertexShader == requiredProgram.positionVertexShader)
- && (prog.mainFragShader == requiredProgram.mainFragShader)
- && (prog.srcPixelFragShader == requiredProgram.srcPixelFragShader)
- && (prog.compositionFragShader == requiredProgram.compositionFragShader) )
- {
- currentShaderProg = &prog;
- currentShaderProg->program->enable();
- shaderProgNeedsChanging = false;
- return true;
+ if (cachedPrograms[i] == requiredProgram) {
+ currentShaderProg = &cachedPrograms[i];
+ foundProgramInCache = true;
+ break;
}
}
- // Shader program not found in cache, create it now.
- requiredProgram.program = new QGLShaderProgram(ctx, this);
- requiredProgram.program->addShader(requiredProgram.mainVertexShader);
- requiredProgram.program->addShader(requiredProgram.positionVertexShader);
- requiredProgram.program->addShader(requiredProgram.mainFragShader);
- requiredProgram.program->addShader(requiredProgram.srcPixelFragShader);
- requiredProgram.program->addShader(requiredProgram.maskFragShader);
- requiredProgram.program->addShader(requiredProgram.compositionFragShader);
-
- // We have to bind the vertex attribute names before the program is linked:
- requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- if (useTextureCoords)
- requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
-
- requiredProgram.program->link();
- if (!requiredProgram.program->isLinked()) {
- QString error;
- qWarning() << "Shader program failed to link,"
+ // If the shader program's not found in the cache, create it now.
+ while (!foundProgramInCache) {
+ requiredProgram.program = new QGLShaderProgram(ctx, this);
+ requiredProgram.program->addShader(requiredProgram.mainVertexShader);
+ requiredProgram.program->addShader(requiredProgram.positionVertexShader);
+ requiredProgram.program->addShader(requiredProgram.mainFragShader);
+ requiredProgram.program->addShader(requiredProgram.srcPixelFragShader);
+ requiredProgram.program->addShader(requiredProgram.maskFragShader);
+ requiredProgram.program->addShader(requiredProgram.compositionFragShader);
+
+ // We have to bind the vertex attribute names before the program is linked:
+ requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ if (useTextureCoords)
+ requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ requiredProgram.program->link();
+ if (!requiredProgram.program->isLinked()) {
+ QString error;
+ qWarning() << "Shader program failed to link,"
#if defined(QT_DEBUG)
- << '\n'
- << " Shaders Used:" << '\n'
- << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n'
- << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n'
- << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n'
- << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n'
- << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n'
- << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n'
+ << '\n'
+ << " Shaders Used:" << '\n'
+ << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n'
+ << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n'
+ << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n'
+ << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n'
+ << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n'
+ << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n'
#endif
- << " Error Log:" << '\n'
- << " " << requiredProgram.program->log();
- qWarning() << error;
- }
- else {
+ << " Error Log:" << '\n'
+ << " " << requiredProgram.program->log();
+ qWarning() << error;
+ delete requiredProgram.program;
+ break;
+ }
+
cachedPrograms.append(requiredProgram);
// taking the address here is safe since
// cachePrograms isn't resized anywhere else
currentShaderProg = &cachedPrograms.last();
+ }
+
+ if (currentShaderProg) {
currentShaderProg->program->enable();
+ if (useCustomSrc)
+ customSrcStage->setUniforms(currentShaderProg->program);
}
+
shaderProgNeedsChanging = false;
return true;
}
@@ -564,7 +604,14 @@ void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderNa
return;
QGLShader *newShader = new QGLShader(type, ctx, this);
- newShader->compile(qglEngineShaderSourceCode[name]);
+
+ const char* sourceCode;
+ if (name == CustomImageSrcFragmentShader)
+ sourceCode = customSrcStage->source();
+ else
+ sourceCode = qglEngineShaderSourceCode[name];
+
+ newShader->compile(sourceCode);
#if defined(QT_DEBUG)
// Name the shader for easier debugging
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 99711bd40..15082c3 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -205,12 +205,16 @@
The use of custom shader code is supported by the engine for drawImage and
drawPixmap calls. This is implemented via hooks in the fragment pipeline.
The custom shader is passed to the engine as a partial fragment shader
- (QGLCustomizedShader). The shader will implement a pre-defined method name
- which Qt's fragment pipeline will call. There are two different hooks which
- can be implemented as custom shader code:
+ (QGLCustomShaderStage). The shader will implement a pre-defined method name
+ which Qt's fragment pipeline will call:
- mediump vec4 customShader(sampler2d src, vec2 srcCoords)
- mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords)
+ lowp vec4 customShader()
+
+ Depending on the custom type, the custom shader has a small API it can use
+ to read pixels. The basic custom type is for image/pixmap drawing and thus
+ can use the following to sample the src texture (non-premultiplied)
+
+ lowp vec4 QSampleSrcPixel(mediump vec2 coords)
*/
@@ -221,6 +225,7 @@
#include <QGLShaderProgram>
#include <QPainter>
#include <private/qgl_p.h>
+#include <private/qglcustomshaderstage_p.h>
QT_BEGIN_HEADER
@@ -240,6 +245,17 @@ struct QGLEngineShaderProg
QGLShaderProgram* program;
QVector<uint> uniformLocations;
+
+ bool operator==(const QGLEngineShaderProg& other) {
+ // We don't care about the program
+ return ( mainVertexShader == other.mainVertexShader &&
+ positionVertexShader == other.positionVertexShader &&
+ mainFragShader == other.mainFragShader &&
+ srcPixelFragShader == other.srcPixelFragShader &&
+ maskFragShader == other.maskFragShader &&
+ compositionFragShader == other.compositionFragShader
+ );
+ }
};
/*
@@ -305,6 +321,8 @@ public:
void setUseGlobalOpacity(bool);
void setMaskType(MaskType);
void setCompositionMode(QPainter::CompositionMode);
+ void setCustomStage(QGLCustomShaderStage* stage);
+ void removeCustomStage(QGLCustomShaderStage* stage);
uint getUniformLocation(Uniform id);
@@ -346,6 +364,7 @@ public:
ImageSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
+ CustomImageSrcFragmentShader,
SolidBrushSrcFragmentShader,
TextureBrushSrcFragmentShader,
TextureBrushSrcWithPatternFragmentShader,
@@ -401,6 +420,7 @@ private:
MaskType maskType;
bool useTextureCoords;
QPainter::CompositionMode compositionMode;
+ QGLCustomShaderStage* customSrcStage;
QGLShaderProgram* blitShaderProg;
QGLShaderProgram* simpleShaderProg;
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 167eb64..b04c7e6 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -690,6 +690,12 @@ void QGL2PaintEngineEx::sync()
d->needsSync = true;
}
+const QGLContext *QGL2PaintEngineEx::context()
+{
+ Q_D(QGL2PaintEngineEx);
+ return d->ctx;
+}
+
void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
{
if (newMode == mode)
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index ec447a3..21c296d 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -121,7 +121,7 @@ public:
Qt::ImageConversionFlags flags = Qt::AutoColor);
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
- Type type() const { return OpenGL; }
+ Type type() const { return OpenGL2; }
void setState(QPainterState *s);
QPainterState *createState(QPainterState *orig) const;
@@ -133,10 +133,12 @@ public:
}
virtual void sync();
+ const QGLContext* context();
private:
Q_DISABLE_COPY(QGL2PaintEngineEx)
};
+
class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
{
Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index c92b8cf..5a76cb1 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -44,7 +44,8 @@ SOURCES += qgl.cpp \
gl2paintengineex/qglengineshadermanager_p.h \
gl2paintengineex/qgl2pexvertexarray_p.h \
gl2paintengineex/qpaintengineex_opengl2_p.h \
- gl2paintengineex/qglengineshadersource_p.h
+ gl2paintengineex/qglengineshadersource_p.h \
+ gl2paintengineex/qglcustomshaderstage_p.h
SOURCES += qglshaderprogram.cpp \
qglpixmapfilter.cpp \
@@ -54,7 +55,8 @@ SOURCES += qgl.cpp \
gl2paintengineex/qglgradientcache.cpp \
gl2paintengineex/qglengineshadermanager.cpp \
gl2paintengineex/qgl2pexvertexarray.cpp \
- gl2paintengineex/qpaintengineex_opengl2.cpp
+ gl2paintengineex/qpaintengineex_opengl2.cpp \
+ gl2paintengineex/qglcustomshaderstage.cpp
}