GLSL: Creating GLSL Programs - Overview The steps used to incorporate shaders into an OpenGL program: 1. Create shader programs There must be at least a vertex and a fragment shader Each is a set of strings that represent lines of GLSL code 2. Create shader objects, one for each shader 3. Associate shader code with shader objects 4. Compile each shader 5. Cretae a program object 6. Attach shader objects to the program object 7. Link the program components 8. Install the shader executable in the current OpenGL state The actual coding of vertex and fragment shaders will be addressed later As the above sequence implies, the steps involved in creating shader programs is similar to that of creating any other compiled program The OpenGL environment must provide storage for 1. The source code, 2. compiled code, and 3. executable code These must be accessible to an OpenGL program from within its context 1
GLSL: Creating GLSL Programs - Versions Both OpenGL and GLSL have version numbers associated with them It is recommended that your program query these to promote compatibility with a given OpenGL environment Syntax: <version number> space [< vendor specific info>] Syntax for the version number: <major version number>.<minor version number>[.< release number>] This info is accessed using glgetstring with either GL V ERSION or GL SHADING LANGUAGE V ERSION 2
GLSL: Creating GLSL Programs - Versions (2) Sample code: // *** From p 202 void getglversion(int *major, int *minor) const char *verstr = (const char *) glgetstring(gl_version); if ((verstr == NULL) (sscanf(verstr,"%d.%d", major, minor)!= 2)) *major = *minor = 0; fprintf(stderr, "Invalid GL_VERSION format!!!\n"); void getglslversion(int *major, int *minor) int gl_major, gl_minor; getglversion(&gl_major, &gl_minor); *major = *minor = 0; if(gl_major == 1) /* GL v1.x can only provide GLSL v1.00 as an extension */ const char *extstr = (const char *) glgetstring(gl_extensions); if ((extstr!= NULL) && (strstr(extstr, "GL_ARB_shading_language_100")!= NULL)) *major = 1; *minor = 0; else if (gl_major >= 2) /* GL v2.0 and greater must parse the version string */ const char *verstr = (const char *) glgetstring(gl_shading_language_version); if((verstr == NULL) (sscanf(verstr, "%d.%d", major, minor)!= 2)) *major = *minor = 0; fprintf(stderr, "Invalid GL_SHADING_LANGUAGE_VERSION format!!!\n"); 3
GLSL: Creating GLSL Programs - Source Code Shader source code has the same syntax as C: Precompiler directives Variable declarations Main function The program is represented as an array of strings in an OpenGL program For examples, see C6 of Shading Language 3rd ed (Details will be addressed in subsequent discussion of vertex and fragment shaders) 4
GLSL: Creating GLSL Programs - Shader Objects These objects store the shader source code To create a shader object use: GLuint glcreateshader (GLenum shadertype) shadertype can be GL VERTEX SHADER, GL FRAGMENT SHADER (or similar values for geometric and tesselation shaders) A unique integer id is returned on successful creation of the object Source code is attached to the shader object using: void glshadersource (GLuint shader, GLsizei count, const GLchar **string, const GLint *length) where shader is the unique id of a shader object count is the number of strings in the array holding the source code string is the array holding the source code strings, and length is an array that holds the string lengths on a string-by-string basis (row-by-row) If length is NULL, it indicates all strings are null-terminated Otherwise, A positive integer indicates the number of characters in the string (excluding the null character) A negative integer indicates the string is null-terminated glshadersource simply copies the code into the object 5
GLSL: Creating GLSL Programs - Compiling The purpose of compiling shader source code is the same as for any language Syntax is checked Object code is generated The result of a successful compile is stored in the shader object Compile using: void glcompileshader(glint shader) The status of the compile (success or failure) is stored in the shader object s state The object code that results from a successful compile is stored in the object The status of a compile can be obtained by querying the object (see below) 6
GLSL: Creating GLSL Programs - Creating a Program To create a program, 1. A program object is created 2. Shader objects are attached to it,and 3. The programs are linked To create a program object: GLuint glcreateprogram (void) Returns a unique id for the object Zero is returned in failure To attach shader objects to a program: void glattachshader (GLuint program, GLuint shader) The shader objects attached to a program when linking occurs will be those that become part of the resulting executable There is no limit on the number that can be attached Shaders can be attached to more than one program Attachment can occur at any time once a shader object has been created 7
GLSL: Creating GLSL Programs - Creating a Program (2) To create an executable program: void gllinkprogram (GLuint program) The status of the linkage (success or failure) is stored in the shader object s state The executable that results from a successful linkage is stored in the object The status of a linkage can be obtained by querying the object (see below) Values of active user-defined uniform variables are initialized to zero and assigned storage (see later) Active user-defined atribute variables not not yet bound to an index are bound to one If a vertex shader is attached but not a fragment shader (or vice-versa), the program uses the fixed functionality pipeline Linkage failure may result from the following: 1. Number of active uniform or active variables exceeded 2. Main missing in vertex or fragment shader 3. Missing a corresponding in variable for an out variable (or vice-versa) 4. Shader being linked not successfully compiled 5. Issues with attribute matrices Successful linkage results in programs for the appropriate gfx processors Results of previous linkages are lost If the shader objects are modified after linkage it will have no effect on the current program object until another liknage operation occurs 8
GLSL: Creating GLSL Programs - Usage To use a program object in an OpenGL program: void gluseprogram (GLunint program) This installs the program in the current OpenGL rendering state If one or the other of the vertex or fragment shader objects are missing, the program uses fixed functionality for the missing component If program is zero, fixed functionality is used gfx processors are disabled 9
GLSL: Creating GLSL Programs - Finishing Up As usual, you should deallocate storage for OpenGL objects when finished with them void gldeleteprogram (GLuint program) Opposite of glcreateprogram Frees memory used for program if not in use in current rendering state Flagged for deletion otherwise Any shaders attached to the program are automatically detached If the shaders have been previously flagged for deletion, they are deleted (see below) void gldeleteshader (GLuint shader) Opposite of glcreateshader Frees memory used for Shader if not attached to any program Flagged for deletion otherwise void gldetachshader (GLuint program, GLuint shader) Opposite of glatachshader Dissociates shader from program If flagged for deletion and not attached to any other program, is deleted Recommended that shader objects be deleted as soon as attached to a program When program object deleted in future, all shader objects will automatically be detached and if not attached to any other program objects, will be automatically deleted (since will have been flagged for deletion by the gldeleteshader call 10
GLSL: Creating GLSL Programs - Query Functions void glgetshaderiv (GLuint shader, GLenum pname, GLint *params) Retrieves info about a shader object Results returned in params Parameters: Parameter Values returned Indicates GL SHADER TYPE GL VERTEX SHADER, GL FRAGMENT SHADER,... GL DELETE STATUS GL TRUE/GL FALSE Is shader flagged for deletion? GL COMPILE STATUS GL TRUE/GL FALSE Was last compile successful? GL INFO LOG LENGTH Number of chars in log; zero if no log GL SHADER SOURCE LENGTH Number of chars in log (including null chars); zero if no log void glprogramiv (GLuint program, GLenum pname, GLint *params) Retrieves info about a program object Results returned in params Parameters: Parameter Values returned Indicates GL DELETE STATUS GL TRUE/GL FALSE Is program flagged for deletion? GL LINK STATUS GL TRUE/GL FALSE Was last linkage successful? GL VALIDATE STATUS GL TRUE/GL FALSE Was last validation operation successful? GL INFO LOG LENGTH Number of chars in log; zero if no log GL ATTACHED SHADERS Number of attached shaders GL ACTIVE ATTRIBUTES Number of active attributes GL ACTIVE ATTRIBUTE MAX LENGTH Length of longest active uniform (including null char); zero if none GL ACTIVE UNIFORMS GL ACTIVE UNIFORM MAX LENGTH Number of active attributes Length of longest active uniform (including null char); zero if none void glgetshadersource (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source) Retrieves the source code as a single null-terminated string Results returned in source bufsize imposes a limit to the number of chars returned (including the null char) length assigned to the number of chars actually returned If NULL passed to length, no value is returned 11
GLSL: Creating GLSL Programs - Query Functions (2) void glgetshaderinfolog (GLuint shader, GLsizei maxlength, GLsizei *length, GLchar *infolog) Retrieves info re shader s compilation Results returned in infolog maxlength imposes a limit to the number of chars returned (including the null char) length assigned to the number of chars actually returned If NULL passed to length, no value is returned void glgetprograminfolog (GLuint shader, GLsizei maxlength, GLsizei *length, GLchar *infolog) Retrieves info re shader s compilation Results returned in infolog maxlength imposes a limit to the number of chars returned (including the null char) length assigned to the number of chars actually returned If NULL passed to length, no value is returned Code for accessing a shader log (GLSL pp252-53); code for program log analogous void printshaderinfolog(gluint shader) int infologlen = 0; int charswritten = 0; GLchar *infolog; glgetshaderiv(shader, GL_INFO_LOG_LENGTH, &infologlen); printopenglerror(); // Check for OpenGL errors if (infologlen > 0) infolog = (GLchar*) malloc(infologlen); if (infolog == NULL) printf("error: Could not allocate InfoLog buffer\n"); exit(1); glgetshaderinfolog(shader, infologlen, &charswritten, infolog); printf("infolog:\n%s\n\n", infolog); free(infolog); printopenglerror(); // Check for OpenGL errors 12
GLSL: Creating GLSL Programs - Query Functions (3) void glgetattachedshaders (GLuint program, GLsizei maxcount, GLsizei *count, GLchar *shaders) Retrieves names of shaders attached to program Results returned in shaders maxcount imposes a limit to the number of shaders returned count assigned to the number of shaders actually returned If NULL passed to count, no value is returned GLboolean glisshader (GLuint shader) Returns GL TRUE/GL FALSE if shader names a shader object GLboolean glisprogram (GLuint program) Returns GL TRUE/GL FALSE if program names a program object 13