Uniforms

Hi,

I am learning how to use Uniforms in OpenGL to provide data to my shaders. I have the following code (the forum decides to do some weird formatting in the code):

#include "sb6.h"
#include <vmath.h>
#include <math.h>
#include <stdlib.h>

using namespace sb6;

class my_application : public sb6::application
{
private:
	GLuint buffers[2];
	GLuint rendering_program;
	GLuint vertex_array_object;

public:
	void startup( void )
	{
		rendering_program = compile_shaders();
		glGenVertexArrays(1, &vertex_array_object );
		glBindVertexArray( vertex_array_object );

		// Generate names for the two buffers
		glGenBuffers( 2, buffers );

		// The data used for vertex positions
		static const float positions[] =
		{
			0.25, -0.25, 0.5, 1.0,
		   -0.25, -0.25, 0.5, 1.0,	
			0.25,  0.25, 0.5, 1.0
		};

		// The data used for vertex colors
		static const float colors[] =
		{
			1.0, 0.0, 0.0, 1.0,
			0.0, 1.0, 0.0, 1.0,
			0.0, 0.0, 1.0, 1.0
		};

		// Bind the first attribute and initialize it
		glBindBuffer( GL_ARRAY_BUFFER, buffers[ 0 ] );
		glBufferData( GL_ARRAY_BUFFER, sizeof( positions ), positions, GL_STATIC_DRAW );
		glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 0, NULL );
		glEnableVertexAttribArray( 0 );

		// Bind the second attribute and initialize it
		glBindBuffer( GL_ARRAY_BUFFER, buffers[ 1 ] );
		glBufferData( GL_ARRAY_BUFFER, sizeof( colors ), colors, GL_STATIC_DRAW );
		glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 0, NULL );
		glEnableVertexAttribArray( 1 );

		// Get the indices of the uniform block
		static const GLchar* uniformNames[ 4 ] =
		{
			"TransformBlock.scale",
			"TransformBlock.translation",
			"TransformBlock.rotation",
			"TransformBlock.projection_matrix"
		};
		GLuint uniformIndices[ 4 ];
		glGetUniformIndices( rendering_program, 4, uniformNames, uniformIndices );

		// Find the locations of the uniform block members
		GLint uniformOffsets[ 4 ];
		GLint arrayStrides[ 4 ];
		GLint matrixStrides[ 4 ];
		glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_OFFSET, uniformOffsets );
		glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_ARRAY_STRIDE, arrayStrides );
		glGetActiveUniformsiv( rendering_program, 4, uniformIndices, GL_UNIFORM_MATRIX_STRIDE, matrixStrides );

		// Allocate some memory for our buffer (don't forget to free it later)
		unsigned char* buffer = ( unsigned char* ) malloc( 4096 );
		memset( buffer, 0, sizeof( buffer ) );

		// Store the scale in the buffer
		*( ( float* )( buffer + uniformOffsets[ 0 ] ) ) = 3.0f;

		// Store the translation in the buffer
		( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 0 ] = 1.0f;
		( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 1 ] = 2.0f;
		( ( float* )( buffer + uniformOffsets[ 1 ] ) )[ 2 ] = 3.0f;

		// Store the rotation in the buffer
		const GLfloat rotations[] = { 30.0f, 40.0f, 60.0f };
		unsigned int offset = uniformOffsets[ 2 ];

		for( int n = 0; n < 3; n++ )
		{
			*( ( float* )( buffer + offset ) ) = rotations[ n ];
			offset += arrayStrides[ 2 ];
		}

		// Store the matrix in the buffer
		const GLfloat matrix[] =
		{
			1.0f, 2.0f, 3.0f, 4.0f,
			9.0f, 8.0f, 7.0f, 6.0f,
			2.0f, 4.0f, 6.0f, 8.0f,
			1.0f, 3.0f, 5.0f, 7.0f
		};

		for( int i = 0; i < 4; i++ )
		{
			GLuint offset = uniformOffsets[ 3 ] + matrixStrides[ 3 ] * i;
			
			for( int j = 0; j < 4; j++ )
			{
				*( ( float* )( buffer + offset ) ) = matrix[ i * 4 + j ];
				offset += sizeof( GLfloat );
			}
		}

		free( buffer );
	}

	void shutdown( void )
	{
		glDeleteVertexArrays(1, &vertex_array_object );
		glDeleteProgram( rendering_program );
	}

	void render( double currentTime )
	{
		const GLfloat color[] = { 0.0f, 0.2f, 0.0f, 1.0f };
		glClearBufferfv( GL_COLOR, 0, color );

		// Use the program object we created earlier for rendering
		glUseProgram( rendering_program );

		glDrawArrays( GL_TRIANGLES, 0, 3 );
	}

	GLuint compile_shaders( void )
	{
		GLuint vertex_shader;
		GLuint fragment_shader;
		GLuint program;

		// Source code for the vertex shader
		static const GLchar* vertex_shader_source[] =
		{
			"#version 430 core																
"
			"																				
"
			"layout ( location = 0 ) in vec4 position;										
"
			"layout ( location = 1 ) in vec4 color;											
"
			"																				
"
			"layout(std140) uniform TransformBlock										    
"
			"{																				
"
			"	float scale;																
"
			"	vec3 translation;															
"
			"	float rotation[ 3 ];														
"
			"	mat4 projection_matrix;														
"
			"} transform;																	
"
			"																				
"
			"out vec4 vs_color;																
"
			"																				
"
			"void main( void )																
"
			"{																				
"
			"	gl_Position = position;													    
"
			"	vs_color = color;															
"
			"}																				
"
		};

		// Source code for the fragment shader
		static const GLchar* fragment_shader_source[] =
		{
			"#version 430 core																
"
			"																				
"
			"in vec4 vs_color;																
"
			"																				
"
			"out vec4 color;																
"
			"																				
"
			"void main( void )																
"
			"{																				
"
			"	color = vs_color;															
"
			"}																				
"
		};

		// Create and compile the vertex shader
		vertex_shader = glCreateShader( GL_VERTEX_SHADER );
		glShaderSource( vertex_shader, 1, vertex_shader_source, NULL );
		glCompileShader( vertex_shader );

		// Create and compile the fragment shader
		fragment_shader = glCreateShader( GL_FRAGMENT_SHADER );
		glShaderSource( fragment_shader, 1, fragment_shader_source, NULL );
		glCompileShader( fragment_shader );

		// Create program, attach shaders to it, and link it
		program = glCreateProgram();
		glAttachShader( program, vertex_shader );
		glAttachShader( program, fragment_shader );
		glLinkProgram( program );

		// Delete the shaders as the program has them now
		glDeleteShader( vertex_shader );
		glDeleteShader( fragment_shader );

		return program;
	}
};

DECLARE_MAIN( my_application );

For some reason “glGetUniformIndices” returns garbage to the “uniformIndices” array, and because of that I get a crash when i try to load a value for the “scale” into the buffer.

Any suggestions?

Thanks
Robin

You need to use “transform.scale” instead of “TransformBlock.scale”. See the syntax section of http://www.opengl.org/wiki/Interface_Block_(GLSL)

Thanks for your reply, but unfortunately it did not make any difference changeing from TransformBlock to transform and the exact same error persists.

Actually, you had it right the first time (TransformBlock.scale to be used when accessed from OpenGL side). What values are being returned? is it the value of GL_INVALID_INDEX (-1 or 0xFFFFFFFFu) returned? Maybe it is because you aren’t using them in your shader so they have been optimised away. Passing a value of GL_INVALID_INDEX back into other functions doesn’t seem to be allowed by spec.

The index returned is the same for every uniform in the block, 4294967295. I tried “using” them in the shader but that did not change anything.

If there was an error, nothing would be written to uniformIndices, so the fact it’s returning 4294967295 (which is equal to 0xFFFFFFFFu = GL_INVALID_INDEX) probably indicates there’s no other error.

Are you sure you’re using the values in such a way that they have an effect on the position of vertices or the final colour of triangles rendered? If they don’t have any effect on what is being rendered, the GLSL compilers are pretty good at optimising the code away.

Ah I wasn’t actually doing anything “usefull” with it. But it feels kinda bad that the program crashes just becauase the compiler decides to optimize away stuff. Is there a way around this (othan than explicitly checking if every single index is equal to GL_INVALID_INDEX and not doing the memory stuff if so is the case)?

If you use a fixed layout (std140 or std430), then you don’t need to query the layout.