This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License
Computer Graphics
Computer Graphics
Computer Graphics
Computer Graphics
#include “glew.h“ …
#include
GLenum err = glewInit(); if( err != GLEW_OK )
{
Do this immediately after opening the window
FILE *fp = fopen( filename, “r” ); if(fp==NULL) {…}
}
// length of file GLchar * buffer = new GLchar [numBytes+1];
fprintf( stderr, “glewInit Error\n” ); exit( 1 );
fseek( fp, 0, SEEK_END ); int numBytes = ftell( fp );
The GLSL API
Mike Bailey mjb@cs.oregonstate.edu
fprintf( stderr, “GLEW initialized OK\n” );
fprintf( stderr, “Status: Using GLEW %s\n”, glewGetString(GLEW_VERSION) );
rewind( fp ); // same as: “fseek( in, 0, SEEK_SET )”
glslapi.pptx
mjb – December 15, 2020
mjb – December 15, 2020
12
Initializing the GL Extension Wrangler (GLEW)
3
Reading a Shader source file into a character array
4
GLEW cannot be initialized until a graphics window is open. Like OpenGL itself, GLEW’s calls will not work unless it can see a graphics context (i.e., a graphics state).
buffer[numBytes] = ‘\0‘;
// the entire file is now in a byte string
http://glew.sourceforge.net
34
mjb – December 15, 2020
mjb – December 15, 2020
1
The GLSL Shader-Creation Process
2
fread( buffer, 1, numBytes, fp ); fclose( fp );
1
Creating and Compiling a Vertex Shader from that character buffer (Geometry and Fragment files work the same way)
5
Creating Different Shader Types 6 GLuint shader = glCreateShader( GL_VERTEX_SHADER );
Computer Graphics
Computer Graphics
int status;
int logLength;
This is the only part of this process that is specific to the type of shader it is
GLuint vertShader = glCreateShader( GL_VERTEX_SHADER );
GLuint shader = glCreateShader( GL_GEOMETRY_SHADER );
GLuint shader = glCreateShader( GL_TESS_CONTROL_SHADER ); GLuint shader = glCreateShader( GL_TESS_EVALUATION_SHADER ); GLuint shader = glCreateShader( GL_FRAGMENT_SHADER );
GLuint shader = glCreateShader( GL_COMPUTE_SHADER );
glShaderSource( vertShader, 1, (const GLchar **)&buffer, NULL );
delete [ ] buffer;
glCompileShader( vertShader ); CheckGlErrors( “Vertex Shader 1” );
An array of strings
glGetShaderiv( vertShader, GL_COMPILE_STATUS, &status ); if( status == GL_FALSE )
{
fprintf( stderr, “Vertex shader compilation failed.\n” );
glGetShaderiv( vertShader, GL_INFO_LOG_LENGTH, &logLength ); GLchar *log = new GLchar [logLength];
glGetShaderInfoLog( vertShader, logLength, NULL, log );
fprintf( stderr, “\n%s\n”, log );
delete [ ] log;
exit( 1 );
Other than this, the rest of the create, compile, link process is the same for each shader type.
}
CheckGlErrors( “Vertex Shader 2” );
56
How does that array-of-strings thing work?
7
Why use an array of strings as the shader input, instead of just a single string?
8
GLchar *ArrayOfStrings[3];
ArrayOfStrings[0] = “#define SMOOTH_SHADING”; ArrayofStrings[1] = “ . . . a commonly-used procedure . . . “; ArrayofStrings[2] = “ . . . the real vertex shader code . .. “; glShaderSource( vertShader, 3, ArrayofStrings, NULL );
1.
You can use the same shader source and insert the appropriate “#defines” at the beginning
These are two ways to provide a single buffer:
if-tests vs. preprocessing
GLchar *buffer[1];
buffer[0] = “ . . . the entire shader code . . . “; glShaderSource( vertShader, 1, buffer, NULL );
if( Mode == SmoothShading ) {…}
else if( Mode == PhongShading ) {…}
#ifdef SMOOTH_SHADING {…}
#endif
GLchar *buffer = “ . . . the entire shader code . . . “; glShaderSource( vertShader, 1, (const GLchar **)&buffer, NULL );
#ifdef PHONG_SHADING {…}
#endif
Computer Graphics
Computer Graphics
78
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
2. 3.
You can insert a common header file (≈ a .h file)
You can simulate a “#include” to re-use common pieces of code
2
Computer Graphics
Computer Graphics
Computer Graphics
Computer Graphics
11
12
Creating the Program and Attaching the Shaders to It
9
Linking the Program and Checking its Validity
10
GLuint program = glCreateProgram( ); glAttachShader( program, vertShader ); glAttachShader( program, fragShader ); glAttachShader( program, geomShader );
glLinkProgram( program );
9 10
Making the Program Active
11
Using Multiple Shader Programs
12
glUseProgram( program );
glUseProgram( program0 );
Making the Program Inactive
(use the fixed function pipeline instead)
glUseProgram( program3 );
glUseProgram( 0 );
glUseProgram( program4 );
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
CheckGlErrors( “Shader Program 1” );
glGetProgramiv( program, GL_LINK_STATUS, &status ); if( status == GL_FALSE )
{
fprintf( stderr, “Link failed.\n” );
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLength ); log = new GLchar [logLength];
glGetProgramInfoLog( program, logLength, NULL, log );
fprintf( stderr, “\n%s\n”, log );
delete [ ] log;
exit( 1 );
}
CheckGlErrors( “Shader Program 2” );
glValidateProgram( program );
glGetProgramiv( program, GL_VALIDATE_STATUS, &status );
fprintf( stderr, “Program is %s.\n”, status == GL_FALSE ? “invalid” : “valid” );
glUseProgram( program1 );
glUseProgram( program2 );
glUseProgram( program5 );
A specified shader program is an “attribute” – it stays in effect until you change it
3
Computer Graphics
Computer Graphics
13
14
15
} }
Computer Graphics
It’s not a bad idea to do this in all your OpenGL programs, even without shaders!
ComHpuytepreGrr-a>pUhicsse( 0 ); 16
Then you need to fill it.
glEnd(); }
void
CheckGlErrors( const char* caller ) {
unsigned int glerr = glGetError(); if( glerr == GL_NO_ERROR )
int Polar;
float K;
GLSLProgram *Hyper = new GLSLProgram( );
bool valid = Hyper->Create( “hyper.vert”, “hyper.geom”, “hyper.frag” ); if( ! valid ) { . . . }
Passing in Uniform Variables
Passing in Attribute Variables
You first need to find the variable’s location in the shader program’s symbol table. float lightLoc[3] = { 0., 100., 0. };
if( location < 0 ) {
GLint location = glGetUniformLocation( program, “uLightLocation” ); if( location < 0 )
else {
else
glVertex3f( x0, y0, z0 ); glVertexAttrib2f( location, a1, b1 ); glVertex3f( x1, y1, z1 ); glVertexAttrib2f( location, a2, b2 ); glVertex3f( x2, y2, z2 );
fprintf( stderr, “Cannot find Uniform variable ‘uLightLocation’\n” ); glUniform3fv( location, 1, lightLoc );
glBegin( GL_TRIANGLES ); glVertexAttrib2f( location, a0, b0 );
return;
fprintf( stderr, "GL Error discovered from caller ‘%s‘: ", caller ); switch( glerr )
{
Checking for Errors
15
Writing a C++ Class to Handle Everything is Fairly Straightforward 16 Setup:
case GL_INVALID_ENUM:
fprintf( stderr, "Invalid enum.\n" );
This loads, compiles, and links the shader. It prints error messages if something went wrong.
break;
case GL_INVALID_VALUE:
fprintf( stderr, "Invalid value.\n" );
Using the GPU program:
break;
case GL_INVALID_OPERATION:
Hyper->Use( );
Hyper->SetUniformVariable( “uPolar”, Polar ); Hyper->SetUniformVariable( “uK”, K ); glBegin( GL_TRIANGLES );
fprintf( stderr, “Invalid Operation.\n” );
break;
case GL_STACK_OVERFLOW:
fprintf( stderr, “Stack overflow.\n” );
Hyper->SetAttributeVariable( “aTemperature”, T0 ); glVertex3f( x0, y0, z0 ); Hyper->SetAttributeVariable( “aTemperature”, T1 ); glVertex3f( x1, y1, z1 ); Hyper->SetAttributeVariable( “aTemperature”, T2 ); glVertex3f(x,y,z );
break;
case GL_STACK_UNDERFLOW:
fprintf(stderr, “Stack underflow.\n” );
break;
case GL_OUT_OF_MEMORY:
break; default:
222
fprintf( stderr, “Out of memory.\n” );
fprintf( stderr, “Unknown OpenGL error: %d (0x%0x)\n”, glerr, glerr );
glEnd( );
Reverting to the fixed-function pipeline during display:
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
13
14
You first need to find the variable’s location in the shader program’s symbol table.
GLint location = glGetAttribLocation( program, “aArray” );
fprintf( stderr, “Cannot find Attribute variable ‘aArray’\n” ); }
Then you need to fill it per-vertex.
4
17
18
SPIR-V
17
Reading SPIR-V-compiled Shaders 18 The new glShaderBinary( ) call replaces both glCreateShader( ) and glCompilerShader( )
SPIR-V is a file format that can be used to hold shader code that has been pre-compiled, but has not yet been turned into machine code. It was created as a way for software developers to pre-compile their code and then allow the vendor-specific driver to produce the final binary representation. There are four major advantages in doing things this way:
FILE *fp = fopen( filename, “r” );
if(fp==NULL) {…}
fseek( fp, 0, SEEK_END );
int numBytes = ftell( fp ); // length of file – guaranteed to be a multiple of 4 GLchar * buffer = new GLchar [numBytes];
1. A software developer can more easily wring compiler errors from the code by having an external compiler that can be run independently from the application.
2. Vendors can still apply their optimization-magic in their device-specific drivers.
rewind( fp ); // same as: “fseek( in, 0, SEEK_SET )” fread( buffer, 1, numBytes, fp );
fclose( fp );
3. SPIR-V files can be read at the start of a program and be turned into machine code faster than the original GLSL files could have been turned into machine code.
GLuint shaders[2]
glShaderBinary( 2, shaders, GL_SHADER_BINARY_FORMAT_SPIR_V, buffer, numbytes ); GLuint program = glCreateProgram( );
glAttachShader( program, shaders[0] );
glAttachShader( program, shaders[1] );
4. Software developers can distribute their code without having to reveal the shaders’ source code.
GLSL Source
External GLSL Compiler
SPIR-V
Compiler in driver
Vendor-specific code
Computer Graphics
Computer Graphics
SPIR-V:
Standard Portable Intermediate Representation for Vulkan
19
How do you know if SPIR-V compiled successfully? 20
glslangValidator shaderFile -G [-H] [-I
Computer Graphics
Computer Graphics
19
20
Shaderfile extensions:
Same as C/C++ — the compiler gives you no nasty messages.
Also, if you care, legal .spv files have a magic number of 0x07230203
.vert Vertex
.tesc Tessellation Control .tese Tessellation Evaluation .geom Geometry
.frag Fragment
.comp Compute
(Can be overridden by the –S option)
So, if you do an od –x on the .spv file, the magic number looks like this:
-V Compile for Vulkan
-G Compile for OpenGL
-I Directory(ies) to look in for #includes
-S Specify stage rather than get it from shaderfile extension -c Print out the maximum sizes of various properties
Windows: glslangValidator.exe
Linux:
setenv LD_LIBRARY_PATH /usr/local/common/gcc-6.3.0/lib64/
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
mjb – December 15, 2020
0203 0723 . . .
5