1 module gfm.opengl.uniform;
2 
3 import std.conv, 
4        std..string,
5        core.stdc..string;
6 
7 import derelict.opengl3.gl3;
8 
9 import gfm.math.vector, 
10        gfm.math.matrix,
11        gfm.opengl.opengl;
12 
13 
14 /// Represents an OpenGL program uniform. Owned by a GLProgram.
15 /// Both uniform locations and values are cached, to minimize OpenGL calls.
16 final class GLUniform
17 {
18     public
19     {
20         /// Creates a GLUniform.
21         /// This is done automatically after linking a GLProgram.
22         /// See_also: GLProgram.
23         /// Throws: $(D OpenGLException) on error.
24         this(OpenGL gl, GLuint program, GLenum type, string name, GLsizei size)
25         {
26             _gl = gl;
27             _type = type;
28             _size = size;
29             _name = name;
30 
31             _location = glGetUniformLocation(program, toStringz(name));
32             if (_location == -1)
33             {
34                 // probably rare: the driver said explicitely this variable was active, and there it's not.
35                 throw new OpenGLException(format("can't get uniform %s location", name));
36             }
37 
38             size_t cacheSize = sizeOfUniformType(type) * size;
39             if (cacheSize > 0)
40             {
41                 _value = new ubyte[cacheSize]; // relying on zero initialization here
42                 _valueChanged = false;
43 
44                 _firstSet = true;
45                 _disabled = false;
46             }
47             else
48             {
49                 _gl._logger.warningf("uniform %s is unrecognized or has size 0, disabled", _name);
50                 _disabled = true;
51             }
52         }
53 
54         /// Creates a fake disabled uniform variable, designed to cope with variables 
55         /// that have been optimized out by the OpenGL driver, or those which do not exist.
56         this(OpenGL gl, string name)
57         {
58             _gl = gl;
59             _disabled = true;
60             _gl._logger.warningf("Faking uniform '%s' which either does not exist in the shader program, or was discarded by the driver as unused", name);
61         }
62 
63         /// Sets a uniform variable value.
64         /// T should be the exact type needed, checked at runtime.
65         /// Throws: $(D OpenGLException) on error.
66         void set(T)(T newValue)
67         {
68             set!T(&newValue, 1u);
69         }
70 
71         /// Sets multiple uniform variables.
72         /// Throws: $(D OpenGLException) on error.
73         void set(T)(T[] newValues)
74         {
75             set!T(newValues.ptr, newValues.length);
76         }
77 
78         /// Sets multiple uniform variables.
79         /// Throws: $(D OpenGLException) on error.
80         void set(T)(T* newValues, size_t count)
81         {
82             if (_disabled)
83                 return;
84 
85             // special case so that GL_BOOL variable can be assigned when T is bool
86             static if (is(T == bool))
87             {
88                 assert(_type == GL_BOOL); // else we would have thrown
89                 assert(count == 1);  // else we would have thrown
90                 set!int( cast(int)(*newValues) );
91                 return;
92             }
93             else
94             {
95                 if (!typeIsCompliant!T(_type))
96                     throw new OpenGLException(format("using type %s for setting uniform '%s' which has GLSL type '%s'", 
97                                                      T.stringof, _name, GLSLTypeNameArray(_type, _size)));
98 
99                 if (count != _size)
100                     throw new OpenGLException(format("cannot set uniform '%s' of size %s with a value of size %s", 
101                                                      _name, _size, count));
102 
103                 // if first time or different value incoming
104                 if (_firstSet || (0 != memcmp(newValues, _value.ptr, _value.length)))
105                 {
106                     memcpy(_value.ptr, newValues, _value.length);
107                     _valueChanged = true;
108 
109                     if (_shouldUpdateImmediately)
110                         update();
111                 }
112 
113                 _firstSet = false;
114             }
115         }
116     
117         /// Updates the uniform value.
118         void use()
119         {
120             _shouldUpdateImmediately = true;
121             update();
122         }       
123 
124         /// Unuses this uniform.
125         void unuse()
126         {
127             _shouldUpdateImmediately = false;
128         }
129 
130         /// Returns: Uniform name.
131         string name()
132         {
133             return _name;
134         }
135     }
136 
137     private
138     {
139         OpenGL _gl;
140         GLint _location;
141         GLenum _type;
142         GLsizei _size;
143         ubyte[] _value;
144         bool _valueChanged;
145         bool _firstSet; // force update to ensure we do not relie on the driver initializing uniform to zero
146         bool _disabled; // allow transparent usage while not doing anything
147         bool _shouldUpdateImmediately;
148         string _name;
149 
150         void update()
151         {
152             if (_disabled)
153                 return;
154 
155             // safety check to prevent defaults values in uniforms
156             if (_firstSet)
157             {
158                 _gl._logger.warningf("uniform '%s' left to default value, driver will probably zero it", _name);
159                 _firstSet = false;
160             }
161 
162             // has value changed?
163             // if so, set OpenGL value
164             if (_valueChanged)
165             {
166                 setUniform();
167                 _valueChanged = false;
168             }
169         }
170 
171         void setUniform()
172         {
173             switch(_type)
174             {
175                 case GL_FLOAT:      glUniform1fv(_location, _size, cast(GLfloat*)_value); break;
176                 case GL_FLOAT_VEC2: glUniform2fv(_location, _size, cast(GLfloat*)_value); break;
177                 case GL_FLOAT_VEC3: glUniform3fv(_location, _size, cast(GLfloat*)_value); break;
178                 case GL_FLOAT_VEC4: glUniform4fv(_location, _size, cast(GLfloat*)_value); break;
179                 case GL_DOUBLE:      glUniform1dv(_location, _size, cast(GLdouble*)_value); break;
180                 case GL_DOUBLE_VEC2: glUniform2dv(_location, _size, cast(GLdouble*)_value); break;
181                 case GL_DOUBLE_VEC3: glUniform3dv(_location, _size, cast(GLdouble*)_value); break;
182                 case GL_DOUBLE_VEC4: glUniform4dv(_location, _size, cast(GLdouble*)_value); break;
183                 case GL_INT:      glUniform1iv(_location, _size, cast(GLint*)_value); break;
184                 case GL_INT_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break;
185                 case GL_INT_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break;
186                 case GL_INT_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break;
187                 case GL_UNSIGNED_INT:      glUniform1uiv(_location, _size, cast(GLuint*)_value); break;
188                 case GL_UNSIGNED_INT_VEC2: glUniform2uiv(_location, _size, cast(GLuint*)_value); break;
189                 case GL_UNSIGNED_INT_VEC3: glUniform3uiv(_location, _size, cast(GLuint*)_value); break;
190                 case GL_UNSIGNED_INT_VEC4: glUniform4uiv(_location, _size, cast(GLuint*)_value); break;
191                 case GL_BOOL:      glUniform1iv(_location, _size, cast(GLint*)_value); break;
192                 case GL_BOOL_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break;
193                 case GL_BOOL_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break;
194                 case GL_BOOL_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break;
195                 case GL_FLOAT_MAT2:   glUniformMatrix2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
196                 case GL_FLOAT_MAT3:   glUniformMatrix3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
197                 case GL_FLOAT_MAT4:   glUniformMatrix4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
198                 case GL_FLOAT_MAT2x3: glUniformMatrix2x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
199                 case GL_FLOAT_MAT2x4: glUniformMatrix3x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
200                 case GL_FLOAT_MAT3x2: glUniformMatrix2x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
201                 case GL_FLOAT_MAT3x4: glUniformMatrix4x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
202                 case GL_FLOAT_MAT4x2: glUniformMatrix3x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
203                 case GL_FLOAT_MAT4x3: glUniformMatrix4x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break;
204                 case GL_DOUBLE_MAT2:   glUniformMatrix2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
205                 case GL_DOUBLE_MAT3:   glUniformMatrix3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
206                 case GL_DOUBLE_MAT4:   glUniformMatrix4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
207                 case GL_DOUBLE_MAT2x3: glUniformMatrix2x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
208                 case GL_DOUBLE_MAT2x4: glUniformMatrix3x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
209                 case GL_DOUBLE_MAT3x2: glUniformMatrix2x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
210                 case GL_DOUBLE_MAT3x4: glUniformMatrix4x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
211                 case GL_DOUBLE_MAT4x2: glUniformMatrix3x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
212                 case GL_DOUBLE_MAT4x3: glUniformMatrix4x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break;
213 
214                 // image samplers
215                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
216                     glUniform1iv(_location, _size, cast(GLint*)_value);
217                     break;
218 
219                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
220                     glUniform1uiv(_location, _size, cast(GLuint*)_value);
221                     break;
222 
223                 case GL_SAMPLER_1D:
224                 case GL_SAMPLER_2D:
225                 case GL_SAMPLER_3D:
226                 case GL_SAMPLER_CUBE:
227                 case GL_SAMPLER_1D_SHADOW:
228                 case GL_SAMPLER_2D_SHADOW:
229                 case GL_SAMPLER_1D_ARRAY:
230                 case GL_SAMPLER_2D_ARRAY:
231                 case GL_SAMPLER_1D_ARRAY_SHADOW:
232                 case GL_SAMPLER_2D_ARRAY_SHADOW:
233                 case GL_SAMPLER_2D_MULTISAMPLE:
234                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
235                 case GL_SAMPLER_CUBE_SHADOW:
236                 case GL_SAMPLER_BUFFER:
237                 case GL_SAMPLER_2D_RECT:
238                 case GL_SAMPLER_2D_RECT_SHADOW:
239                 case GL_INT_SAMPLER_1D:
240                 case GL_INT_SAMPLER_2D:
241                 case GL_INT_SAMPLER_3D:
242                 case GL_INT_SAMPLER_CUBE:
243                 case GL_INT_SAMPLER_1D_ARRAY:
244                 case GL_INT_SAMPLER_2D_ARRAY:
245                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
246                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
247                 case GL_INT_SAMPLER_BUFFER:
248                 case GL_INT_SAMPLER_2D_RECT:
249                 case GL_UNSIGNED_INT_SAMPLER_1D:
250                 case GL_UNSIGNED_INT_SAMPLER_2D:
251                 case GL_UNSIGNED_INT_SAMPLER_3D:
252                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
253                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
254                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
255                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
256                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
257                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
258                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
259                     glUniform1iv(_location, _size, cast(GLint*)_value);
260                     break;
261 
262                 default: 
263                     break;
264             }
265             _gl.runtimeCheck();
266         }
267 
268         public static bool typeIsCompliant(T)(GLenum type)
269         {
270             switch (type)
271             {
272                 case GL_FLOAT:      return is(T == float);
273                 case GL_FLOAT_VEC2: return is(T == vec2f);
274                 case GL_FLOAT_VEC3: return is(T == vec3f);
275                 case GL_FLOAT_VEC4: return is(T == vec4f);
276                 case GL_DOUBLE:      return is(T == double);
277                 case GL_DOUBLE_VEC2: return is(T == vec2d);
278                 case GL_DOUBLE_VEC3: return is(T == vec3d);
279                 case GL_DOUBLE_VEC4: return is(T == vec4d);
280                 case GL_INT:      return is(T == int);
281                 case GL_INT_VEC2: return is(T == vec2i);
282                 case GL_INT_VEC3: return is(T == vec3i);
283                 case GL_INT_VEC4: return is(T == vec4i);
284                 case GL_UNSIGNED_INT:      return is(T == uint);
285                 case GL_UNSIGNED_INT_VEC2: return is(T == vec2ui);
286                 case GL_UNSIGNED_INT_VEC3: return is(T == vec3ui);
287                 case GL_UNSIGNED_INT_VEC4: return is(T == vec4ui);
288                 case GL_BOOL:      return is(T == int) || is(T == bool); // int because bool type is 1 byte
289                 case GL_BOOL_VEC2: return is(T == vec2i);
290                 case GL_BOOL_VEC3: return is(T == vec3i);
291                 case GL_BOOL_VEC4: return is(T == vec4i);
292                 case GL_FLOAT_MAT2: return is(T == mat2f);
293                 case GL_FLOAT_MAT3: return is(T == mat3f);
294                 case GL_FLOAT_MAT4: return is(T == mat4f);
295                 case GL_FLOAT_MAT2x3: return is(T == mat3x2f);
296                 case GL_FLOAT_MAT2x4: return is(T == mat4x2f);
297                 case GL_FLOAT_MAT3x2: return is(T == mat2x3f);
298                 case GL_FLOAT_MAT3x4: return is(T == mat4x3f);
299                 case GL_FLOAT_MAT4x2: return is(T == mat2x4f);
300                 case GL_FLOAT_MAT4x3: return is(T == mat3x4f);
301                 case GL_DOUBLE_MAT2: return is(T == mat2d);
302                 case GL_DOUBLE_MAT3: return is(T == mat3d);
303                 case GL_DOUBLE_MAT4: return is(T == mat4d);
304                 case GL_DOUBLE_MAT2x3: return is(T == mat3x2d);
305                 case GL_DOUBLE_MAT2x4: return is(T == mat4x2d);
306                 case GL_DOUBLE_MAT3x2: return is(T == mat2x3d);
307                 case GL_DOUBLE_MAT3x4: return is(T == mat4x3d);
308                 case GL_DOUBLE_MAT4x2: return is(T == mat2x4d);
309                 case GL_DOUBLE_MAT4x3: return is(T == mat3x4d);
310 
311                     // image samplers
312                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
313                     return is(T == int);
314 
315                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
316                     return is(T == uint);
317 
318                 case GL_SAMPLER_1D:
319                 case GL_SAMPLER_2D:
320                 case GL_SAMPLER_3D:
321                 case GL_SAMPLER_CUBE:
322                 case GL_SAMPLER_1D_SHADOW:
323                 case GL_SAMPLER_2D_SHADOW:
324                 case GL_SAMPLER_1D_ARRAY:
325                 case GL_SAMPLER_2D_ARRAY:
326                 case GL_SAMPLER_1D_ARRAY_SHADOW:
327                 case GL_SAMPLER_2D_ARRAY_SHADOW:
328                 case GL_SAMPLER_2D_MULTISAMPLE:
329                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
330                 case GL_SAMPLER_CUBE_SHADOW:
331                 case GL_SAMPLER_BUFFER:
332                 case GL_SAMPLER_2D_RECT:
333                 case GL_SAMPLER_2D_RECT_SHADOW:
334                 case GL_INT_SAMPLER_1D:
335                 case GL_INT_SAMPLER_2D:
336                 case GL_INT_SAMPLER_3D:
337                 case GL_INT_SAMPLER_CUBE:
338                 case GL_INT_SAMPLER_1D_ARRAY:
339                 case GL_INT_SAMPLER_2D_ARRAY:
340                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
341                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
342                 case GL_INT_SAMPLER_BUFFER:
343                 case GL_INT_SAMPLER_2D_RECT:
344                 case GL_UNSIGNED_INT_SAMPLER_1D:
345                 case GL_UNSIGNED_INT_SAMPLER_2D:
346                 case GL_UNSIGNED_INT_SAMPLER_3D:
347                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
348                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
349                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
350                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
351                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
352                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
353                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
354                     return is(T == int);
355 
356                 default:
357                     // unrecognized type, in release mode return true
358                     debug
359                     {
360                         assert(false);
361                     }
362                     else
363                     {
364                         return true;
365                     }
366             }
367         }
368 
369         public static size_t sizeOfUniformType(GLenum type)
370         {
371             switch (type)
372             {
373                 case GL_FLOAT:      return float.sizeof;
374                 case GL_FLOAT_VEC2: return vec2f.sizeof;
375                 case GL_FLOAT_VEC3: return vec3f.sizeof;
376                 case GL_FLOAT_VEC4: return vec4f.sizeof;
377                 case GL_DOUBLE:      return double.sizeof;
378                 case GL_DOUBLE_VEC2: return vec2d.sizeof;
379                 case GL_DOUBLE_VEC3: return vec3d.sizeof;
380                 case GL_DOUBLE_VEC4: return vec4d.sizeof;
381                 case GL_INT:      return int.sizeof;
382                 case GL_INT_VEC2: return vec2i.sizeof;
383                 case GL_INT_VEC3: return vec3i.sizeof;
384                 case GL_INT_VEC4: return vec4i.sizeof;
385                 case GL_UNSIGNED_INT:      return uint.sizeof;
386                 case GL_UNSIGNED_INT_VEC2: return vec2ui.sizeof;
387                 case GL_UNSIGNED_INT_VEC3: return vec3ui.sizeof;
388                 case GL_UNSIGNED_INT_VEC4: return vec4ui.sizeof;
389                 case GL_BOOL:      return int.sizeof; // int because D bool type is 1 byte
390                 case GL_BOOL_VEC2: return vec2i.sizeof;
391                 case GL_BOOL_VEC3: return vec3i.sizeof;
392                 case GL_BOOL_VEC4: return vec4i.sizeof;
393                 case GL_FLOAT_MAT2: return mat2f.sizeof;
394                 case GL_FLOAT_MAT3: return mat3f.sizeof;
395                 case GL_FLOAT_MAT4: return mat4f.sizeof;
396                 case GL_FLOAT_MAT2x3: return mat3x2f.sizeof;
397                 case GL_FLOAT_MAT2x4: return mat4x2f.sizeof;
398                 case GL_FLOAT_MAT3x2: return mat2x3f.sizeof;
399                 case GL_FLOAT_MAT3x4: return mat4x3f.sizeof;
400                 case GL_FLOAT_MAT4x2: return mat2x4f.sizeof;
401                 case GL_FLOAT_MAT4x3: return mat3x4f.sizeof;
402                 case GL_DOUBLE_MAT2: return mat2d.sizeof;
403                 case GL_DOUBLE_MAT3: return mat3d.sizeof;
404                 case GL_DOUBLE_MAT4: return mat4d.sizeof;
405                 case GL_DOUBLE_MAT2x3: return mat3x2d.sizeof;
406                 case GL_DOUBLE_MAT2x4: return mat4x2d.sizeof;
407                 case GL_DOUBLE_MAT3x2: return mat2x3d.sizeof;
408                 case GL_DOUBLE_MAT3x4: return mat4x3d.sizeof;
409                 case GL_DOUBLE_MAT4x2: return mat2x4d.sizeof;
410                 case GL_DOUBLE_MAT4x3: return mat3x4d.sizeof;
411 
412                     // image samplers
413                 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
414                     return int.sizeof;
415 
416                 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
417                     return uint.sizeof;
418 
419                 case GL_SAMPLER_1D:
420                 case GL_SAMPLER_2D:
421                 case GL_SAMPLER_3D:
422                 case GL_SAMPLER_CUBE:
423                 case GL_SAMPLER_1D_SHADOW:
424                 case GL_SAMPLER_2D_SHADOW:
425                 case GL_SAMPLER_1D_ARRAY:
426                 case GL_SAMPLER_2D_ARRAY:
427                 case GL_SAMPLER_1D_ARRAY_SHADOW:
428                 case GL_SAMPLER_2D_ARRAY_SHADOW:
429                 case GL_SAMPLER_2D_MULTISAMPLE:
430                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
431                 case GL_SAMPLER_CUBE_SHADOW:
432                 case GL_SAMPLER_BUFFER:
433                 case GL_SAMPLER_2D_RECT:
434                 case GL_SAMPLER_2D_RECT_SHADOW:
435                 case GL_INT_SAMPLER_1D:
436                 case GL_INT_SAMPLER_2D:
437                 case GL_INT_SAMPLER_3D:
438                 case GL_INT_SAMPLER_CUBE:
439                 case GL_INT_SAMPLER_1D_ARRAY:
440                 case GL_INT_SAMPLER_2D_ARRAY:
441                 case GL_INT_SAMPLER_2D_MULTISAMPLE:
442                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
443                 case GL_INT_SAMPLER_BUFFER:
444                 case GL_INT_SAMPLER_2D_RECT:
445                 case GL_UNSIGNED_INT_SAMPLER_1D:
446                 case GL_UNSIGNED_INT_SAMPLER_2D:
447                 case GL_UNSIGNED_INT_SAMPLER_3D:
448                 case GL_UNSIGNED_INT_SAMPLER_CUBE:
449                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
450                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
451                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
452                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
453                 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
454                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
455                     return int.sizeof;
456 
457                 default:
458                     // unrecognized type
459                     // in debug mode assert, in release mode return 0 to disable this uniform
460                     debug
461                     {
462                         assert(false);
463                     }
464                     else
465                     {
466                         return 0;
467                     }
468             }
469         }
470 
471         static string GLSLTypeName(GLenum type)
472         {
473             switch (type)
474             {
475                 case GL_FLOAT: return "float";
476                 case GL_FLOAT_VEC2: return "vec2";
477                 case GL_FLOAT_VEC3: return "vec3";
478                 case GL_FLOAT_VEC4: return "vec4";
479                 case GL_DOUBLE: return "double";
480                 case GL_DOUBLE_VEC2: return "dvec2";
481                 case GL_DOUBLE_VEC3: return "dvec3";
482                 case GL_DOUBLE_VEC4: return "dvec4";
483                 case GL_INT: return "int";
484                 case GL_INT_VEC2: return "ivec2";
485                 case GL_INT_VEC3: return "ivec3";
486                 case GL_INT_VEC4: return "ivec4";
487                 case GL_UNSIGNED_INT: return "uint";
488                 case GL_UNSIGNED_INT_VEC2: return "uvec2";
489                 case GL_UNSIGNED_INT_VEC3: return "uvec3";
490                 case GL_UNSIGNED_INT_VEC4: return "uvec4";
491                 case GL_BOOL: return "bool";
492                 case GL_BOOL_VEC2: return "bvec2";
493                 case GL_BOOL_VEC3: return "bvec3";
494                 case GL_BOOL_VEC4: return "bvec4";
495                 case GL_FLOAT_MAT2: return "mat2";
496                 case GL_FLOAT_MAT3: return "mat3";
497                 case GL_FLOAT_MAT4: return "mat4";
498                 case GL_FLOAT_MAT2x3: return "mat2x3";
499                 case GL_FLOAT_MAT2x4: return "mat2x4";
500                 case GL_FLOAT_MAT3x2: return "mat3x2";
501                 case GL_FLOAT_MAT3x4: return "mat3x4";
502                 case GL_FLOAT_MAT4x2: return "mat4x2";
503                 case GL_FLOAT_MAT4x3: return "mat4x3";
504                 case GL_DOUBLE_MAT2: return "dmat2";
505                 case GL_DOUBLE_MAT3: return "dmat3";
506                 case GL_DOUBLE_MAT4: return "dmat4";
507                 case GL_DOUBLE_MAT2x3: return "dmat2x3";
508                 case GL_DOUBLE_MAT2x4: return "dmat2x4";
509                 case GL_DOUBLE_MAT3x2: return "dmat3x2";
510                 case GL_DOUBLE_MAT3x4: return "dmat3x4";
511                 case GL_DOUBLE_MAT4x2: return "dmat4x2";
512                 case GL_DOUBLE_MAT4x3: return "dmat4x3";
513                 case GL_SAMPLER_1D: return "sampler1D";
514                 case GL_SAMPLER_2D: return "sampler2D";
515                 case GL_SAMPLER_3D: return "sampler3D";
516                 case GL_SAMPLER_CUBE: return "samplerCube";
517                 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
518                 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
519                 case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
520                 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
521                 case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow";
522                 case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow";
523                 case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
524                 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
525                 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
526                 case GL_SAMPLER_BUFFER: return "samplerBuffer";
527                 case GL_SAMPLER_2D_RECT: return "sampler2DRect";
528                 case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow";
529                 case GL_INT_SAMPLER_1D: return "isampler1D";
530                 case GL_INT_SAMPLER_2D: return "isampler2D";
531                 case GL_INT_SAMPLER_3D: return "isampler3D";
532                 case GL_INT_SAMPLER_CUBE: return "isamplerCube";
533                 case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray";
534                 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray";
535                 case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS";
536                 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray";
537                 case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer";
538                 case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect";
539                 case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D";
540                 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D";
541                 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D";
542                 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube";
543                 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler2DArray";
544                 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray";
545                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS";
546                 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray";
547                 case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer";
548                 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect";
549                 case GL_IMAGE_1D: return "image1D";
550                 case GL_IMAGE_2D: return "image2D";
551                 case GL_IMAGE_3D: return "image3D";
552                 case GL_IMAGE_2D_RECT: return "image2DRect";
553                 case GL_IMAGE_CUBE: return "imageCube";
554                 case GL_IMAGE_BUFFER: return "imageBuffer";
555                 case GL_IMAGE_1D_ARRAY: return "image1DArray";
556                 case GL_IMAGE_2D_ARRAY: return "image2DArray";
557                 case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS";
558                 case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray";
559                 case GL_INT_IMAGE_1D: return "iimage1D";
560                 case GL_INT_IMAGE_2D: return "iimage2D";
561                 case GL_INT_IMAGE_3D: return "iimage3D";
562                 case GL_INT_IMAGE_2D_RECT: return "iimage2DRect";
563                 case GL_INT_IMAGE_CUBE: return "iimageCube";
564                 case GL_INT_IMAGE_BUFFER: return "iimageBuffer";
565                 case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray";
566                 case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray";
567                 case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS";
568                 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray";
569                 case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D";
570                 case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D";
571                 case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D";
572                 case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect";
573                 case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube";
574                 case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer";
575                 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray";
576                 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray";
577                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS";
578                 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray";
579                 case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint";
580                 default:
581                     return "unknown";
582             }
583         }
584 
585         static string GLSLTypeNameArray(GLenum type, size_t multiplicity)
586         {
587             assert(multiplicity > 0);
588             if (multiplicity == 1)
589                 return GLSLTypeName(type);
590             else
591                 return format("%s[%s]", GLSLTypeName(type), multiplicity);
592         }
593     }
594 }
595 
596 static assert(is(GLint == int));
597 static assert(is(GLuint == uint));
598 static assert(is(GLfloat == float));
599 static assert(is(GLdouble == double));