Skip to content

Commit

Permalink
[GL] Mapping of name to active GL uniform location.
Browse files Browse the repository at this point in the history
The location returned by glGetUniformLocation() must be used for gl*Uniform*() functions only, not as index for glGetActiveUniform().
This change builds a full map that maps a name to its active GL uniform type and array size.
  • Loading branch information
LukasBanana committed Jun 21, 2024
1 parent a8f83f3 commit 4c1e085
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 23 deletions.
95 changes: 73 additions & 22 deletions sources/Renderer/OpenGL/RenderState/GLPipelineState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,59 @@ void GLPipelineState::BuildUniformMap(GLShader::Permutation permutation, const s
{
const GLuint program = shaderPipelines_[permutation]->GetID();

/* Build name-to-index map of all active uniforms, since glGetUniformLocation() does *not* map to the active uniform index */
GLNameToUniformMap nameToUniformMap;
BuildNameToActiveUniformMap(program, nameToUniformMap);

/* Build uniform locations from input descriptors */
uniformMap_.resize(uniforms.size());
for_range(i, uniforms.size())
BuildUniformLocation(program, uniformMap_[i], uniforms[i]);
BuildUniformLocation(program, uniformMap_[i], uniforms[i], nameToUniformMap);
}
}

/*
Returns the name of an active GL uniform as an identifier, i.e. removing any subscripts.
Arrays of uniforms are reflected with a subscript for the first entry,
e.g. "uniform inputTextures[2];" yields the active uniform name "inputTextures[0]".
This functions removes the subscript, effecitvely returning "inputTextures" for this example.
*/
static std::string GetActiveUniformNameAsIdent(const GLchar* uniformName)
{
std::string ident{ uniformName };
const std::size_t subscriptStartPos = ident.find('[');
if (subscriptStartPos != std::string::npos)
return ident.substr(0, subscriptStartPos);
return ident;
}

void GLPipelineState::BuildNameToActiveUniformMap(GLuint program, GLNameToUniformMap& outNameToUniformMap)
{
/* Determine number of active GL uniforms */
GLint numActiveUniforms = 0;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
if (numActiveUniforms <= 0)
return;

/* Determine buffer size for largest GL uniform name */
GLint maxUniformNameLength = 0;
glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformNameLength);
if (maxUniformNameLength <= 0)
return;

/* Reserve memory to iterate over all active GL uniforms */
std::vector<GLchar> uniformName;
uniformName.resize(maxUniformNameLength, '\0');

outNameToUniformMap.reserve(static_cast<std::size_t>(numActiveUniforms));

/* Build name-to-index map for all active GL uniforms */
for_range(i, static_cast<GLuint>(numActiveUniforms))
{
GLActiveUniform uniform = {};
glGetActiveUniform(program, i, static_cast<GLsizei>(uniformName.size()), nullptr, &uniform.size, &uniform.type, &uniformName[0]);
const std::string uniformIdent = GetActiveUniformNameAsIdent(uniformName.data());
outNameToUniformMap[uniformIdent] = uniform;
}
}

Expand Down Expand Up @@ -184,31 +233,33 @@ static GLuint GetUniformWordSize(GLenum type)
}
}

void GLPipelineState::BuildUniformLocation(GLuint program, GLUniformLocation& outUniform, const UniformDescriptor& inUniform)
void GLPipelineState::BuildUniformLocation(
GLuint program,
GLUniformLocation& outUniform,
const UniformDescriptor& inUniform,
const GLNameToUniformMap& nameToUniformMap)
{
/* Initialize output with invalid uniform location */
outUniform.type = UniformType::Undefined;
outUniform.location = -1;
outUniform.count = 0;
outUniform.wordSize = 0;

/* Find uniform location by name in shader pipeline */
GLint location = glGetUniformLocation(program, inUniform.name.c_str());
if (location == -1)
{
/* Write invalid uniform location */
outUniform.type = UniformType::Undefined;
outUniform.location = -1;
outUniform.count = 0;
outUniform.wordSize = 0;
}
else
{
/* Determine type of uniform */
GLenum type = 0;
GLint size = 0;
glGetActiveUniform(program, static_cast<GLuint>(location), 0, nullptr, &size, &type, nullptr);

/* Write output uniform */
outUniform.type = GLTypes::UnmapUniformType(type);
outUniform.location = location;
outUniform.count = size;
outUniform.wordSize = GetUniformWordSize(type);
}
return;

/* Determine type of uniform */
auto it = nameToUniformMap.find(inUniform.name);
if (it == nameToUniformMap.end())
return;

/* Write output uniform */
outUniform.type = GLTypes::UnmapUniformType(it->second.type);
outUniform.location = location;
outUniform.count = it->second.size;
outUniform.wordSize = GetUniformWordSize(it->second.type);
}


Expand Down
22 changes: 21 additions & 1 deletion sources/Renderer/OpenGL/RenderState/GLPipelineState.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <LLGL/RenderSystemFlags.h>
#include <LLGL/Container/ArrayView.h>
#include <memory>
#include <unordered_map>


namespace LLGL
Expand Down Expand Up @@ -95,13 +96,32 @@ class GLPipelineState : public PipelineState
return report_;
}

private:

struct GLActiveUniform
{
GLint size;
GLenum type;
};

// Maps a name to its active GL uniform.
using GLNameToUniformMap = std::unordered_map<std::string, GLActiveUniform>;

private:

// Builds the index-to-uniform map.
void BuildUniformMap(GLShader::Permutation permutation, const std::vector<UniformDescriptor>& uniforms);

// Builds the container that maps a name to the index of its active GL uniform.
void BuildNameToActiveUniformMap(GLuint program, GLNameToUniformMap& outNameToUniformMap);

// Builds the specified uniform location.
void BuildUniformLocation(GLuint program, GLUniformLocation& outUniform, const UniformDescriptor& inUniform);
void BuildUniformLocation(
GLuint program,
GLUniformLocation& outUniform,
const UniformDescriptor& inUniform,
const GLNameToUniformMap& nameToUniformMap
);

private:

Expand Down

0 comments on commit 4c1e085

Please sign in to comment.