23/03/2010 OpenGL 4.0 review(ClickForSource :-) )
OpenGL 4.0 is the new specification for GeForce GTX 4** and Radeon HD 5*** hardware: aka Direct3D 11 hardware level. In this review we go through all the new features and explore their details.Tessellation.
OpenGL 4.0 brings 3 new processing stages that take place between the vertex shader and geometry shader.
- Control shader (Known as Hull shader in Direct3D 11)
- Primitive generator
- Evaluation shader (Known as Domain shader in Direct3D 11)
In a way, the tessellation stages replace the vertex shader stage in the graphics pipeline. Most of the vertex shader tasks will be dispatched in the control shader and the evaluation shader. So far, the vertex shader stage is still required but the control shader and the evaluation shader are both optional.
Control shaders work on 'patches', a set of vertices. Their output per-vertex data and per-patch data used by the primitive generator and available as read only in the evaluation shader. Input per-vertex data are stored in an array called 'gl_in' which maximum size is gl_MaxPatchVertives. The elements of gl_in contain the variables gl_Position, gl_PointSize, gl_ClipDistance and gl_ClipVertex. The per-patch variables are gl_PatchVerticesIn (number of vertices in the patch), gl_PrimitiveID (number of primitives of the draw call) and gl_InvocationID (Invocation number).
The control shaders have a gl_out array of per-vertex data which members are gl_Position, gl_PointSize and gl_ClipDistance. They also output per-patch data with the variables gl_TessLevelOuter and gl_Tesslevel Inner to control the tesselation level.
A control shader is invoked several times, one by vertex of a patch and each invocation is identified by gl_InvocationID. These invocations can be synchronised by the built-in function barrier.
The primitive generator consumes a patch and produces a set of points, lines or triangles. Each vertex generated are associated with (u, v, w) or (u, v) position available in the evaluation shader thanks to the variable gl_TessCoord where u + v + w = 1.
The evaluation shaders provide a gl_In array like control shaders. The members of the elements of gl_In aregl_Position, gl_PointSize and gl_ClipDistance for each vertex of a patch. The evaluation shaders have the variables gl_PatchVerticesIn and gl_PrimitivesID but also some extra variables gl_TessLevelOuter andgl_TessLevelInner which contain the tessellation levels of the patch.
The evaluation shaders output gl_Position, gl_PointSize and gl_ClipDistance.
Tessellation has a lot more details to understand to work on a real implementation in a project! Those details are available in GL_ARB_tessellation_shader and obviously in OpenGL 4.0 specification. I think the API need some refinements but provides enough to start having fun with tesselation.
Subroutine.
Subroutines are defined by GL_ARB_shader_subroutine as part of OpenGL 4.0 specification. This mechanism is some sort of C++ function pointer which allows to select, from the C++ program, a specific algorithm to be used in a GLSL program. This feature is a great enhancement for the 'uber-shader' type of software design where all the algorithms are included in a single shader to handle multiple/every cases. Subroutines allow to select specific shader code-pathes but also to keep the same program and program environment.
The following GLSL code sample defines 3 subroutine uniforms, which means 3 entries to change a shader behaviour. Several functions can be defined for a subroutine and a single subroutine function can be used for multiple subroutine uniforms. Subroutine function can't be overloaded. Subroutine uniforms are the sort of 'function pointer' but can only 'point' on subroutine functions.
Subroutine in GLSL 4.00:
- subroutine vec4 greatFeature(in vec3 Var1, in vec3 Var2);
- subroutine vec4 bestFeature(in vec3 Var1, in vec3 Var2);
- subroutine mat4 otherFeature(in vec4 Var1, in float Var2, in int var3);
- subroutine(greatFeature, bestFeature)
- vec4 myFeature1(in vec3 Var1, in vec3 Var2)
- { ... } // Required function body
- subroutine(greatFeature, bestFeature)
- vec4 myFeature2(in vec3 Var1, in vec3 Var2)
- { ... } // Required function body
- subroutine(bestFeature)
- vec4 myBestFeature(in vec3 Var1, in vec3 Var2)
- { ... } // Required function body
- subroutine(otherFeature)
- subroutine mat4 myOtherFeature(in vec4 Var1, in float Var2, in int var3);
- { ... } // Required function body
- // Could be set to myFeature1, myFeature2
- subroutine uniform greatFeature GreatFeature;
- // Could be set to myFeature1, myFeature2, myBestFeature
- subroutine uniform bestFeature BestFeature;
- // Could be set to myOtherFeature only...
- // probably not a recommanded use of subroutines...
- subroutine uniform otherFeature OtherFeature;
- void main()
- {
- // Subroutine uniform variables are called the same way functions are called.
- GreatFeature();
- ...
- BestFeature();
- ...
- OtherFeature();
- }
The subroutine uniforms are assigned using the function glUniformSubroutinesuiv which parameters define the list of the subroutine functions used set to all subroutine uniforms. To get the subroutine function locations, OpenGL provides the function glGetSubroutineIndex.
Transform feedback.
Transform feedback is the OpenGL name given to Direct3D output stream. It allows to capture processed vertices data before rasterization and to be more accurate, just before clipping. A first extension proposed by nVidia (GL_NV_transform_feedback) has been promoted to GL_EXT_transform_feedback and finally included in OpenGL 3.0 specification.
From where we come (OpenGL 3.0):
- char * Strings[] = {"Position", "Color"};
- glTransformFeedbackVaryings(Program, 2, Strings, GL_SEPARATE_ATTRIBS);
- glLinkProgram(Program);
- ...
- glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, PositionBuffer);
- glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, ColorBuffer);
- // No rasterisation will bit performed, optional.
- glEnable(GL_RASTERIZER_DISCARD);
- ...
- glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, Query);
- glBeginTransformFeedback(GL_TRIANGLES);
- glDrawElement(...);
- glEndTransformFeedback();
- glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
- ...
- // Query the number of primitives written in the transform buffer.
- glGetQueryObjectuiv(Query, GL_QUERY_RESULT, &PrimitivesWritten);
GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN is a query that can be used to get the number of primitives actually written in the transform feedback buffer(s). When data are captured from a vertex shader and the feedback primitive is the same as the drawn primitive, the number of primitives written in the buffer is likely to be the same as the number of primitives sent at draw call but transform feedback has such flexibility that transform feedback primitive can be different than draw call primitive.
Furthermore, transform feedback can capture geometry shader output. As geometry shader can generate or discard primitives, which output vertrices count become unpredictable. Transform feedback buffers can be used as vertex data of further draw calls where the vertices polygon count might define the draw call primitive count. If you repeat a series of geometry shader and transform feedback, we might have a tessellator... but a really slow useless one!
This work has been followed by some more work by nVidia in the form of GL_NV_transform_feedback2 to finally give us 4 new extensions in OpenGL 4.0 which push the transform feedback boundaries.
......
No comments:
Post a Comment