PDA

View Full Version : Binding points and OSX



noizex
02-15-2016, 09:01 AM
Hello,
I recently learned that OSX version of OpenGL/GLSL does not support explicit binding points in shader, like this:



// this is included in every shader and defines binding points for samplers for whole engine
#define BASE_TEXTURE 0
#define NORMAL_TEXTURE 1

layout(binding = BASE_TEXTURE) uniform sampler2D mainTexture;
layout(binding = NORMAL_TEXTURE) uniform sampler2D normTexture;


I'm really struggling with figuring out how to support OSX in this case and not break all my neatly organized code. What would be the best way to keep these fixed binding points organized by texture type (BASE, NORMAL, SHADOW_MAP, NOISE, SPECIAL_1, SPECIAL_2). Right now my engine can keep track of what texture type is active at which binding slot so I can skip changing that texture if it doesn't have to be and so on. It all works great and with way more clear code.

Now it seems for OSX I'd have to set binding points by sampler name and this defeats whole concept where the actual name ("mainTexture", "normTexture") does not matter, it's up to GLSL dev how it will be named, what is important is binding point that this texture sampler connects to.

Any help appreciated, looks like making portable game will be harder than I imagined :(

malexander
03-08-2016, 08:05 AM
Unfortunately OSX only supports OpenGL 4.1, and explicit-uniform-location is a GL4.2 feature. This has also made it difficult to sweep through our shaders and make them Vulkan-ready as OSX is one of our supported platforms (at least explicit-attribute-location is supported).

What you can do is to name your samplers in a very standard way in the shader, and use the shader loading code to assign the proper bindings. Have the shader loading code inspect each sampler, map its uniform name to your desired texture binding, and assign that value to the uniform. eg:



// build a map, once
std_map_name_to_binding[ "mainTexture" ] = BASE_TEXTURE;
std_map_name_to_binding[ "normTexture" ] = NORM_TEXTURE;

// ....

// loading shader
int num_uniforms=0;
glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uniforms);
for(int index=0; index<num_uniforms; ++index)
{
glGetActiveUniform(prog, index, MAX_NAME_LENGTH, &namelen, &usize, &utype, uname);
uloc = glGetUniformLocation(prog, uname);
if(uniform_type == GL_SAMPLER_2D) // plus any other sampler types you support...
{
GLint location = std_map_name_to_binding[ uname ]; // map prebuilt to convert name to binding location
glUniform1i( uloc, location);
}
}


I've left out a lot of the declarations for brevity's sake to show the basic idea. If you use a lot of modern GL4, you'll find yourself doing this sort of workaround on OSX quite a bit, I'm afraid.