From 2485575f1883fe990d0072eed2231a5bd06948af Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Fri, 3 Apr 2009 14:30:25 +0200 Subject: Add (big) comment explaining shader pipeline in GL2 engine Reviewed-by: TrustMe --- src/opengl/gl2paintengineex/glgc_shader_source.h | 138 +++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/opengl/gl2paintengineex/glgc_shader_source.h b/src/opengl/gl2paintengineex/glgc_shader_source.h index 5b9d28b..47a1cbb 100644 --- a/src/opengl/gl2paintengineex/glgc_shader_source.h +++ b/src/opengl/gl2paintengineex/glgc_shader_source.h @@ -48,6 +48,144 @@ QT_BEGIN_NAMESPACE QT_MODULE(OpenGL) + +/* + VERTEX SHADERS + ============== + + Vertex shaders are specified as multiple (partial) shaders. On desktop, + this works fine. On ES, QGLShader & QGLShaderProgram will make partial + shaders work by concatenating the source in each QGLShader and compiling + it as a single shader. This is abstracted nicely by QGLShaderProgram and + the GL2 engine doesn't need to worry about it. + + Generally, there's two vertex shader objects. The position shaders are + the ones which set gl_Position. There's also two "main" vertex shaders, + one which just calls the position shader and another which also passes + through some texture coordinates from a vertex attribute array to a + varying. These texture coordinates are used for mask position in text + rendering and for the source coordinates in drawImage/drawPixmap. There's + also a "Simple" vertex shader for rendering a solid colour (used to render + into the stencil buffer where the actual colour value is discarded). + + The position shaders for brushes look scary. This is because many of the + calculations which logically belong in the fragment shader have been moved + into the vertex shader to improve performance. This is why the position + calculation is in a seperate shader. Not only does it calculate the + position, but it also calculates some data to be passed to the fragment + shader as a varying. It is optimal to move as much of the calculation as + possible into the vertex shader as this is executed less often. + + The varyings passed to the fragment shaders are interpolated (which is + cheap). Unfortunately, GL will apply perspective correction to the + interpolation calusing errors. To get around this, the vertex shader must + apply perspective correction itself and set the w-value of gl_Position to + zero. That way, GL will be tricked into thinking it doesn't need to apply a + perspective correction and use linear interpolation instead (which is what + we want). Of course, if the brush transform is affeine, no perspective + correction is needed and a simpler vertex shader can be used instead. + + So there are the following "main" vertex shaders: + qglslSimpleVertexShader + qglslMainVertexShader + qglslMainWithTexCoordsVertexShader + + And the the following position vertex shaders: + qglslPositionOnlyVertexShader + qglslPositionWithTextureBrushVertexShader + qglslPositionWithPatternBrushVertexShader + qglslPositionWithLinearGradientBrushVertexShader + qglslPositionWithRadialGradientBrushVertexShader + qglslPositionWithConicalGradientBrushVertexShader + qglslAffinePositionWithTextureBrushVertexShader + qglslAffinePositionWithPatternBrushVertexShader + qglslAffinePositionWithLinearGradientBrushVertexShader + qglslAffinePositionWithRadialGradientBrushVertexShader + qglslAffinePositionWithConicalGradientBrushVertexShader + + Leading to 23 possible vertex shaders + + + FRAGMENT SHADERS + ================ + + Fragment shaders are also specified as multiple (partial) shaders. The + different fragment shaders represent the different stages in Qt's fragment + pipeline. There are 1-3 stages in this pipeline: First stage is to get the + fragment's colour value. The next stage is to get the fragment's mask value + (coverage value for anti-aliasing) and the final stage is to blend the + incoming fragment with the background (for composition modes not supported + by GL). + + Of these, the first stage will always be present. If Qt doesn't need to + apply anti-aliasing (because it's off or handled by multisampling) then + the coverage value doesn't need to be applied. (Note: There are two types + of mask, one for regular anti-aliasing and one for sub-pixel anti- + aliasing.) If the composition mode is one which GL supports natively then + the blending stage doesn't need to be applied. + + As eash stage can have multiple implementations, they are abstracted as + GLSL function calls, with the following signatures: + + Brushes & image drawing are implementations of "mediump vec4 srcPixel()": + qglslImageFragmentShader + qglslNonPremultipliedImageFragmentShader + qglslSolidBrushFragmentShader + qglslTextureBrushFragmentShader + qglslPatternBrushFragmentShader + qglslLinearGradientBrushFragmentShader + qglslRadialGradientBrushFragmentShader + qglslConicalGradientBrushFragmentShader + + NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied + + The two masks are have these signature and are called: + qglslMaskFragmentShader: "mediump float mask()" + qglslRgbMaskFragmentShader: "mediump vec3 rgbMask()" + + Composition modes are "mediump vec4 composite(mediump vec4 src, mediump vec4 dest)": + qglslColorBurnCompositionModeFragmentShader + qglslColorDodgeCompositionModeFragmentShader + qglslDarkenCompositionModeFragmentShader + qglslDifferenceCompositionModeFragmentShader + qglslExclusionCompositionModeFragmentShader + qglslHardLightCompositionModeFragmentShader + qglslLightenCompositionModeFragmentShader + qglslMultiplyCompositionModeFragmentShader + qglslOverlayCompositionModeFragmentShader + qglslScreenCompositionModeFragmentShader + qglslSoftLightCompositionModeFragmentShader + + + So there are differnt frament shader main functions, depending on the + number & type of pipelines the fragment needs to go through. + + The choice of which main() fragment shader string to use depends on: + - Use of global opacity + - Brush style (some brushes apply opacity themselves) + - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) + - Use of gamma-correction + - Use of non-GL Composition mode + + + CUSTOM SHADER CODE (idea) + ================== + + 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: + + mediump vec4 customShader(sampler2d src, vec2 srcCoords) + mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords) + +*/ + +///////////////////////////////////////////////////////////////////// + + static const char* qglslImageVertexShader = "\ attribute highp vec4 inputVertex; \ attribute lowp vec2 textureCoord; \ -- cgit v0.12