Class ShaderProgramManager

Class Documentation

class ShaderProgramManager

Manages the lifecycle and caching of OpenGL shader programs.

This class centralizes shader program management for the entire rendering system. It provides:

  • Lazy loading: Shaders are compiled on first use

  • Caching: Each shader is compiled once and reused

  • Automatic cleanup: Programs are destroyed when manager is destroyed

  • Thread safety: All operations must be on the OpenGL context thread

  • Custom shader support: Load shaders from source code or files

The manager handles both built-in default shaders (from DefaultShaders.h) and user-defined custom shaders.

Typical usage:

ShaderProgramManager shaderMgr;

// Get a built-in shader (compiled on first request):
auto pointsShader = shaderMgr.getProgram(DefaultShaderID::POINTS);
pointsShader->use();

// Load a custom shader:
auto customShader = shaderMgr.loadCustomProgram(
    "myShader",
    vertexShaderSource,
    fragmentShaderSource);

Thread safety:

  • This class is NOT thread-safe

  • All operations must be called from the OpenGL context thread

  • Violating this will cause OpenGL errors or crashes

See also

Program, Shader, DefaultShaders.h, CompiledScene

Built-in Shader Access

Program::Ptr getProgram(shader_id_t id)

Retrieves a built-in shader program by ID.

If the shader hasn’t been compiled yet, it is compiled on first access. Subsequent calls return the cached program.

Note

This must be called from the OpenGL context thread

Note

The returned pointer remains valid as long as this manager exists

Parameters:

id – The shader ID (from DefaultShaderID enum)

Throws:

std::runtime_error – if shader compilation fails

Returns:

Shared pointer to the program, or nullptr on compilation failure

bool hasProgram(shader_id_t id) const

Checks if a shader program has been compiled and cached.

Parameters:

id – The shader ID to check

Returns:

true if program exists in cache, false otherwise

void overrideBuiltinProgram(shader_id_t id, Program::Ptr program)

Replaces (or installs) a built-in shader slot with a custom compiled program.

Use this to override one of the standard MRPT shaders (e.g. DefaultShaderID::TRIANGLES_NO_LIGHT) with a custom Program you have compiled yourself. The new program will be used for all subsequent render calls that request id.

Note

Must be called from the OpenGL context thread.

size_t preloadAllDefaultShaders(std::vector<std::string> *outErrors = nullptr)

Preloads all default shaders.

By default, shaders are compiled lazily. Call this to compile all built-in shaders at initialization time, which can help avoid stuttering during first render.

Note

This can take 100-500ms depending on GPU/driver

Parameters:

outErrors – Optional vector to receive compilation errors

Returns:

Number of shaders successfully compiled

Custom Shader Management

Program::Ptr loadCustomProgram(const std::string &name, const std::string &vertexShaderSource, const std::string &fragmentShaderSource, const std::string &geometryShaderSource = "", std::string *outErrorMsg = nullptr)

Loads a custom shader program from source code.

The shader is compiled and linked immediately. If successful, it is cached and can be retrieved later by name.

Example:

const char* vertSrc = R"(
  #version 330 core
  layout(location = 0) in vec3 position;
  uniform mat4 pmv_matrix;
  void main() {
    gl_Position = pmv_matrix * vec4(position, 1.0);
  }
)";

const char* fragSrc = R"(
  #version 330 core
  out vec4 color;
  void main() {
    color = vec4(1.0, 0.0, 0.0, 1.0);
  }
)";

auto prog = shaderMgr.loadCustomProgram("redShader", vertSrc, fragSrc);

Parameters:
  • name – Unique name for this custom shader

  • vertexShaderSource – GLSL source code for vertex shader

  • fragmentShaderSource – GLSL source code for fragment shader

  • geometryShaderSource – Optional GLSL source for geometry shader

  • outErrorMsg – Optional string to receive compilation/link errors

Throws:

std::runtime_error – if name already exists

Returns:

Shared pointer to program, or nullptr on failure

Program::Ptr loadCustomProgramFromFiles(const std::string &name, const std::string &vertexShaderFile, const std::string &fragmentShaderFile, const std::string &geometryShaderFile = "", std::string *outErrorMsg = nullptr)

Loads a custom shader program from files.

Convenience wrapper that reads shader source from files.

Parameters:
  • name – Unique name for this custom shader

  • vertexShaderFile – Path to vertex shader (.vert, .vs, etc.)

  • fragmentShaderFile – Path to fragment shader (.frag, .fs, etc.)

  • geometryShaderFile – Optional path to geometry shader (.geom, .gs)

  • outErrorMsg – Optional string to receive errors

Returns:

Shared pointer to program, or nullptr on failure

Program::Ptr getCustomProgram(const std::string &name) const

Retrieves a custom shader by name.

Parameters:

name – The name given when loading the shader

Returns:

Shared pointer to program, or nullptr if not found

bool hasCustomProgram(const std::string &name) const

Checks if a custom shader exists.

Parameters:

name – The shader name to check

Returns:

true if custom shader exists, false otherwise

bool removeCustomProgram(const std::string &name)

Removes a custom shader from the cache.

The program is destroyed if no other references exist.

Parameters:

name – Name of shader to remove

Returns:

true if shader was found and removed, false if not found

Shader Variants (for Shadow Mapping)

shader_id_t getShaderVariant(shader_id_t baseShaderID, bool isShadowMapPass) const

Retrieves the appropriate shader variant for the current render pass.

Shadow rendering requires different shaders for different passes:

  • 1st pass (shadow map generation): depth-only shaders

  • 2nd pass (normal rendering): shaders that sample shadow map

This method automatically selects the right variant based on the base shader ID and render pass.

Example mappings:

  • TRIANGLES_LIGHT + shadowMapPass=true → TRIANGLES_SHADOW_1ST

  • TRIANGLES_LIGHT + shadowMapPass=false → TRIANGLES_SHADOW_2ND

  • POINTS + shadowMapPass=true → NONE (points don’t cast shadows)

  • WIREFRAME + shadowMapPass=false → WIREFRAME (no shadow variant)

Parameters:
  • baseShaderID – The base shader (e.g., TRIANGLES_LIGHT)

  • isShadowMapPass – true for 1st pass, false for 2nd pass

Returns:

The appropriate shader variant

Utility Methods

void clear()

Clears all cached programs (built-in and custom).

Forces recompilation on next access. Useful for shader hot-reloading during development.

Warning

All existing Program::Ptr references become invalid

inline size_t getBuiltinProgramCount() const

Returns number of cached built-in programs

inline size_t getCustomProgramCount() const

Returns number of cached custom programs

inline size_t getTotalProgramCount() const

Returns total number of cached programs

std::vector<shader_id_t> getLoadedShaderIDs() const

Lists all loaded shader IDs (built-in).

Returns:

Vector of shader IDs currently in cache

std::vector<std::string> getLoadedCustomShaderNames() const

Lists all loaded custom shader names.

Returns:

Vector of custom shader names currently in cache

inline void setVerbose(bool verbose)

Enables/disables verbose logging of shader compilation.

When enabled, compilation success/failure is logged to stdout. Default: false

inline bool isVerbose() const

Returns current verbose setting

Public Functions

ShaderProgramManager()

Constructor.

Does not compile any shaders yet - they are loaded lazily on first use.

~ShaderProgramManager()

Destructor.

Automatically cleans up all shader programs. Must be called from the same thread that created the shaders (OpenGL context thread).

ShaderProgramManager(const ShaderProgramManager&) = delete
ShaderProgramManager &operator=(const ShaderProgramManager&) = delete
ShaderProgramManager(ShaderProgramManager&&) = delete
ShaderProgramManager &operator=(ShaderProgramManager&&) = delete