What Preprocessor Directives Does GLSL Support?
The OpenGL Shading Language (GLSL) features a built-in preprocessor
closely modeled on the standard C/C++ preprocessor, used to control
compilation conditionally, define macros, enforce language versions, and
manage hardware extensions. While it supports familiar operations like
conditional branching and macro expansion, it includes GLSL-specific
directives like #version and #extension, while
omitting standard features like #include from the core
specification.
Macro Definition and Undefinition
GLSL allows basic macro replacement and parameterized macros across shader code.
#define: Defines a macro identifier or a function-like macro. Macro definitions do not evaluate types and perform direct token substitution.#undef: Undefines an existing macro identifier, removing its definition from subsequent shader lines.
GLSL also provides standard predefined macros, such as
__LINE__, __FILE__, __VERSION__,
and GL_core_profile (or GL_es_profile), which
allow shaders to adapt dynamically to their execution context.
Conditional Compilation
Conditional directives enable shaders to include or exclude blocks of code based on macro definitions or integer constant expressions.
#if: Evaluates an integer constant expression. Non-zero evaluates to true.#ifdef: Checks if a specific macro has been defined.#ifndef: Checks if a specific macro has not been defined.#elif: Short for "else if," evaluated if preceding#ifor#elifconditions fail.#else: Executes if all preceding condition branches evaluate to false.#endif: Terminates a conditional compilation block.defined: A preprocessor operator used inside#ifor#elifexpressions (e.g.,defined(FEATURE_FLAG)) to evaluate whether a macro name is defined.
Floating-point operations and typecasts are not permitted within GLSL preprocessor conditional expressions; only integer constant expressions and operators (such as arithmetic, bitwise, and logical operators) are valid.
Version Declaration:
#version
The #version directive is mandatory for modern GLSL and
informs the driver which specification version to use when parsing the
shader.
- Syntax:
#version number [profile] - Placement: Must be the first non-comment, non-whitespace statement in the shader source string.
- Profiles: On desktop OpenGL 3.3 and higher, an
optional profile argument can be specified (
core,compatibility, ores).
For example, #version 330 core specifies version 3.30
using the core profile, whereas #version 300 es designates
OpenGL ES 3.0.
Extension Handling:
#extension
The #extension directive controls compiler behavior
regarding optional or vendor-specific GLSL capabilities.
- Syntax:
#extension extension_name : behavior - Target:
extension_namecan be a specific extension (e.g.,GL_ARB_gpu_shader5) orallto apply a rule across all available extensions. - Behaviors:
require: Fails compilation with an error if the extension is not supported.enable: Enables the extension if supported; issues a warning if unsupported.warn: Enables the extension if supported, but emits a compiler warning whenever the extension is used.disable: Disables use of the extension and emits an error if any of its features are referenced.
Diagnostic and Line Control Directives
GLSL includes directives to adjust compiler error tracking and report custom compilation errors.
#error: Halts compilation immediately and prints the supplied token message to the shader compilation info log.#line: Resets the internal line number and optionally the source string index tracked by the compiler (#line line_number [source_string_number]). This is useful when host applications concatenate multiple source strings or generate code dynamically.
Compiler Pragma Controls:
#pragma
The #pragma directive passes implementation-specific
instructions to the shader compiler. Standard GLSL specifications define
several reserved pragmas:
#pragma STDGL: Reserved for standard GLSL pragma configurations.#pragma optimize(on)/#pragma optimize(off): Directs the compiler to enable or disable optimization passes (primarily used for debugging).#pragma debug(on)/#pragma debug(off): Requests debug instrumentation from the driver to assist external shader debuggers.#pragma invariant(all): Forces all output variables in the shader stage to be treated with invariant qualification, guaranteeing identical calculations across different shaders.
Omitted Directives
The core GLSL specification does not include a standard
#include directive. Shader file composition, module
management, and header inclusions must either be resolved on the CPU
before passing the shader string to glShaderSource, or
handled using specialized extensions like
GL_ARB_shading_language_include or
GL_GOOGLE_include_directive where driver and runtime
support exist.