iOS: Using Separate Shaders

One of the lovely additions to iOS5 is there is now the ability to use separate vertex and fragment shaders (GL_EXT_separate_shader_objects).

The first step in using separate shaders is to create an object to bind them onto that will be our overall shader program, known as a pipeline object.

GLuint gProgramPipeline = 0;
GLuint gVertexProgram = 0;
GLuint gFragmentProgram = 0;
 
//
//
int main()
{
	//
	CreatePipeline();
	CreateShaders();
 
	//
	BindShadersToPipeline();
 
	//
	do
	{
		//
		UpdateUniforms();
 
		//
		BindPipeline();
		DrawSomething();
		UnbindPipeline();
	}
	while( true );
 
	//
	DestroyShaders();
	DestroyPipeline();
}
 
//
//
void CreatePipeline()
{
	glGenProgramPipelinesEXT( 1, &gProgramPipeline );
}
 
//
//
void DestroyPipeline()
{
	if( gProgramPipeline )
	{
		glDeleteProgramPipelinesEXT( 1, &gProgramPipeline );
		gProgramPipeline = 0;
	}
}

This pipeline object acts similar to vertex array object (VAO) only with shader programs, however instead of using glUseProgram, a separate function glUseProgramStagesEXT() must be used to bind the shader program to the pipeline, specifying the role of the shader program.

//
//
void BindShadersToPipeline()
{
	glUseProgramStagesEXT( gProgramPipeline, GL_VERTEX_SHADER_BIT_EXT, gVertexProgram );
	glUseProgramStagesEXT( gProgramPipeline, GL_FRAGMENT_SHADER_BIT_EXT, gFragmentProgram );
}

Updating uniforms is slightly different as well.

//
//
void UpdateUniforms()
{
	//
	GLint uniformLoc = glGetUniformLocation( gVertexProgram, "myVertUniform" );
	glProgramUniform1fEXT( gVertexProgram,
			       uniformLoc,
			       1.248f );
 
	uniformLoc = glGetUniformLocation( gFragmentProgram, "myFragUniform" );
	glProgramUniform1fEXT( gFragmentProgram,
			       uniformLoc,
			       6.1218f );
 
	//
	uniformLoc = glGetUniformLocation( gVertexProgram, "myCommonUniform" );
	float commonValue = 2.0f;
 
	glProgramUniform1fEXT( gVertexProgram,
			       uniformLoc,
			       commonValue );
 
	uniformLoc = glGetUniformLocation( gFragmentProgram, "myCommonUniform" );
	glProgramUniform1fEXT( gVertexProgram,
			       uniformLoc,
			       commonValue );
}

Finally to use the program pipeline, we just need to bind it.

//
//
void BindPipeline()
{
	glBindProgramPipelineEXT( gProgramPipeline );
}
 
//
//
void UnbindPipeline()
{
	glBindProgramPipelineEXT( 0 );
}

fef