class mrpt::opengl::ShaderProgramManager

Overview

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

#include <mrpt/opengl/ShaderProgramManager.h>

class ShaderProgramManager
{
public:
    // construction

    ShaderProgramManager();
    ShaderProgramManager(const ShaderProgramManager&);
    ShaderProgramManager(ShaderProgramManager&&);

    // methods

    Program::Ptr getProgram(shader_id_t id);
    bool hasProgram(shader_id_t id) const;
    void overrideBuiltinProgram(shader_id_t id, Program::Ptr program);
    size_t preloadAllDefaultShaders(std::vector<std::string>* outErrors = nullptr);

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

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

    Program::Ptr getCustomProgram(const std::string& name) const;
    bool hasCustomProgram(const std::string& name) const;
    bool removeCustomProgram(const std::string& name);
    shader_id_t getShaderVariant(shader_id_t baseShaderID, bool isShadowMapPass) const;
    void clear();
    size_t getBuiltinProgramCount() const;
    size_t getCustomProgramCount() const;
    size_t getTotalProgramCount() const;
    std::vector<shader_id_t> getLoadedShaderIDs() const;
    std::vector<std::string> getLoadedCustomShaderNames() const;
    void setVerbose(bool verbose);
    bool isVerbose() const;
    ShaderProgramManager& operator = (const ShaderProgramManager&);
    ShaderProgramManager& operator = (ShaderProgramManager&&);
};

Construction

ShaderProgramManager()

Constructor.

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

Methods

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.

This must be called from the OpenGL context thread

The returned pointer remains valid as long as this manager exists

Parameters:

id

The shader ID (from DefaultShaderID enum)

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.

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.

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

Parameters:

outErrors

Optional vector to receive compilation errors

Returns:

Number of shaders successfully compiled

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

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_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

void clear()

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

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

All existing Program::Ptr references become invalid

size_t getBuiltinProgramCount() const

Returns number of cached built-in programs.

size_t getCustomProgramCount() const

Returns number of cached custom programs.

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

void setVerbose(bool verbose)

Enables/disables verbose logging of shader compilation.

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

bool isVerbose() const

Returns current verbose setting.