GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/basic/GLSL.h
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 0 48 0.0%
Functions: 0 9 0.0%
Branches: 0 14 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_GFX_BASIC_GLSL
41 #define GEOGRAM_GFX_BASIC_GLSL
42
43 #include <geogram_gfx/basic/common.h>
44 #include <geogram/basic/numeric.h>
45
46 /**
47 * \file geogram_gfx/basic/GLSL.h
48 * \brief Utilities for manipulating GLSL shaders.
49 */
50
51 namespace GEO {
52
53 namespace GLSL {
54
55 /**
56 * \brief Initializes some GLSL functions and objects.
57 * \details Called by GEO::Graphics::initialize()
58 */
59 void GEOGRAM_GFX_API initialize();
60
61 /**
62 * \brief Terminates GLSL functions and objects.
63 * \details Called by GEO::Graphics::terminate()
64 */
65 void GEOGRAM_GFX_API terminate();
66
67 /**
68 * \brief Exception thrown when a GLSL shader fails to
69 * compiled.
70 * \details Can occur when OpenGL driver or hardware
71 * does not support some features.
72 */
73 struct GEOGRAM_GFX_API GLSLCompileError : std::exception {
74
75 /**
76 * \brief Gets the string identifying the exception
77 */
78 const char* what() const GEO_NOEXCEPT override;
79 };
80
81
82 /**
83 * \brief Gets the supported GLSL language version.
84 * \details The supported GLSL version is determined
85 * from hardware/driver capabilities and user-defined
86 * parameters.
87 */
88 double GEOGRAM_GFX_API supported_language_version();
89
90 /************************************************************/
91
92 /**
93 * \brief A GLSL source.
94 * \details Can be a pointer to a static string in constant memory
95 * or a dynamically created string.
96 */
97 class Source {
98 public:
99 /**
100 * \brief Source constructor.
101 */
102 Source() : text_(nullptr) {
103 }
104
105 /**
106 * \brief Source constructor from a char pointer.
107 * \param[in] src a pointer to the source text. Can be a constant
108 * string. It is not copied.
109 */
110 Source(const char* src) : text_(src) {
111 }
112
113 /**
114 * \brief Source constructor from a string.
115 * \param[in] src a const reference to a string. It is copied
116 * into this Source.
117 */
118 Source(const std::string& src) : text_string_(src) {
119 text_ = text_string_.c_str();
120 }
121
122 /**
123 * \brief Source copy constructor.
124 * \param[in] rhs a const reference to the Source to be copied
125 */
126 Source(const Source& rhs) {
127 copy(rhs);
128 }
129
130 /**
131 * \brief Source assignment operator.
132 * \param[in] rhs a const reference to the Source to be copied.
133 * \return this Source after assignment
134 */
135 Source& operator=(const Source& rhs) {
136 if(&rhs != this) {
137 copy(rhs);
138 }
139 return *this;
140 }
141
142 /**
143 * \brief Gets the text.
144 * \return a const pointer to the text of this source.
145 */
146 const char* text() {
147 return text_;
148 }
149
150 protected:
151 /**
152 * \brief Copies a Source.
153 * \param[in] rhs a const reference to the Source to be copied.
154 */
155 void copy(const Source& rhs) {
156 if(rhs.text_string_ != "") {
157 text_string_ = rhs.text_string_;
158 text_ = text_string_.c_str();
159 } else {
160 text_ = rhs.text_;
161 }
162 }
163
164 private:
165 const char* text_;
166 std::string text_string_;
167 };
168
169 /**
170 * \brief A class that can register functions to the GLSL
171 * pseudo file system.
172 * \details The GLSL pseudo file system manages the
173 * include directives.
174 */
175 class GEOGRAM_GFX_API PseudoFileProvider {
176 public:
177 /**
178 * \brief PseudoFileProvider destructor.
179 */
180 virtual ~PseudoFileProvider();
181 };
182
183 /**
184 * \brief A pointer to a function registered as a pseudo file
185 * in the GLSL pseudo file system.
186 * \details The GLSL pseudo file system manages the
187 * include directives. A PseudoFile is a pointer to a function
188 * that fills-in the file contents. The file contents is a vector
189 * of Source objects, that can be either constant string litterals
190 * or dynamically created strings.
191 */
192 typedef void (*PseudoFile)(
193 PseudoFileProvider* provider, std::vector<Source>& sources
194 );
195
196
197 /**
198 * \brief Registers a file in the GLSL pseudo file system.
199 * \details The file can then be included in a GLSL source
200 * with the //include <name> directive.
201 * \param[in] name the name of the pseudo file
202 * \param[in] source the GLSL source of the file
203 */
204 void GEOGRAM_GFX_API register_GLSL_include_file(
205 const std::string& name, const char* source
206 );
207
208 /**
209 * \brief Registers a pseudo file in the GLSL pseudo file system.
210 * \details The pseudo file can then be included in a GLSL source
211 * with the //include <name> directive. Each time it is included,
212 * it is generated by calling the specified function.
213 * \param[in] name the name of the pseudo file
214 * \param[in] file a pointer to a member function of an object
215 * derived from a PseudoFileProvider object that returns a string.
216 */
217 void GEOGRAM_GFX_API register_GLSL_include_file(
218 const std::string& name, PseudoFile file
219 );
220
221
222 /**
223 * \brief Gets a GLSL include file by file name.
224 * \details It needs to be a real file, registered as
225 * a pointer to static text data (not a PseudoFile).
226 * \param[in] name the name of the file in the pseudo
227 * file system.
228 * \return a const pointer to the contents of the file.
229 */
230 const char* get_GLSL_include_file(
231 const std::string& name
232 );
233
234 /**
235 * \brief Compiles a shader for a specific target.
236 * \details This version of compile_shader() supports the
237 * include directive through the GLSL pseudo file system.
238 * Errors are detected and displayed to std::err.
239 * \param[in] target the OpenGL shader target
240 * (one of GL_COMPUTE_SHADER,
241 * GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER,
242 * GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER)
243 * \param[in] source an ASCII string that contain
244 * the source of the shader
245 * \param[in] provider a pointer to an object that implements
246 * the PseudoFileProvider interface (typically a GLUP Context)
247 * \return the OpenGL opaque Id of the created shader object
248 * \throw GLSLCompileError if the shader could not be compiled
249 */
250 GLuint GEOGRAM_GFX_API compile_shader_with_includes(
251 GLenum target, const char* source, PseudoFileProvider* provider
252 );
253
254
255 /**
256 * \brief Compiles a program from shader sources.
257 * \param[in] provider a pointer to an object that implements
258 * the PseudoFileProvider interface (typically a GLUP Context)
259 * \param[in] shader1 , shader2 , shader3 , shader4 , shader5 ,
260 * shader6 up to six shader sources definition.
261 * Each shader source definition should begin
262 * with //stage STAGE where STAGE is one of GL_VERTEX_SHADER,
263 * GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESSELLATION_SHADER,
264 * GL_TESS_EVALUATION_SHADER
265 * \return the OpenGL opaque Id of the created program object
266 * \throw GLSLCompileError if the shaders could not be compiled
267 */
268 GLuint GEOGRAM_GFX_API compile_program_with_includes_no_link(
269 PseudoFileProvider* provider,
270 const char* shader1, const char* shader2 = nullptr,
271 const char* shader3 = nullptr, const char* shader4 = nullptr,
272 const char* shader5 = nullptr, const char* shader6 = nullptr
273 );
274
275
276 /************************************************************/
277
278 /**
279 * \brief Compiles a shader for a specific target.
280 * \details One can split the source of the shader into
281 * different strings, one of them being used for library
282 * functions common to different shaders.
283 * It may seem more natural to generate a shader object with library
284 * functions, but OpenGL documentation does not recommend
285 * to do so (and it did not seem to work). Errors are detected and
286 * displayed to std::err.
287 * \param[in] target the OpenGL shader target
288 * (one of GL_COMPUTE_SHADER,
289 * GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER,
290 * GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER)
291 * \param[in] sources an array of pointer to ASCII strings
292 * that contain the source of the shader
293 * \param[in] nb_sources number of strings in \p sources
294 * \return the OpenGL opaque Id of the created shader object
295 * \throw GLSLCompileError if the shader could not be compiled
296 */
297 GLuint GEOGRAM_GFX_API compile_shader(
298 GLenum target, const char** sources, index_t nb_sources
299 );
300
301 /**
302 * \brief Compiles a shader for a specific target.
303 * \details One can split the source of the shader into
304 * different strings, one of them being used for library
305 * functions common to different shaders.
306 * It may seem more natural to generate a shader object with library
307 * functions, but OpenGL documentation does not recommend
308 * to do so (and it did not seem to work). Errors are detected and
309 * displayed to std::err.
310 * \param[in] target the OpenGL shader target
311 * (one of GL_COMPUTE_SHADER,
312 * GL_VERTEX_SHADER, GL_TESS_CONTROL_SHADER,
313 * GL_TESS_EVALUATION_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADER)
314 * \param[in] source1 , source2 , ... ASCII strings that will be
315 * concatened to form the source of the shader. It needs to be
316 * terminated by 0.
317 * \return the OpenGL opaque Id of the created shader object
318 * \throw GLSLCompileError if the shader could not be compiled
319 * \note Could have been implemented using varargs, but I had
320 * problems with it (crashes that I could not fix), and it is
321 * not recommended anyway (does not have typechecking).
322 */
323 GLuint GEOGRAM_GFX_API compile_shader(
324 GLenum target,
325 const char* source1,
326 const char* source2,
327 const char* source3 = nullptr,
328 const char* source4 = nullptr,
329 const char* source5 = nullptr,
330 const char* source6 = nullptr,
331 const char* source7 = nullptr,
332 const char* source8 = nullptr,
333 const char* source9 = nullptr,
334 const char* source10 = nullptr,
335 const char* source11 = nullptr,
336 const char* source12 = nullptr,
337 const char* source13 = nullptr,
338 const char* source14 = nullptr,
339 const char* source15 = nullptr,
340 const char* source16 = nullptr,
341 const char* source17 = nullptr,
342 const char* source18 = nullptr,
343 const char* source19 = nullptr,
344 const char* source20 = nullptr
345 );
346
347
348 /**
349 * \brief Links a program.
350 * \details Errors are detexted and displayed to the Logger.
351 * \param[in] program the program to be linked
352 */
353 void GEOGRAM_GFX_API link_program(GLuint program);
354
355 /**
356 * \brief Creates a GLSL program from a zero-terminated
357 * list of shaders
358 * \details Errors are detected and displayed to the Logger.
359 * \note link_program() needs to be called after.
360 * If the program has vertex attributes, then
361 * glBindAttribLocation() needs to be called after
362 * create_program_from_shaders_no_link() and before
363 * link_program().
364 * \param[in] shader the first shader of the list
365 * \return the OpenGL opaque Id of the created program
366 */
367 GLuint GEOGRAM_GFX_API create_program_from_shaders_no_link(
368 GLuint shader, ...
369 );
370
371 /**
372 * \brief Creates a GLSL program from a zero-terminated
373 * list of shaders
374 * \details Errors are detected and displayed to the Logger.
375 * \note If the program has vertex attributes and needs
376 * glBindAttribLocation(), then use
377 * create_program_from_shaders_no_link() instead.
378 * \param[in] shader the first shader of the list
379 * \return the OpenGL opaque Id of the created program
380 */
381 GLuint GEOGRAM_GFX_API create_program_from_shaders(GLuint shader, ...);
382
383 /**
384 * \brief Creates a GLSL program from a string.
385 * \details The string may contain several shaders. Each shader
386 * is delimited by begin-end statements:
387 * #begin(SHADER_TYPE) / #end(SHADER_TYPE)
388 * where SHADER_TYPE is one of GL_VERTEX_SHADER, GL_FRAGMENT_SHADER,
389 * GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER,
390 * GL_TESS_EVALUATION_SHADER.
391 * \note link_program() needs to be called after.
392 * \param[in,out] string the combined shaders that constitute the
393 * program.
394 * \param[in] copy_string if true, the input string is copied
395 * internally. The function temporarily modifies the input string
396 * (and then restores it on exit). This may
397 * be forbidden when input string is a constant char array
398 * (string litteral in source code). In this case, the input
399 * string is copied to a temporary buffer.
400 * \return the OpenGL opaque Id of the created shader object
401 * \throw GLSLCompileError if the shader could not be compiled
402 */
403 GLuint GEOGRAM_GFX_API create_program_from_string_no_link(
404 const char* string, bool copy_string = true
405 );
406
407 /**
408 * \brief Creates a GLSL program from a file.
409 * \details The file contains a list of shaders, delimited by
410 * begin-end statements (see setup_program_from_string()).
411 * \note link_program() needs to be called after.
412 * \param[in] filename the name of the file
413 * \throw GLSLCompileError if the shader could not be compiled
414 */
415 GLuint GEOGRAM_GFX_API create_program_from_file_no_link(
416 const std::string& filename
417 );
418
419 /**
420 * \brief Sets a uniform variable in a shader by name.
421 * \param[in] shader_id the handle to the GLSL shader
422 * \param[in] name the name of the uniform variable,
423 * as specified in the GLSL source of the shader.
424 * \param[in] val the value of the parameter
425 * \tparam T the type of the parameter. Needs to match
426 * the type of the uniform parameter in the GLSL source.
427 */
428 template <class T> inline bool set_program_uniform_by_name(
429 GLuint shader_id, const char* name, T val
430 ) {
431 geo_argused(shader_id);
432 geo_argused(name);
433 geo_argused(val);
434 geo_assert_not_reached;
435 return false;
436 }
437
438 template<> inline bool set_program_uniform_by_name(
439 GLuint shader_id, const char* name, bool val
440 ) {
441 GLint location = glGetUniformLocation(shader_id, name) ;
442 if(location < 0) {
443 return false ;
444 }
445 glUseProgram(shader_id);
446 glUniform1i(location, val ? 1 : 0) ;
447 glUseProgram(0);
448 return true;
449 }
450
451 template<> inline bool set_program_uniform_by_name(
452 GLuint shader_id, const char* name, float val
453 ) {
454 GLint location = glGetUniformLocation(shader_id, name) ;
455 if(location < 0) {
456 return false ;
457 }
458 glUseProgram(shader_id);
459 glUniform1f(location, val) ;
460 glUseProgram(0);
461 return true;
462 }
463
464 template<> inline bool set_program_uniform_by_name(
465 GLuint shader_id, const char* name, double val
466 ) {
467 GLint location = glGetUniformLocation(shader_id, name) ;
468 if(location < 0) {
469 return false ;
470 }
471 glUseProgram(shader_id);
472 glUniform1f(location, float(val)) ;
473 glUseProgram(0);
474 return true;
475 }
476
477 template<> inline bool set_program_uniform_by_name(
478 GLuint shader_id, const char* name, int val
479 ) {
480 GLint location = glGetUniformLocation(shader_id, name) ;
481 if(location < 0) {
482 return false ;
483 }
484 glUseProgram(shader_id);
485 glUniform1i(location, val) ;
486 glUseProgram(0);
487 return true;
488 }
489
490
491 template<> inline bool set_program_uniform_by_name(
492 GLuint shader_id, const char* name, unsigned int val
493 ) {
494 GLint location = glGetUniformLocation(shader_id, name) ;
495 if(location < 0) {
496 return false ;
497 }
498 glUseProgram(shader_id);
499 #ifdef GEO_GL_150
500 glUniform1ui(location, val) ;
501 #else
502 glUniform1i(location, GLint(val)) ;
503 #endif
504 glUseProgram(0);
505 return true;
506 }
507
508 /**
509 * \brief Sets an array of uniform variables in a shader by name.
510 * \param[in] shader_id the handle to the GLSL shader
511 * \param[in] name the name of the uniform variable,
512 * as specified in the GLSL source of the shader.
513 * \param[in] count number of values
514 * \param[in] values a pointer to an array of values of size count
515 */
516 inline bool set_program_uniform_by_name(
517 GLuint shader_id, const char* name, index_t count, float* values
518 ) {
519 GLint location = glGetUniformLocation(shader_id, name) ;
520 if(location < 0) {
521 return false ;
522 }
523 glUseProgram(shader_id);
524 glUniform1fv(location, GLsizei(count), values) ;
525 glUseProgram(0);
526 return true;
527 }
528
529 inline bool set_program_uniform_by_name(
530 GLuint shader_id, const char* name, float x, float y
531 ) {
532 GLint location = glGetUniformLocation(shader_id, name) ;
533 if(location < 0) {
534 return false ;
535 }
536 glUseProgram(shader_id);
537 glUniform2f(location, x, y);
538 glUseProgram(0);
539 return true;
540 }
541
542 /**
543 * \brief Gets the offset of a uniform variable relative
544 * to the uniform block it is declared in.
545 * \param[in] program a GLSL program handle
546 * \param[in] varname the name of the variable
547 * \return the offset of the variable relative to the beginning
548 * of the uniform block it is declared in, in bytes.
549 */
550 GLint GEOGRAM_GFX_API get_uniform_variable_offset(
551 GLuint program, const char* varname
552 );
553
554 /**
555 * \brief Queries array stride for a variable in a
556 * GLSL program using introspection.
557 * \param[in] program the handle of the program
558 * \param[in] varname a string with the name of the array variable
559 * \return the number of bytes between two consecutive elements of the
560 * array.
561 */
562 size_t GEOGRAM_GFX_API get_uniform_variable_array_stride(
563 GLuint program, const char* varname
564 );
565
566 /**
567 * \brief Outputs to the logger everything that can
568 * be queried about a program using OpenGL
569 * introspection APIs.
570 */
571 void GEOGRAM_GFX_API introspect_program(GLuint program);
572
573 }
574 }
575
576 #endif
577