1 module gfmod.opengl.uniform; 2 3 import std.algorithm, 4 std.conv, 5 std.exception, 6 std..string, 7 core.stdc..string; 8 9 import derelict.opengl3.gl3; 10 11 import gfmod.opengl.opengl, 12 gfmod.opengl.program; 13 14 15 // TODO: (WISHLIST) eventually refactor/simplify GLUniform to be templated with uniform type, 16 // so e.g. set() will be generated just for that type without runtime checks. 2014-08-13 17 18 import std.traits; 19 import std.typetuple; 20 21 import gl3n_extra.linalg; 22 23 /// Checks if Spec is a valid uniform specification. 24 /// 25 /// Uses static asserts for better compile-time error messages. 26 bool isUniformSpec(Spec)() 27 { 28 // All supported uniform types. 29 alias GLSLTypes = TypeTuple!(float, vec2, vec3, vec4, 30 double, vec2d, vec3d, vec4d, 31 int, vec2i, vec3i, vec4i, 32 uint, vec2u, vec3u, vec4u, 33 mat2, mat3, mat4, 34 mat32, mat42, mat23, mat43, mat24, mat34, 35 mat2d, mat3d, mat4d, 36 mat32d, mat42d, mat23d, mat43d, mat24d, mat34d); 37 38 foreach(Field; FieldTypeTuple!Spec) 39 { 40 static assert(staticIndexOf!(Field, GLSLTypes) >= 0, 41 "Field of uniform spec %s has type %s which is not a supported " 42 " GL uniform type".format(Spec.stringof, Field.stringof)); 43 } 44 return true; 45 } 46 47 // Manually copied from tharsis-core to avoid a dependency. 48 /// Get a compile-time tuple containing names of all fields in a struct. 49 package template FieldNamesTuple(S) 50 if(is(S == struct)) 51 { 52 /// Determine if a member with specified name is a field of S. 53 template isField(string memberName) 54 { 55 // For some reason, checking if 'S.this.offsetof' compiles is a compiler 56 // error. 57 static if(memberName == "this") 58 { 59 enum bool isField = false; 60 } 61 else 62 { 63 mixin(q{enum bool isField = __traits(compiles, S.%s.offsetof);}.format(memberName)); 64 } 65 } 66 67 alias FieldNamesTuple = Filter!(isField, __traits(allMembers, S)); 68 } 69 70 71 /** A type-safe API for manipulating GLSL uniform variables. 72 * 73 * 'Uniforms specification' struct Spec specifies types and names of uniforms in 74 * a program. GLUniforms!Spec has properties with names matching fields of Spec. 75 * Uniforms in a program can be set by setting these properties. 76 * 77 * Example: 78 * 79 * We have a vertex shader with source such as this: 80 * 81 * -------------------- 82 * #version 130 83 * 84 * uniform mat4 projection; 85 * uniform mat4 modelView; 86 * in vec3 position; 87 * 88 * void main() 89 * { 90 * gl_Position = projection * modelView * vec4(position, 1.0); 91 * } 92 * -------------------- 93 * 94 * We have the following uniforms specification struct: 95 * 96 * -------------------- 97 * struct Uniforms 98 * { 99 * import gl3n.linalg; 100 * mat4 projection; 101 * mat4 modelView; 102 * } 103 * -------------------- 104 * 105 * $(B NOTE:) Array uniforms are not supported at the moment, but will be supported in 106 * future. 107 * 108 * The vertex shader above is used by a GLProgram $(D program). 109 * 110 * The following code builds a GLUniforms struct: 111 * 112 * Example: 113 * -------------------- 114 * try 115 * { 116 * auto uniforms = GLUniforms!Uniforms(program); 117 * } 118 * catch(OpenGLException e) 119 * { 120 * writeln("ERROR: uniforms in a program have unexpected types: ", e); 121 * return; 122 * } 123 * -------------------- 124 * 125 * The GLUniforms constructor enforces that types of uniforms in $(D program) match 126 * types in $(D Uniforms) - the uniforms specification struct. Note that if 127 * $(D program) is missing any uniform, there is no error, only a logged warning, and 128 * a dummy uniform is created. This is because some GPU drivers agressively optimize 129 * and remove uniforms, and we don't want to trigger an error just because a user is 130 * running our program on a GPU we didn't test. 131 * 132 * Finally, the following code sets the uniforms through $(D uniforms). 133 * 134 * -------------------- 135 * // mat4 projectionMatrix, modelViewMatrix 136 * uniforms.projection = projectionMatrix; 137 * uniforms.modelView = modelViewMatrix; 138 * -------------------- 139 */ 140 struct GLUniforms(Spec) 141 if(isUniformSpec!Spec) 142 { 143 private: 144 // Names of fields in Spec. 145 enum fieldNames = [FieldNamesTuple!Spec]; 146 147 // Types of fields in Spec. 148 alias fieldTypes = FieldTypeTuple!Spec; 149 150 // Generate GLUniform data members used internally to access uniforms. 151 static string uniformsInternal() 152 { 153 return fieldNames.map!(n => q{GLUniform %s_;}.format(n)).join("\n"); 154 } 155 156 // Generate setters that set each uniform. 157 static string setters() 158 { 159 string[] setters; 160 foreach(i, T; fieldTypes) 161 { 162 enum name = fieldNames[i]; 163 setters ~= q{ 164 // GLUniform ensures the value can be set even while the program is not 165 // bound. 166 void %s(%s rhs) @safe nothrow { %s_.set(rhs); } 167 }.format(name, T.stringof, name); 168 } 169 170 return setters.join("\n\n"); 171 } 172 173 // GLSL program owning the uniforms. 174 GLProgram program_; 175 176 // pragma(msg, uniformsInternal()); 177 mixin(uniformsInternal()); 178 179 public: 180 /// Construct GLUniforms to access uniforms in a GLProgram. 181 /// 182 /// If any uniform present in Spec is missing in program, a fake uniform will be 183 /// created to avoid an error. See GLUniforms documentation top for why we avoid 184 /// throwing an exception in that case. 185 /// 186 /// OpenGLException if types of uniforms in the program don't match types in Spec. 187 this(GLProgram program) @safe 188 { 189 program_ = program; 190 foreach(i, T; fieldTypes) 191 { 192 enum name = fieldNames[i]; 193 194 // Initialize the uniform 195 mixin(q{ 196 %s_ = program_.uniform(name); 197 // Fake uniforms are automatically ignored as they have no type. 198 if(%s_.isFake) { continue; } 199 // Check that the uniform has type from the spec. 200 const compliant = %s_.typeIsCompliant!T; 201 }.format(name, name, name)); 202 203 enum msg = "Uniform %s is not compatible with type %s." 204 .format(name, T.stringof); 205 enforce(compliant, new OpenGLException(msg)); 206 } 207 }; 208 209 // pragma(msg, setters()); 210 mixin(setters()); 211 } 212 213 /// Represents an OpenGL program uniform. Owned by a GLProgram. 214 /// Both uniform locations and values are cached, to minimize OpenGL calls. 215 package final class GLUniform 216 { 217 public 218 { 219 /// Creates a GLUniform. 220 /// This is done automatically after linking a GLProgram. 221 /// See_also: GLProgram. 222 /// Throws: $(D OpenGLException) on error. 223 this(OpenGL gl, GLuint program, GLenum type, string name, GLsizei size) 224 { 225 _gl = gl; 226 _type = type; 227 _size = size; 228 _name = name; 229 230 _location = glGetUniformLocation(program, toStringz(_name)); 231 if (_location == -1) 232 { 233 // probably rare: the driver said explicitely this variable was active, and there it's not. 234 throw new OpenGLException(format("can't get uniform %s location", _name)); 235 } 236 237 size_t cacheSize = sizeOfUniformType(type) * size; 238 if (cacheSize > 0) 239 { 240 _value = new ubyte[cacheSize]; // relying on zero initialization here 241 _valueChanged = false; 242 243 _firstSet = true; 244 _disabled = false; 245 } 246 else 247 { 248 _gl._logger.warningf("uniform %s is unrecognized or has size 0, disabled", _name); 249 _disabled = true; 250 } 251 } 252 253 /// Creates a fake disabled uniform variable, designed to cope with variables 254 /// that have been optimized out by the OpenGL driver, or those which do not exist. 255 this(OpenGL gl, string name) @safe nothrow 256 { 257 _gl = gl; 258 _disabled = true; 259 _fake = true; 260 _gl._logger.warningf("creating fake uniform '%s' which either does not " 261 "exist in the shader program, or was discarded by the" 262 "driver as unused", name).assumeWontThrow; 263 } 264 265 /// Sets a uniform variable value. 266 /// T should be the exact type needed, checked at runtime. 267 /// Throws: $(D OpenGLException) on error. 268 void set(T)(T newValue) @trusted 269 { 270 set!T(&newValue, 1u); 271 } 272 273 /// Sets multiple uniform variables. 274 /// Throws: $(D OpenGLException) on error. 275 void set(T)(T[] newValues) @safe 276 { 277 set!T(newValues.ptr, newValues.length); 278 } 279 280 /// Sets multiple uniform variables. 281 /// Throws: $(D OpenGLException) on error. 282 void set(T)(T* newValues, size_t count) @trusted nothrow 283 { 284 if (_disabled) 285 return; 286 287 assert(typeIsCompliant!T, 288 "Can't use type %s to set uniform '%s' which has GLSL type %s.\n" 289 "Use GLUniform.isTypeCompliant() to check if the type matches". 290 format(T.stringof, _name, GLSLTypeNameArray(_type, _size)) 291 .assumeWontThrow); 292 assert(count == _size, 293 "Can't set uniform '%s' of size %s with a value of size %s.\n" 294 "Use GLUniform.size() to check the uniform's size." 295 .format(_name, _size, count).assumeWontThrow); 296 297 298 // if first time or different value incoming 299 if (_firstSet || (0 != memcmp(newValues, _value.ptr, _value.length))) 300 { 301 memcpy(_value.ptr, newValues, _value.length); 302 _valueChanged = true; 303 304 if (_shouldUpdateImmediately) 305 update(); 306 } 307 308 _firstSet = false; 309 } 310 311 /// Is this a "fake" uniform? 312 /// 313 /// Fake uniforms are created to avoid errors when a uniform is optimized out 314 /// by the driver. A fake uniform has no type and will silently do nothing 315 /// without failing when set. 316 bool isFake() @safe pure nothrow const @nogc 317 { 318 return _fake; 319 } 320 321 /// Get the size (number of elements) of the uniform. 322 size_t size() @safe pure nothrow const @nogc 323 { 324 return _size; 325 } 326 327 /// Called when the program owning this uniform is used. 328 void use() nothrow 329 { 330 // When in use, any changes to the uniform must trigger an immediate update. 331 _shouldUpdateImmediately = true; 332 update(); 333 } 334 335 /// Called when the program owning this uniform is unused. 336 void unuse() @safe pure nothrow @nogc 337 { 338 // When not in use, we can wait with updating the uniform till we're being 339 // used. 340 _shouldUpdateImmediately = false; 341 } 342 } 343 344 private 345 { 346 OpenGL _gl; 347 GLint _location; 348 GLenum _type; 349 GLsizei _size; 350 ubyte[] _value; 351 bool _valueChanged; 352 bool _firstSet; // force update to ensure we do not relie on the driver initializing uniform to zero 353 bool _disabled; // allow transparent usage while not doing anything 354 bool _fake; // Extra flag for fake uniforms used when a uniform is optimized out. 355 bool _shouldUpdateImmediately; 356 string _name; 357 358 void update() nothrow 359 { 360 if (_disabled) 361 return; 362 363 // safety check to prevent defaults values in uniforms 364 if (_firstSet) 365 { 366 _gl._logger.warningf("uniform '%s' left to default value, driver will probably zero it", _name) 367 .assumeWontThrow(); 368 _firstSet = false; 369 } 370 371 // has value changed? 372 // if so, set OpenGL value 373 if (_valueChanged) 374 { 375 // _gl._logger.info(*cast(mat4*)_value.ptr).assumeWontThrow; 376 setUniform(); 377 _valueChanged = false; 378 } 379 } 380 381 void setUniform() @trusted nothrow @nogc 382 { 383 switch(_type) 384 { 385 case GL_FLOAT: glUniform1fv(_location, _size, cast(GLfloat*)_value); break; 386 case GL_FLOAT_VEC2: glUniform2fv(_location, _size, cast(GLfloat*)_value); break; 387 case GL_FLOAT_VEC3: glUniform3fv(_location, _size, cast(GLfloat*)_value); break; 388 case GL_FLOAT_VEC4: glUniform4fv(_location, _size, cast(GLfloat*)_value); break; 389 case GL_DOUBLE: glUniform1dv(_location, _size, cast(GLdouble*)_value); break; 390 case GL_DOUBLE_VEC2: glUniform2dv(_location, _size, cast(GLdouble*)_value); break; 391 case GL_DOUBLE_VEC3: glUniform3dv(_location, _size, cast(GLdouble*)_value); break; 392 case GL_DOUBLE_VEC4: glUniform4dv(_location, _size, cast(GLdouble*)_value); break; 393 case GL_INT: glUniform1iv(_location, _size, cast(GLint*)_value); break; 394 case GL_INT_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break; 395 case GL_INT_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break; 396 case GL_INT_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break; 397 case GL_UNSIGNED_INT: glUniform1uiv(_location, _size, cast(GLuint*)_value); break; 398 case GL_UNSIGNED_INT_VEC2: glUniform2uiv(_location, _size, cast(GLuint*)_value); break; 399 case GL_UNSIGNED_INT_VEC3: glUniform3uiv(_location, _size, cast(GLuint*)_value); break; 400 case GL_UNSIGNED_INT_VEC4: glUniform4uiv(_location, _size, cast(GLuint*)_value); break; 401 case GL_BOOL: glUniform1iv(_location, _size, cast(GLint*)_value); break; 402 case GL_BOOL_VEC2: glUniform2iv(_location, _size, cast(GLint*)_value); break; 403 case GL_BOOL_VEC3: glUniform3iv(_location, _size, cast(GLint*)_value); break; 404 case GL_BOOL_VEC4: glUniform4iv(_location, _size, cast(GLint*)_value); break; 405 case GL_FLOAT_MAT2: glUniformMatrix2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 406 case GL_FLOAT_MAT3: glUniformMatrix3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 407 case GL_FLOAT_MAT4: glUniformMatrix4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 408 case GL_FLOAT_MAT2x3: glUniformMatrix2x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 409 case GL_FLOAT_MAT2x4: glUniformMatrix3x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 410 case GL_FLOAT_MAT3x2: glUniformMatrix2x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 411 case GL_FLOAT_MAT3x4: glUniformMatrix4x2fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 412 case GL_FLOAT_MAT4x2: glUniformMatrix3x4fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 413 case GL_FLOAT_MAT4x3: glUniformMatrix4x3fv(_location, _size, GL_TRUE, cast(GLfloat*)_value); break; 414 case GL_DOUBLE_MAT2: glUniformMatrix2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 415 case GL_DOUBLE_MAT3: glUniformMatrix3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 416 case GL_DOUBLE_MAT4: glUniformMatrix4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 417 case GL_DOUBLE_MAT2x3: glUniformMatrix2x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 418 case GL_DOUBLE_MAT2x4: glUniformMatrix3x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 419 case GL_DOUBLE_MAT3x2: glUniformMatrix2x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 420 case GL_DOUBLE_MAT3x4: glUniformMatrix4x2dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 421 case GL_DOUBLE_MAT4x2: glUniformMatrix3x4dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 422 case GL_DOUBLE_MAT4x3: glUniformMatrix4x3dv(_location, _size, GL_TRUE, cast(GLdouble*)_value); break; 423 424 // image samplers 425 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: 426 glUniform1iv(_location, _size, cast(GLint*)_value); 427 break; 428 429 case GL_UNSIGNED_INT_ATOMIC_COUNTER: 430 glUniform1uiv(_location, _size, cast(GLuint*)_value); 431 break; 432 433 case GL_SAMPLER_1D: 434 case GL_SAMPLER_2D: 435 case GL_SAMPLER_3D: 436 case GL_SAMPLER_CUBE: 437 case GL_SAMPLER_1D_SHADOW: 438 case GL_SAMPLER_2D_SHADOW: 439 case GL_SAMPLER_1D_ARRAY: 440 case GL_SAMPLER_2D_ARRAY: 441 case GL_SAMPLER_1D_ARRAY_SHADOW: 442 case GL_SAMPLER_2D_ARRAY_SHADOW: 443 case GL_SAMPLER_2D_MULTISAMPLE: 444 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: 445 case GL_SAMPLER_CUBE_SHADOW: 446 case GL_SAMPLER_BUFFER: 447 case GL_SAMPLER_2D_RECT: 448 case GL_SAMPLER_2D_RECT_SHADOW: 449 case GL_INT_SAMPLER_1D: 450 case GL_INT_SAMPLER_2D: 451 case GL_INT_SAMPLER_3D: 452 case GL_INT_SAMPLER_CUBE: 453 case GL_INT_SAMPLER_1D_ARRAY: 454 case GL_INT_SAMPLER_2D_ARRAY: 455 case GL_INT_SAMPLER_2D_MULTISAMPLE: 456 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 457 case GL_INT_SAMPLER_BUFFER: 458 case GL_INT_SAMPLER_2D_RECT: 459 case GL_UNSIGNED_INT_SAMPLER_1D: 460 case GL_UNSIGNED_INT_SAMPLER_2D: 461 case GL_UNSIGNED_INT_SAMPLER_3D: 462 case GL_UNSIGNED_INT_SAMPLER_CUBE: 463 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: 464 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: 465 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: 466 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 467 case GL_UNSIGNED_INT_SAMPLER_BUFFER: 468 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: 469 glUniform1iv(_location, _size, cast(GLint*)_value); 470 break; 471 472 default: 473 break; 474 } 475 } 476 477 public bool typeIsCompliant(T)() @safe pure nothrow const @nogc 478 { 479 switch (_type) 480 { 481 case GL_FLOAT: return is(T == float); 482 case GL_FLOAT_VEC2: return is(T == vec2); 483 case GL_FLOAT_VEC3: return is(T == vec3); 484 case GL_FLOAT_VEC4: return is(T == vec4); 485 case GL_DOUBLE: return is(T == double); 486 case GL_DOUBLE_VEC2: return is(T == vec2d); 487 case GL_DOUBLE_VEC3: return is(T == vec3d); 488 case GL_DOUBLE_VEC4: return is(T == vec4d); 489 case GL_INT: return is(T == int); 490 case GL_INT_VEC2: return is(T == vec2i); 491 case GL_INT_VEC3: return is(T == vec3i); 492 case GL_INT_VEC4: return is(T == vec4i); 493 case GL_UNSIGNED_INT: return is(T == uint); 494 case GL_UNSIGNED_INT_VEC2: return is(T == vec2u); 495 case GL_UNSIGNED_INT_VEC3: return is(T == vec3u); 496 case GL_UNSIGNED_INT_VEC4: return is(T == vec4u); 497 case GL_BOOL: return is(T == int); // int because bool type is 1 byte 498 case GL_BOOL_VEC2: return is(T == vec2i); 499 case GL_BOOL_VEC3: return is(T == vec3i); 500 case GL_BOOL_VEC4: return is(T == vec4i); 501 case GL_FLOAT_MAT2: return is(T == mat2); 502 case GL_FLOAT_MAT3: return is(T == mat3); 503 case GL_FLOAT_MAT4: return is(T == mat4); 504 case GL_FLOAT_MAT2x3: return is(T == mat32); 505 case GL_FLOAT_MAT2x4: return is(T == mat42); 506 case GL_FLOAT_MAT3x2: return is(T == mat23); 507 case GL_FLOAT_MAT3x4: return is(T == mat43); 508 case GL_FLOAT_MAT4x2: return is(T == mat24); 509 case GL_FLOAT_MAT4x3: return is(T == mat34); 510 case GL_DOUBLE_MAT2: return is(T == mat2d); 511 case GL_DOUBLE_MAT3: return is(T == mat3d); 512 case GL_DOUBLE_MAT4: return is(T == mat4d); 513 case GL_DOUBLE_MAT2x3: return is(T == mat32d); 514 case GL_DOUBLE_MAT2x4: return is(T == mat42d); 515 case GL_DOUBLE_MAT3x2: return is(T == mat23d); 516 case GL_DOUBLE_MAT3x4: return is(T == mat43d); 517 case GL_DOUBLE_MAT4x2: return is(T == mat24d); 518 case GL_DOUBLE_MAT4x3: return is(T == mat34d); 519 520 // image samplers 521 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: 522 return is(T == int); 523 524 case GL_UNSIGNED_INT_ATOMIC_COUNTER: 525 return is(T == uint); 526 527 case GL_SAMPLER_1D: 528 case GL_SAMPLER_2D: 529 case GL_SAMPLER_3D: 530 case GL_SAMPLER_CUBE: 531 case GL_SAMPLER_1D_SHADOW: 532 case GL_SAMPLER_2D_SHADOW: 533 case GL_SAMPLER_1D_ARRAY: 534 case GL_SAMPLER_2D_ARRAY: 535 case GL_SAMPLER_1D_ARRAY_SHADOW: 536 case GL_SAMPLER_2D_ARRAY_SHADOW: 537 case GL_SAMPLER_2D_MULTISAMPLE: 538 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: 539 case GL_SAMPLER_CUBE_SHADOW: 540 case GL_SAMPLER_BUFFER: 541 case GL_SAMPLER_2D_RECT: 542 case GL_SAMPLER_2D_RECT_SHADOW: 543 case GL_INT_SAMPLER_1D: 544 case GL_INT_SAMPLER_2D: 545 case GL_INT_SAMPLER_3D: 546 case GL_INT_SAMPLER_CUBE: 547 case GL_INT_SAMPLER_1D_ARRAY: 548 case GL_INT_SAMPLER_2D_ARRAY: 549 case GL_INT_SAMPLER_2D_MULTISAMPLE: 550 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 551 case GL_INT_SAMPLER_BUFFER: 552 case GL_INT_SAMPLER_2D_RECT: 553 case GL_UNSIGNED_INT_SAMPLER_1D: 554 case GL_UNSIGNED_INT_SAMPLER_2D: 555 case GL_UNSIGNED_INT_SAMPLER_3D: 556 case GL_UNSIGNED_INT_SAMPLER_CUBE: 557 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: 558 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: 559 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: 560 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 561 case GL_UNSIGNED_INT_SAMPLER_BUFFER: 562 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: 563 return is(T == int); 564 565 default: 566 // unrecognized type, in release mode return true 567 debug 568 { 569 assert(false); 570 } 571 else 572 { 573 return true; 574 } 575 } 576 } 577 578 public static size_t sizeOfUniformType(GLenum type) @safe pure nothrow @nogc 579 { 580 switch (type) 581 { 582 case GL_FLOAT: return float.sizeof; 583 case GL_FLOAT_VEC2: return vec2.sizeof; 584 case GL_FLOAT_VEC3: return vec3.sizeof; 585 case GL_FLOAT_VEC4: return vec4.sizeof; 586 case GL_DOUBLE: return double.sizeof; 587 case GL_DOUBLE_VEC2: return vec2d.sizeof; 588 case GL_DOUBLE_VEC3: return vec3d.sizeof; 589 case GL_DOUBLE_VEC4: return vec4d.sizeof; 590 case GL_INT: return int.sizeof; 591 case GL_INT_VEC2: return vec2i.sizeof; 592 case GL_INT_VEC3: return vec3i.sizeof; 593 case GL_INT_VEC4: return vec4i.sizeof; 594 case GL_UNSIGNED_INT: return uint.sizeof; 595 case GL_UNSIGNED_INT_VEC2: return vec2u.sizeof; 596 case GL_UNSIGNED_INT_VEC3: return vec3u.sizeof; 597 case GL_UNSIGNED_INT_VEC4: return vec4u.sizeof; 598 case GL_BOOL: return int.sizeof; // int because D bool type is 1 byte 599 case GL_BOOL_VEC2: return vec2i.sizeof; 600 case GL_BOOL_VEC3: return vec3i.sizeof; 601 case GL_BOOL_VEC4: return vec4i.sizeof; 602 case GL_FLOAT_MAT2: return mat2.sizeof; 603 case GL_FLOAT_MAT3: return mat3.sizeof; 604 case GL_FLOAT_MAT4: return mat4.sizeof; 605 case GL_FLOAT_MAT2x3: return mat32.sizeof; 606 case GL_FLOAT_MAT2x4: return mat42.sizeof; 607 case GL_FLOAT_MAT3x2: return mat23.sizeof; 608 case GL_FLOAT_MAT3x4: return mat43.sizeof; 609 case GL_FLOAT_MAT4x2: return mat24.sizeof; 610 case GL_FLOAT_MAT4x3: return mat34.sizeof; 611 case GL_DOUBLE_MAT2: return mat2d.sizeof; 612 case GL_DOUBLE_MAT3: return mat3d.sizeof; 613 case GL_DOUBLE_MAT4: return mat4d.sizeof; 614 case GL_DOUBLE_MAT2x3: return mat32d.sizeof; 615 case GL_DOUBLE_MAT2x4: return mat42d.sizeof; 616 case GL_DOUBLE_MAT3x2: return mat23d.sizeof; 617 case GL_DOUBLE_MAT3x4: return mat43d.sizeof; 618 case GL_DOUBLE_MAT4x2: return mat24d.sizeof; 619 case GL_DOUBLE_MAT4x3: return mat34d.sizeof; 620 621 // image samplers 622 case GL_IMAGE_1D: .. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: 623 return int.sizeof; 624 625 case GL_UNSIGNED_INT_ATOMIC_COUNTER: 626 return uint.sizeof; 627 628 case GL_SAMPLER_1D: 629 case GL_SAMPLER_2D: 630 case GL_SAMPLER_3D: 631 case GL_SAMPLER_CUBE: 632 case GL_SAMPLER_1D_SHADOW: 633 case GL_SAMPLER_2D_SHADOW: 634 case GL_SAMPLER_1D_ARRAY: 635 case GL_SAMPLER_2D_ARRAY: 636 case GL_SAMPLER_1D_ARRAY_SHADOW: 637 case GL_SAMPLER_2D_ARRAY_SHADOW: 638 case GL_SAMPLER_2D_MULTISAMPLE: 639 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: 640 case GL_SAMPLER_CUBE_SHADOW: 641 case GL_SAMPLER_BUFFER: 642 case GL_SAMPLER_2D_RECT: 643 case GL_SAMPLER_2D_RECT_SHADOW: 644 case GL_INT_SAMPLER_1D: 645 case GL_INT_SAMPLER_2D: 646 case GL_INT_SAMPLER_3D: 647 case GL_INT_SAMPLER_CUBE: 648 case GL_INT_SAMPLER_1D_ARRAY: 649 case GL_INT_SAMPLER_2D_ARRAY: 650 case GL_INT_SAMPLER_2D_MULTISAMPLE: 651 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 652 case GL_INT_SAMPLER_BUFFER: 653 case GL_INT_SAMPLER_2D_RECT: 654 case GL_UNSIGNED_INT_SAMPLER_1D: 655 case GL_UNSIGNED_INT_SAMPLER_2D: 656 case GL_UNSIGNED_INT_SAMPLER_3D: 657 case GL_UNSIGNED_INT_SAMPLER_CUBE: 658 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: 659 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: 660 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: 661 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 662 case GL_UNSIGNED_INT_SAMPLER_BUFFER: 663 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: 664 return int.sizeof; 665 666 default: 667 // unrecognized type 668 // in debug mode assert, in release mode return 0 to disable this uniform 669 debug 670 { 671 assert(false); 672 } 673 else 674 { 675 return 0; 676 } 677 } 678 } 679 680 static string GLSLTypeName(GLenum type) @safe pure nothrow @nogc 681 { 682 switch (type) 683 { 684 case GL_FLOAT: return "float"; 685 case GL_FLOAT_VEC2: return "vec2"; 686 case GL_FLOAT_VEC3: return "vec3"; 687 case GL_FLOAT_VEC4: return "vec4"; 688 case GL_DOUBLE: return "double"; 689 case GL_DOUBLE_VEC2: return "dvec2"; 690 case GL_DOUBLE_VEC3: return "dvec3"; 691 case GL_DOUBLE_VEC4: return "dvec4"; 692 case GL_INT: return "int"; 693 case GL_INT_VEC2: return "ivec2"; 694 case GL_INT_VEC3: return "ivec3"; 695 case GL_INT_VEC4: return "ivec4"; 696 case GL_UNSIGNED_INT: return "uint"; 697 case GL_UNSIGNED_INT_VEC2: return "uvec2"; 698 case GL_UNSIGNED_INT_VEC3: return "uvec3"; 699 case GL_UNSIGNED_INT_VEC4: return "uvec4"; 700 case GL_BOOL: return "bool"; 701 case GL_BOOL_VEC2: return "bvec2"; 702 case GL_BOOL_VEC3: return "bvec3"; 703 case GL_BOOL_VEC4: return "bvec4"; 704 case GL_FLOAT_MAT2: return "mat2"; 705 case GL_FLOAT_MAT3: return "mat3"; 706 case GL_FLOAT_MAT4: return "mat4"; 707 case GL_FLOAT_MAT2x3: return "mat2x3"; 708 case GL_FLOAT_MAT2x4: return "mat2x4"; 709 case GL_FLOAT_MAT3x2: return "mat3x2"; 710 case GL_FLOAT_MAT3x4: return "mat3x4"; 711 case GL_FLOAT_MAT4x2: return "mat4x2"; 712 case GL_FLOAT_MAT4x3: return "mat4x3"; 713 case GL_DOUBLE_MAT2: return "dmat2"; 714 case GL_DOUBLE_MAT3: return "dmat3"; 715 case GL_DOUBLE_MAT4: return "dmat4"; 716 case GL_DOUBLE_MAT2x3: return "dmat2x3"; 717 case GL_DOUBLE_MAT2x4: return "dmat2x4"; 718 case GL_DOUBLE_MAT3x2: return "dmat3x2"; 719 case GL_DOUBLE_MAT3x4: return "dmat3x4"; 720 case GL_DOUBLE_MAT4x2: return "dmat4x2"; 721 case GL_DOUBLE_MAT4x3: return "dmat4x3"; 722 case GL_SAMPLER_1D: return "sampler1D"; 723 case GL_SAMPLER_2D: return "sampler2D"; 724 case GL_SAMPLER_3D: return "sampler3D"; 725 case GL_SAMPLER_CUBE: return "samplerCube"; 726 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow"; 727 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow"; 728 case GL_SAMPLER_1D_ARRAY: return "sampler1DArray"; 729 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray"; 730 case GL_SAMPLER_1D_ARRAY_SHADOW: return "sampler1DArrayShadow"; 731 case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow"; 732 case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS"; 733 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray"; 734 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow"; 735 case GL_SAMPLER_BUFFER: return "samplerBuffer"; 736 case GL_SAMPLER_2D_RECT: return "sampler2DRect"; 737 case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow"; 738 case GL_INT_SAMPLER_1D: return "isampler1D"; 739 case GL_INT_SAMPLER_2D: return "isampler2D"; 740 case GL_INT_SAMPLER_3D: return "isampler3D"; 741 case GL_INT_SAMPLER_CUBE: return "isamplerCube"; 742 case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray"; 743 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray"; 744 case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS"; 745 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray"; 746 case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer"; 747 case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect"; 748 case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D"; 749 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D"; 750 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D"; 751 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube"; 752 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler2DArray"; 753 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray"; 754 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS"; 755 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray"; 756 case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer"; 757 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect"; 758 case GL_IMAGE_1D: return "image1D"; 759 case GL_IMAGE_2D: return "image2D"; 760 case GL_IMAGE_3D: return "image3D"; 761 case GL_IMAGE_2D_RECT: return "image2DRect"; 762 case GL_IMAGE_CUBE: return "imageCube"; 763 case GL_IMAGE_BUFFER: return "imageBuffer"; 764 case GL_IMAGE_1D_ARRAY: return "image1DArray"; 765 case GL_IMAGE_2D_ARRAY: return "image2DArray"; 766 case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS"; 767 case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray"; 768 case GL_INT_IMAGE_1D: return "iimage1D"; 769 case GL_INT_IMAGE_2D: return "iimage2D"; 770 case GL_INT_IMAGE_3D: return "iimage3D"; 771 case GL_INT_IMAGE_2D_RECT: return "iimage2DRect"; 772 case GL_INT_IMAGE_CUBE: return "iimageCube"; 773 case GL_INT_IMAGE_BUFFER: return "iimageBuffer"; 774 case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray"; 775 case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray"; 776 case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS"; 777 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray"; 778 case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D"; 779 case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D"; 780 case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D"; 781 case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect"; 782 case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube"; 783 case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer"; 784 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray"; 785 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray"; 786 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS"; 787 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray"; 788 case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint"; 789 default: 790 return "unknown"; 791 } 792 } 793 794 static string GLSLTypeNameArray(GLenum type, size_t multiplicity) 795 { 796 assert(multiplicity > 0); 797 if (multiplicity == 1) 798 return GLSLTypeName(type); 799 else 800 return format("%s[%s]", GLSLTypeName(type), multiplicity); 801 } 802 } 803 } 804 805 static assert(is(GLint == int)); 806 static assert(is(GLuint == uint)); 807 static assert(is(GLfloat == float)); 808 static assert(is(GLdouble == double));