1#include "EffectsGL20.h"
2#include "GraphicsDeviceGL20.h"
4#include "../Base/Utilities.h"
6#include "Foundation/Logging/Logger.h"
7#include "Foundation/Platform/IO.h"
9#define COGS_DUMP_SHADERS 1
11#ifdef COGS_ENABLE_GLSLANG
13#include <glslang/Public/ShaderLang.h>
15#include <glslang/SPIRV/GlslangToSpv.h>
16#ifdef COGS_DUMP_SHADERS
17#include <glslang/SPIRV/disassemble.h>
20#include <spirv_cross.hpp>
21#include <spirv_glsl.hpp>
31#ifdef COGS_ENABLE_GLSLANG
32 TBuiltInResource resources = {
146 HlslSemantic getSemanticWithIndex(
const StringView & str)
149 while (index < str.
size()) {
150 if (str[index] >=
'0' && str[index] <=
'9')
break;
154 size_t semanticIndex = 0;
155 if (index < str.
size()) {
156 semanticIndex = atoi(str.
substr(index).
data());
159 return { str.
substr(0, index), semanticIndex };
170 void checkGLError(
const char * ) { }
175 GLint sourceLength = 0;
176 glGetShaderiv(shaderId, GL_SHADER_SOURCE_LENGTH, &sourceLength);
178 std::vector<char> source(sourceLength);
179 glGetShaderSource(shaderId, sourceLength, &sourceLength, source.data());
181 char* start = source.data();
186 while ((*stop !=
'\0') && (*stop !=
'\n') && (*stop !=
'\r')) { stop++; }
188 LOG_DEBUG(logger,
"%3d: %s", line++, std::string(start, stop - start).c_str());
190 while ((*stop !=
'\0') && (*stop !=
'\n')) { stop++; }
191 while ((*stop !=
'\0') && (*stop ==
'\r')) { stop++; }
194 }
while (*stop !=
'\0');
201 GLint bufferLength = 0;
202 glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &bufferLength);
205 std::vector<char> buffer(bufferLength);
207 glGetShaderInfoLog(shaderId, bufferLength,
nullptr, buffer.data());
210 printShaderSource(shaderId, effectFlags);
211 LOG_ERROR(logger,
"Could not compile shader %d:\n", shaderId);
212 LOG_ERROR(logger,
"%s\n", buffer.data());
213 }
else if (bufferLength > 1) {
214 LOG_WARNING(logger,
"Warnings compiling shader:\n%s\n", buffer.data());
221 GLint bufferLength = 0;
222 glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &bufferLength);
227 GLint attachedShadersCount = 0;
228 glGetProgramiv(programId, GL_ATTACHED_SHADERS, &attachedShadersCount);
229 std::vector<GLuint> shaders(attachedShadersCount);
231 GLsizei actualCount = 0;
232 glGetAttachedShaders(programId,
static_cast<GLsizei
>(shaders.size()), &actualCount, shaders.data());
234 for (
auto shaderId : shaders) {
235 const char* stage =
"unknown";
237 glGetShaderiv(shaderId, GL_SHADER_TYPE, &shaderType);
240 case GL_VERTEX_SHADER: stage =
"vertex";
break;
241 case GL_TESS_CONTROL_SHADER: stage =
"tess control";
break;
242 case GL_TESS_EVALUATION_SHADER: stage =
"tess eval";
break;
243 case GL_GEOMETRY_SHADER: stage =
"geometry";
break;
244 case GL_FRAGMENT_SHADER: stage =
"fragment";
break;
248 LOG_DEBUG(logger,
"Source of %s stage:", stage);
249 printShaderSource(shaderId, effectFlags);
253 std::vector<char> buffer(bufferLength);
255 glGetProgramInfoLog(programId, bufferLength,
nullptr, buffer.data());
258 LOG_ERROR(logger,
"Could not link program:\n%s\n", buffer.data());
259 }
else if (bufferLength > 1) {
260 LOG_WARNING(logger,
"Warnings linking program:\n%s\n", buffer.data());
265 static const char* getShaderUniformTypeString(GLenum type)
269 case GL_FLOAT:
return "float";
break;
270 case GL_FLOAT_VEC2:
return "vec2";
break;
271 case GL_FLOAT_VEC3:
return "vec3";
break;
272 case GL_FLOAT_VEC4:
return "vec4";
break;
273 case GL_DOUBLE:
return "double";
break;
274 case GL_DOUBLE_VEC2:
return "dvec2";
break;
275 case GL_DOUBLE_VEC3:
return "dvec3";
break;
276 case GL_DOUBLE_VEC4:
return "dvec4";
break;
277 case GL_INT:
return "int";
break;
278 case GL_INT_VEC2:
return "ivec2";
break;
279 case GL_INT_VEC3:
return "ivec3";
break;
280 case GL_INT_VEC4:
return "ivec4";
break;
281 case GL_UNSIGNED_INT:
return "unsigned int";
break;
282 case GL_UNSIGNED_INT_VEC2:
return "uvec2";
break;
283 case GL_UNSIGNED_INT_VEC3:
return "uvec3";
break;
284 case GL_UNSIGNED_INT_VEC4:
return "uvec4";
break;
285 case GL_BOOL:
return "bool";
break;
286 case GL_BOOL_VEC2:
return "bvec2";
break;
287 case GL_BOOL_VEC3:
return "bvec3";
break;
288 case GL_BOOL_VEC4:
return "bvec4";
break;
289 case GL_FLOAT_MAT2:
return "mat2";
break;
290 case GL_FLOAT_MAT3:
return "mat3";
break;
291 case GL_FLOAT_MAT4:
return "mat4";
break;
292 case GL_FLOAT_MAT2x3:
return "mat2x3";
break;
293 case GL_FLOAT_MAT2x4:
return "mat2x4";
break;
294 case GL_FLOAT_MAT3x2:
return "mat3x2";
break;
295 case GL_FLOAT_MAT3x4:
return "mat3x4";
break;
296 case GL_FLOAT_MAT4x2:
return "mat4x2";
break;
297 case GL_FLOAT_MAT4x3:
return "mat4x3";
break;
298 case GL_DOUBLE_MAT2:
return "dmat2";
break;
299 case GL_DOUBLE_MAT3:
return "dmat3";
break;
300 case GL_DOUBLE_MAT4:
return "dmat4";
break;
301 case GL_DOUBLE_MAT2x3:
return "dmat2x3";
break;
302 case GL_DOUBLE_MAT2x4:
return "dmat2x4";
break;
303 case GL_DOUBLE_MAT3x2:
return "dmat3x2";
break;
304 case GL_DOUBLE_MAT3x4:
return "dmat3x4";
break;
305 case GL_DOUBLE_MAT4x2:
return "dmat4x2";
break;
306 case GL_DOUBLE_MAT4x3:
return "dmat4x3";
break;
307 case GL_SAMPLER_1D:
return "sampler1D";
break;
308 case GL_SAMPLER_2D:
return "sampler2D";
break;
309 case GL_SAMPLER_3D:
return "sampler3D";
break;
310 case GL_SAMPLER_CUBE:
return "samplerCube";
break;
311 case GL_SAMPLER_1D_SHADOW:
return "sampler1DShadow";
break;
312 case GL_SAMPLER_2D_SHADOW:
return "sampler2DShadow";
break;
313 case GL_SAMPLER_1D_ARRAY:
return "sampler1DArray";
break;
314 case GL_SAMPLER_2D_ARRAY:
return "sampler2DArray";
break;
315 case GL_SAMPLER_1D_ARRAY_SHADOW:
return "sampler1DArrayShadow";
break;
316 case GL_SAMPLER_2D_ARRAY_SHADOW:
return "sampler2DArrayShadow";
break;
317 case GL_SAMPLER_2D_MULTISAMPLE:
return "sampler2DMS";
break;
318 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
return "sampler2DMSArray";
break;
319 case GL_SAMPLER_CUBE_SHADOW:
return "samplerCubeShadow";
break;
320 case GL_SAMPLER_BUFFER:
return "samplerBuffer";
break;
321 case GL_SAMPLER_2D_RECT:
return "sampler2DRect";
break;
322 case GL_SAMPLER_2D_RECT_SHADOW:
return "sampler2DRectShadow";
break;
323 case GL_INT_SAMPLER_1D:
return "isampler1D";
break;
324 case GL_INT_SAMPLER_2D:
return "isampler2D";
break;
325 case GL_INT_SAMPLER_3D:
return "isampler3D";
break;
326 case GL_INT_SAMPLER_CUBE:
return "isamplerCube";
break;
327 case GL_INT_SAMPLER_1D_ARRAY:
return "isampler1DArray";
break;
328 case GL_INT_SAMPLER_2D_ARRAY:
return "isampler2DArray";
break;
329 case GL_INT_SAMPLER_2D_MULTISAMPLE:
return "isampler2DMS";
break;
330 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
return "isampler2DMSArray";
break;
331 case GL_INT_SAMPLER_BUFFER:
return "isamplerBuffer";
break;
332 case GL_INT_SAMPLER_2D_RECT:
return "isampler2DRect";
break;
333 case GL_UNSIGNED_INT_SAMPLER_1D:
return "usampler1D";
break;
334 case GL_UNSIGNED_INT_SAMPLER_2D:
return "usampler2D";
break;
335 case GL_UNSIGNED_INT_SAMPLER_3D:
return "usampler3D";
break;
336 case GL_UNSIGNED_INT_SAMPLER_CUBE:
return "usamplerCube";
break;
337 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
return "usampler2DArray";
break;
338 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
return "usampler2DArray";
break;
339 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
return "usampler2DMS";
break;
340 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
return "usampler2DMSArray";
break;
341 case GL_UNSIGNED_INT_SAMPLER_BUFFER:
return "usamplerBuffer";
break;
342 case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
return "usampler2DRect";
break;
343 case GL_IMAGE_1D:
return "image1D";
break;
344 case GL_IMAGE_2D:
return "image2D";
break;
345 case GL_IMAGE_3D:
return "image3D";
break;
346 case GL_IMAGE_2D_RECT:
return "image2DRect";
break;
347 case GL_IMAGE_CUBE:
return "imageCube";
break;
348 case GL_IMAGE_BUFFER:
return "imageBuffer";
break;
349 case GL_IMAGE_1D_ARRAY:
return "image1DArray";
break;
350 case GL_IMAGE_2D_ARRAY:
return "image2DArray";
break;
351 case GL_IMAGE_2D_MULTISAMPLE:
return "image2DMS";
break;
352 case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
return "image2DMSArray";
break;
353 case GL_INT_IMAGE_1D:
return "iimage1D";
break;
354 case GL_INT_IMAGE_2D:
return "iimage2D";
break;
355 case GL_INT_IMAGE_3D:
return "iimage3D";
break;
356 case GL_INT_IMAGE_2D_RECT:
return "iimage2DRect";
break;
357 case GL_INT_IMAGE_CUBE:
return "iimageCube";
break;
358 case GL_INT_IMAGE_BUFFER:
return "iimageBuffer";
break;
359 case GL_INT_IMAGE_1D_ARRAY:
return "iimage1DArray";
break;
360 case GL_INT_IMAGE_2D_ARRAY:
return "iimage2DArray";
break;
361 case GL_INT_IMAGE_2D_MULTISAMPLE:
return "iimage2DMS";
break;
362 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
return "iimage2DMSArray";
break;
363 case GL_UNSIGNED_INT_IMAGE_1D:
return "uimage1D";
break;
364 case GL_UNSIGNED_INT_IMAGE_2D:
return "uimage2D";
break;
365 case GL_UNSIGNED_INT_IMAGE_3D:
return "uimage3D";
break;
366 case GL_UNSIGNED_INT_IMAGE_2D_RECT:
return "uimage2DRect";
break;
367 case GL_UNSIGNED_INT_IMAGE_CUBE:
return "uimageCube";
break;
368 case GL_UNSIGNED_INT_IMAGE_BUFFER:
return "uimageBuffer";
break;
369 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
return "uimage1DArray";
break;
370 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
return "uimage2DArray";
break;
371 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
return "uimage2DMS";
break;
372 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
return "uimage2DMSArray";
break;
373 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
return "atomic_uint";
break;
375 return "UNKNOWN type";
384 this->capabilities = capabilities;
385 graphicsDevice = device;
386 EffectsCommon::initialize(buffers);
387 attributes.initialize();
388 glEnable(GL_CLIP_DISTANCE0);
390#ifdef COGS_ENABLE_GLSLANG
395 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &resources.maxVertexAttribs);
396 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &resources.maxVertexUniformComponents);
397 glGetIntegerv(GL_MAX_VARYING_FLOATS, &resources.maxVaryingFloats);
398 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &resources.maxVertexTextureImageUnits);
399 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &resources.maxCombinedTextureImageUnits);
400 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &resources.maxTextureImageUnits);
401 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &resources.maxFragmentUniformComponents);
402 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &resources.maxDrawBuffers);
404 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &resources.maxVertexUniformVectors);
405 glGetIntegerv(GL_MAX_VARYING_VECTORS, &resources.maxVaryingVectors);
406 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &resources.maxFragmentUniformVectors);
409 glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &resources.minProgramTexelOffset);
410 glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &resources.maxProgramTexelOffset);
411 glGetIntegerv(GL_MAX_CLIP_DISTANCES, &resources.maxClipDistances);
418 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &count);
419 resources.maxComputeWorkGroupCountX = count;
420 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &count);
421 resources.maxComputeWorkGroupCountY = count;
422 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &count);
423 resources.maxComputeWorkGroupCountZ = count;
425 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &size);
426 resources.maxComputeWorkGroupSizeX = size;
427 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &size);
428 resources.maxComputeWorkGroupSizeY = size;
429 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &size);
430 resources.maxComputeWorkGroupSizeZ = size;
431 glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &resources.maxComputeUniformComponents);
432 glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &resources.maxComputeTextureImageUnits);
433 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &resources.maxComputeImageUniforms);
434 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &resources.maxComputeAtomicCounters);
435 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &resources.maxComputeAtomicCounterBuffers);
437 glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &resources.maxVaryingComponents);
438 glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &resources.maxVertexOutputComponents);
439 glGetIntegerv(GL_MAX_GEOMETRY_INPUT_COMPONENTS, &resources.maxGeometryInputComponents);
440 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &resources.maxGeometryOutputComponents);
441 glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &resources.maxFragmentInputComponents);
442 glGetIntegerv(GL_MAX_IMAGE_UNITS, &resources.maxImageUnits);
443 glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS, &resources.maxCombinedImageUnitsAndFragmentOutputs);
444 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &resources.maxCombinedShaderOutputResources);
445 glGetIntegerv(GL_MAX_IMAGE_SAMPLES, &resources.maxImageSamples);
447 glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &resources.maxVertexImageUniforms);
448 glGetIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &resources.maxTessControlImageUniforms);
449 glGetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &resources.maxTessEvaluationImageUniforms);
450 glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &resources.maxGeometryImageUniforms);
451 glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &resources.maxFragmentImageUniforms);
452 glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &resources.maxCombinedImageUniforms);
454 glGetIntegerv(GL_MAX_VIEWPORTS, &resources.maxViewports);
456 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &resources.maxVertexAtomicCounters);
457 glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, &resources.maxTessControlAtomicCounters);
458 glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &resources.maxTessEvaluationAtomicCounters);
459 glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTERS, &resources.maxGeometryAtomicCounters);
460 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &resources.maxFragmentAtomicCounters);
461 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &resources.maxCombinedAtomicCounters);
463 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &resources.maxAtomicCounterBindings);
465 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &resources.maxVertexAtomicCounterBuffers);
466 glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, &resources.maxTessControlAtomicCounterBuffers);
467 glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, &resources.maxTessEvaluationAtomicCounterBuffers);
468 glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, &resources.maxGeometryAtomicCounterBuffers);
469 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &resources.maxFragmentAtomicCounterBuffers);
470 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &resources.maxCombinedAtomicCounterBuffers);
472 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &resources.maxAtomicCounterBufferSize);
473 glGetIntegerv(GL_MAX_CULL_DISTANCES, &resources.maxCullDistances);
474 glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &resources.maxCombinedClipAndCullDistances);
475 glGetIntegerv(GL_MAX_SAMPLES, &resources.maxSamples);
483 const GLuint shaderId = glCreateShader(shaderType);
487 if (definitions.size() == 0) {
488 glShaderSource(shaderId, 1, &pSource,
nullptr);
490 std::vector<std::string> defines(definitions.size());
492 for (
size_t i = 0; i < definitions.size(); ++i) {
493 if (definitions[i].first ==
"version") {
495 LOG_ERROR(logger,
"Version tag must be first.");
500 defines[i] =
"#version " + definitions[i].second +
"\n";
502 defines[i] =
"#define " + definitions[i].first +
" " + definitions[i].second +
"\n";
506 std::vector<const char *> strings(definitions.size());
508 for (
size_t i = 0; i < definitions.size(); ++i) {
509 strings[i] = defines[i].c_str();
512 strings.push_back(pSource);
514 glShaderSource(shaderId,
static_cast<GLsizei
>(strings.size()), strings.data(),
nullptr);
517 glCompileShader(shaderId);
520 glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled);
522 if (compiled != GL_TRUE) {
523 printShaderLog(shaderType, shaderId, effectFlags);
525 glDeleteShader(shaderId);
529 printShaderLog(shaderType, shaderId, effectFlags,
false);
533 return this->shaderIds.addResource(shaderId);
538 GLuint programId = glCreateProgram();
541 if (programId == GL_INVALID_INDEX) {
546 glAttachShader(programId, this->shaderIds[vertexShader]);
547 checkGLError(
"glAttachShader");
551 glAttachShader(programId, this->shaderIds[hullShader]);
552 checkGLError(
"glAttachShader");
556 glAttachShader(programId, this->shaderIds[domainShader]);
557 checkGLError(
"glAttachShader");
561 glAttachShader(programId, this->shaderIds[geometryShader]);
562 checkGLError(
"glAttachShader");
566 glAttachShader(programId, this->shaderIds[pixelShader]);
567 checkGLError(
"glAttachShader");
570 glLinkProgram(programId);
572 GLint linkStatus = GL_FALSE;
573 glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
575 if (linkStatus != GL_TRUE) {
576 printProgramError(programId, effectFlags);
578 glDeleteProgram(programId);
582 printProgramError(programId, effectFlags,
false);
585 GLint savedProgram = 0;
586 glGetIntegerv(GL_CURRENT_PROGRAM, &savedProgram);
587 glUseProgram(programId);
590 effect.programId = programId;
591 effect.pixelShader.shaderHandle = pixelShader;
592 effect.vertexShader.shaderHandle = vertexShader;
593 effect.geometryShader.shaderHandle = geometryShader;
596 const bool logInputs =
false;
599 GLint activeAtomicCounterBuffers = 0;
600 glGetProgramiv(programId, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, &activeAtomicCounterBuffers);
601 for (
int i = 0; i < activeAtomicCounterBuffers; i++) {
603 glGetActiveAtomicCounterBufferiv(programId, i, GL_ATOMIC_COUNTER_BUFFER_BINDING, &b.binding);
604 glGetActiveAtomicCounterBufferiv(programId, i, GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE, &b.dataSize);
606 GLuint bufferName = 0;
607 glGenBuffers(1, &bufferName);
608 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, bufferName);
609 glBufferData(GL_ATOMIC_COUNTER_BUFFER, b.dataSize,
nullptr, GL_STREAM_COPY);
610 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
611 b.backingBuffer = this->backingBuffers.addResource(bufferName);
613 if (logInputs) LOG_INFO(logger,
"Atomic counter buffer %d: name=%d, binding=%d, size=%d", i, bufferName, b.binding, b.dataSize);
614 effect.atomicCounterBuffers.push_back(b);
618 GLint activeUniforms = 0, uniformMaxLength = 0;
619 glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &activeUniforms);
620 glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxLength);
621 std::vector<char> nameBuf(uniformMaxLength);
622 for (GLuint i = 0; i < static_cast<GLuint>(activeUniforms); i++) {
626 glGetActiveUniform(programId,
static_cast<GLsizei
>(i),
static_cast<GLsizei
>(nameBuf.size()), &length, &size, &type, nameBuf.data());
628 if (type == GL_UNSIGNED_INT_ATOMIC_COUNTER) {
631 glGetActiveUniformsiv(programId, 1, &v.uniformIndex, GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX, &v.bufferIndex);
632 glGetActiveUniformsiv(programId, 1, &v.uniformIndex, GL_UNIFORM_OFFSET, &v.bufferOffset);
634 if (logInputs) LOG_DEBUG(logger,
"Program %d: Active uniform %d: type='%s', symbol='%s', buffer index=%d, offset=%d.", programId, i, getShaderUniformTypeString(type), nameBuf.data(), v.bufferIndex, v.bufferOffset);
635 effect.atomicCounterVariables.push_back(v);
636 }
else if(type == GL_SAMPLER_1D ||
637 type == GL_SAMPLER_2D ||
638 type == GL_SAMPLER_3D ||
639 type == GL_SAMPLER_CUBE ||
640 type == GL_SAMPLER_1D_SHADOW ||
641 type == GL_SAMPLER_2D_SHADOW ||
642 type == GL_SAMPLER_1D_ARRAY ||
643 type == GL_SAMPLER_2D_ARRAY ||
644 type == GL_SAMPLER_1D_ARRAY_SHADOW ||
645 type == GL_SAMPLER_2D_ARRAY_SHADOW ||
646 type == GL_SAMPLER_2D_MULTISAMPLE ||
647 type == GL_SAMPLER_2D_MULTISAMPLE_ARRAY ||
648 type == GL_SAMPLER_CUBE_SHADOW ||
649 type == GL_SAMPLER_BUFFER ||
650 type == GL_SAMPLER_2D_RECT ||
651 type == GL_SAMPLER_2D_RECT_SHADOW ||
652 type == GL_INT_SAMPLER_1D ||
653 type == GL_INT_SAMPLER_2D ||
654 type == GL_INT_SAMPLER_3D ||
655 type == GL_INT_SAMPLER_CUBE ||
656 type == GL_INT_SAMPLER_1D_ARRAY ||
657 type == GL_INT_SAMPLER_2D_ARRAY ||
658 type == GL_INT_SAMPLER_2D_MULTISAMPLE ||
659 type == GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY ||
660 type == GL_INT_SAMPLER_BUFFER ||
661 type == GL_INT_SAMPLER_2D_RECT ||
662 type == GL_UNSIGNED_INT_SAMPLER_1D ||
663 type == GL_UNSIGNED_INT_SAMPLER_2D ||
664 type == GL_UNSIGNED_INT_SAMPLER_3D ||
665 type == GL_UNSIGNED_INT_SAMPLER_CUBE ||
666 type == GL_UNSIGNED_INT_SAMPLER_1D_ARRAY ||
667 type == GL_UNSIGNED_INT_SAMPLER_2D_ARRAY ||
668 type == GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE ||
669 type == GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY ||
670 type == GL_UNSIGNED_INT_SAMPLER_BUFFER ||
671 type == GL_UNSIGNED_INT_SAMPLER_2D_RECT){
673 glGetActiveUniformsiv(programId, 1, &i, GL_UNIFORM_SIZE, &size2);
675 std::string alt(nameBuf.data());
676 std::string name = alt.substr(0, alt.find(
'['));
679 auto samplerHash =
Cogs::hash(name +
"Sampler");
680 effect.samplers[samplerHash] = { effect.unitsInUse, size2 };
685 effect.samplers[samplerHash] = { effect.unitsInUse, size2 };
692 effect.textures[textureHash] = effect.unitsInUse;
693 effect.samplers[textureHash] = { effect.unitsInUse, 1 };
696 GLint location = glGetUniformLocation(programId, nameBuf.data());
697 assert(0 <= location);
698 glUniform1i(location, effect.unitsInUse);
703 for(GLint j=0; j<size2; j++){
704 std::string namea = name +
'[' + std::to_string(j) +
']';
706 effect.textures[textureHash] = effect.unitsInUse;
707 effect.samplers[textureHash] = { effect.unitsInUse, 1 };
710 GLint location = glGetUniformLocation(programId, namea.c_str());
711 assert(0 <= location);
712 glUniform1i(location, effect.unitsInUse);
718 if (logInputs) LOG_DEBUG(logger,
"Program %d: Active uniform %d: type='%s', symbol='%s'.", programId, i, getShaderUniformTypeString(type), nameBuf.data());
722 ::memset(&effect.attributeMap, InvalidAttributeLocationGL20, MaxVertexAttributesGL20);
724 GLint activeAttributes = 0;
725 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
728 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
730 std::vector<char> buffer(maxLength);
732 for (
int i = 0; i < activeAttributes; ++i) {
735 GLenum type = GL_INVALID_ENUM;
737 glGetActiveAttrib(programId,
static_cast<GLsizei
>(i),
static_cast<GLsizei
>(buffer.size()), &length, &size, &type, buffer.data());
739 const GLint index = this->attributes.getAttributeIndex(std::string(buffer.data()), hlsl);
740 const GLint location = glGetAttribLocation(programId, buffer.data());
742 if (uint32_t(index) != GL_INVALID_INDEX && uint32_t(location) != GL_INVALID_INDEX) {
743 assert(location >= 0 && location <= 255 &&
"Attribute location out of range.");
744 effect.attributeMap[index] =
static_cast<unsigned char>(location);
747 if (logInputs) LOG_DEBUG(logger,
"Program %d: Active attribute %d: type='%s', symbol='%s'.", programId, i, getShaderUniformTypeString(type), buffer.data());
750 glUseProgram(savedProgram);
751 return this->effects.addResource(std::move(effect));
756 if (!HandleIsValid(handle))
return;
758 if(context->getEffect() == handle)
761 auto & effect = this->effects[handle];
763 for (
auto & s : effect.shaders) {
764 if (HandleIsValid(s.shaderHandle)) {
765 releaseShader(s.shaderHandle);
769 glDeleteProgram(this->effects[handle].programId);
771 for (
auto & b : effect.atomicCounterBuffers) {
772 auto name = this->backingBuffers[b.backingBuffer];
773 glDeleteBuffers(1, &name);
774 this->backingBuffers.removeResource(b.backingBuffer);
777 for(
auto smap : effect.sampler_map){
781 this->effects.removeResource(handle);
784void Cogs::EffectsGL20::releaseShader(
ShaderHandle shaderHandle)
786 glDeleteShader(this->shaderIds[shaderHandle]);
787 this->shaderIds.removeResource(shaderHandle);
792 assert(HandleIsValid(effectHandle) && this->effects.hasResource(effectHandle) &&
"Effect handle not valid.");
794 const GLuint programId = this->effects[effectHandle].programId;
796 auto index = glGetUniformBlockIndex(programId, name.
data());
798 if (index == GL_INVALID_INDEX) {
809 assert(HandleIsValid(effectHandle) && this->effects.hasResource(effectHandle) &&
"Effect handle not valid.");
812 std::string name = std::string(name_view);
813 const auto& effect = this->effects[effectHandle];
814 const auto programId = effect.programId;
816 auto index = glGetProgramResourceIndex(programId, GL_SHADER_STORAGE_BLOCK, name.c_str());
817 if (index == GL_INVALID_INDEX) {
818 auto alt_name =
"_" + name;
819 index = glGetProgramResourceIndex(programId, GL_SHADER_STORAGE_BLOCK, alt_name.c_str());
820 if (index == GL_INVALID_INDEX) {
821 LOG_DEBUG(logger,
"Failed to get index of shader storage block '%s'.", name.c_str());
826 GLenum props[] = {GL_BUFFER_BINDING};
827 GLint shaderStorageBinding = -1;
828 glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, index,
830 static_cast<GLsizei
>(
sizeof(shaderStorageBinding)),
nullptr, &shaderStorageBinding);
832 uint32_t atomicCounterBinding = 0;
833 auto counterName = name +
"_Store_counter";
834 for (uint32_t i = 0; i < effect.atomicCounterVariables.size(); i++) {
835 if (effect.atomicCounterVariables[i].name == counterName) {
836 atomicCounterBinding = i;
842 BufferBindingHandle handle((uint64_t(shaderStorageBinding) + 1) << 32 | (uint64_t(atomicCounterBinding) + 1));
861 auto context = graphicsDevice->getImmediateContext();
863 std::vector<EffectHandle> handles;
864 for (
auto & effect : effects) {
865 auto handle = effects.getHandle(effect);
866 if (!effects.pinned(handle)) {
867 handles.emplace_back(handle);
871 for (
auto & handle : handles) {
872 releaseEffect(handle);
895 bool hlslAttr =
false;
899 if (&vsSource == &psSource) {
900 processedSource.shaderSource = vsSource.content;
902 processedSource.vsSource = vsSource.content;
903 processedSource.gsSource = gsSource.content;
904 processedSource.psSource = psSource.content;
915 std::unordered_map<size_t, std::vector<size_t>> real_sampler;
918#ifdef COGS_ENABLE_GLSLANG
919 glslang::InitializeProcess();
923 ShaderType::EShaderType type;
925 const std::string & source;
927 EShLanguage language;
935 std::vector<ShaderInput> inputs;
936 if(vsSource.content.size()){
938 {ShaderType::VertexShader,
"VS", vsSource.content, vsEntryPoint, EShLangVertex, shader_num++ });
940 if(hsSource.content.size()){
941 targetVersion = std::max(targetVersion, 410);
943 { ShaderType::HullShader,
"HS", hsSource.content, hsEntryPoint, EShLangTessControl, shader_num++ });
945 if(dsSource.content.size()){
946 targetVersion = std::max(targetVersion, 410);
948 { ShaderType::DomainShader,
"DS", dsSource.content, dsEntryPoint, EShLangTessEvaluation, shader_num++ });
950 if(gsSource.content.size()){
951 targetVersion = std::max(targetVersion, 410);
953 { ShaderType::GeometryShader,
"GS", gsSource.content, gsEntryPoint, EShLangGeometry, shader_num++ });
955 if(psSource.content.size()){
957 { ShaderType::PixelShader,
"PS", psSource.content, psEntryPoint, EShLangFragment, shader_num++ });
960 std::string strings[ShaderType::NumShaderTypes];
962 glslang::TProgram program;
963 std::vector<std::unique_ptr<glslang::TShader>> shaders(ShaderType::NumShaderTypes);
964 std::unordered_map<size_t, std::string> variableMap;
966 for (
auto & shaderSource : inputs) {
967 shaders[shaderSource.language] = std::make_unique<glslang::TShader>(shaderSource.language);
968 auto & shader = *shaders[shaderSource.language];
970 std::vector<std::string> definitions(desc.definitions.size()+1);
971 std::vector<const char *> shaderStrings(desc.definitions.size()+3);
973 shaderStrings[0] =
"#pragma pack_matrix(row_major)\n";
974 for (
size_t i = 0; i < desc.definitions.size(); ++i) {
975 auto & d = desc.definitions[i];
976 auto str =
"#define " + d.first +
" " + d.second +
"\n";
977 definitions[i] = str;
978 shaderStrings[i+1] = definitions[i].c_str();
981 size_t i = definitions.size()-1;
982 auto str =
"#define GLSLANG\n";
983 definitions[i] = str;
984 shaderStrings[i+1] = definitions[i].c_str();
987 shaderStrings[shaderStrings.size()-1] = shaderSource.source.c_str();
989#ifdef COGS_DUMP_SHADERS
992 sprintf(num,
"%04d", shaderSource.num);
993 std::string file = IO::getTempPath() + num +
".hlsl";
994 FILE *fp = fopen(file.c_str(),
"wb");
996 LOG_INFO(logger,
"Write HLSL to %s", file.c_str());
997 for(
auto &t : shaderStrings){
998 fprintf(fp,
"%s", t);
1005 shader.setStrings(shaderStrings.data(), (
int)shaderStrings.size());
1006 shader.setEntryPoint(shaderSource.entryPoint.data());
1007 shader.setSourceEntryPoint(shaderSource.entryPoint.data());
1010 shader.setHlslIoMapping(
true);
1011 shader.setEnvInput(glslang::EShSourceHlsl, shaderSource.language, glslang::EShClientOpenGL, 100);
1012 shader.setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_3);
1013 shader.setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450);
1014 shader.setEnvTargetHlslFunctionality1();
1016 int defaultVersion = 460;
1017 bool forwardCompatible =
true;
1019 EShMessages messages = EShMsgDefault;
1020 std::string pOutput;
1021 glslang::TShader::ForbidIncluder includer;
1023 shader.parse(&resources, defaultVersion, ECoreProfile,
false, forwardCompatible, messages, includer);
1025 auto infoLog =
StringView(shader.getInfoLog());
1026 if(!infoLog.empty()){
1027 LOG_INFO(logger,
"glslang info_log: %s", infoLog.data());
1030 auto infoDebugLog =
StringView(shader.getInfoDebugLog());
1031 if(!infoDebugLog.empty()){
1032 LOG_INFO(logger,
"glslang info_debug_log: %s", infoDebugLog.data());
1035 program.addShader(&shader);
1038 EShMessages messages = EShMsgDefault;
1039 program.link(messages);
1041 auto linkInfo =
StringView(program.getInfoLog());
1042 if (!linkInfo.empty()) {
1043 LOG_WARNING(logger,
"%s", linkInfo.data());
1048 auto ioInfo =
StringView(program.getInfoLog());
1049 if (!ioInfo.empty()) {
1050 LOG_WARNING(logger,
"%s", ioInfo.data());
1053 program.buildReflection();
1055 auto reflectionInfoLog =
StringView(program.getInfoLog());
1056 if (!reflectionInfoLog.empty()) {
1057 LOG_WARNING(logger,
"%s", reflectionInfoLog.data());
1060 for (
auto & shaderSource : inputs) {
1061 std::vector<unsigned int> spirv;
1063 spv::SpvBuildLogger buildLogger;
1065 glslang::SpvOptions spvOptions;
1066 spvOptions.generateDebugInfo =
false;
1067 spvOptions.disableOptimizer =
false;
1068 spvOptions.optimizeSize =
false;
1070 auto intermediateShader = program.getIntermediate(shaderSource.language);
1071 glslang::GlslangToSpv(*intermediateShader, spirv, &buildLogger, &spvOptions);
1075#ifdef COGS_DUMP_SHADERS
1078 sprintf(num,
"%04d", shaderSource.num);
1079 std::string file = IO::getTempPath() + num +
".spv";
1080 std::ofstream out(file.c_str(), std::ofstream::out);
1082 LOG_INFO(logger,
"Write SPV to %s", file.c_str());
1083 spv::Disassemble(out, spirv);
1088 spirv_cross::CompilerGLSL glsl(std::move(spirv));
1089 glsl.build_dummy_sampler_for_combined_images();
1090 glsl.build_combined_image_samplers();
1092 spirv_cross::ShaderResources shaderResources;
1093 auto active = glsl.get_active_interface_variables();
1094 shaderResources = glsl.get_shader_resources(active);
1095 glsl.set_enabled_interface_variables(move(active));
1097 for (
auto & input : shaderResources.stage_inputs) {
1098 auto location = glsl.get_decoration(input.id, spv::DecorationLocation);
1099 auto hlslSemantic = glsl.get_decoration_string(input.id, spv::DecorationHlslSemanticGOOGLE);
1100 auto[semantic, semanticIndex] = getSemanticWithIndex(hlslSemantic);
1101 auto isBuiltIn = glsl.get_decoration(input.id, spv::DecorationBuiltIn);
1104 std::string newName;
1107 switch (shaderSource.type) {
1108 case ShaderType::GeometryShader: newName =
"vsOutput";
break;
1109 case ShaderType::PixelShader: newName = gsSource.content.empty() ?
"vsOutput" :
"gsOutput";
break;
1110 case ShaderType::VertexShader: newName =
"a_";
break;
1112 glsl.set_name(input.id, newName + std::string(semantic) + std::to_string(semanticIndex));
1115 LOG_TRACE(logger,
"%s Input: %s, [%s] %d", shaderSource.stage, input.name.c_str(), hlslSemantic.c_str(), location);
1118 auto & combinedSamplers = glsl.get_combined_image_samplers();
1120 for (
auto & c : combinedSamplers) {
1121 auto & tex = glsl.get_name(c.image_id);
1122 glsl.set_name(c.combined_id, tex);
1123 auto & sampler = glsl.get_name(c.sampler_id);
1124 auto & combined = glsl.get_name(c.combined_id);
1134 for (
auto & input : shaderResources.uniform_buffers) {
1135 auto loc = glsl.get_decoration(input.id, spv::DecorationBinding);
1137 LOG_TRACE(logger,
"%s Uniform buffer: %s, %d", shaderSource.stage, input.name.c_str(), loc);
1139 glsl.set_name(input.id,
"_" + input.name);
1141 auto activeMembers = glsl.get_active_buffer_ranges(input.id);
1142 auto & baseType = glsl.get_type(input.base_type_id);
1144 for (
auto & m : activeMembers) {
1145 auto & member = glsl.get_member_name(input.base_type_id, m.index);
1146 auto & memberTypeId = baseType.member_types[m.index];
1147 auto & memberType = glsl.get_type(memberTypeId);
1148 auto & memberBase = memberType.parent_type ? glsl.get_type(memberType.parent_type) : memberType;
1150 auto size = glsl.get_declared_struct_member_size(baseType, m.index);
1152 LOG_TRACE(logger,
" %s, size: %zu", member.c_str(), size);
1154 if (!memberType.array.empty()) {
1155 for (
size_t i = 0; i < memberType.array[0]; ++i) {
1156 if (memberBase.basetype == spirv_cross::SPIRType::Struct) {
1157 for (uint32_t j = 0; j < memberBase.member_types.size(); ++j) {
1158 auto & nestedMember = glsl.get_member_name(memberType.parent_type, j);
1160 auto mn = member +
"[" + std::to_string(i) +
"]." + nestedMember;
1161 auto nn =
"_" + input.name +
"." + mn;
1166 auto mn = member +
"[" + std::to_string(i) +
"]";
1167 auto nn =
"_" + input.name +
"." + mn;
1172 variableMap[
Cogs::hash(member)] =
"_" + input.name +
"." + member;
1177 for (
auto & output : shaderResources.stage_outputs) {
1178 auto location = glsl.get_decoration(output.id, spv::DecorationLocation);
1179 auto hlslSemantic = glsl.get_decoration_string(output.id, spv::DecorationHlslSemanticGOOGLE);
1180 auto[semantic, semanticIndex] = getSemanticWithIndex(hlslSemantic);
1181 auto isBuiltIn = glsl.get_decoration(output.id, spv::DecorationBuiltIn);
1184 std::string newName;
1186 switch (shaderSource.type) {
1187 case ShaderType::GeometryShader: newName =
"gsOutput";
break;
1188 case ShaderType::VertexShader: newName =
"vsOutput";
break;
1190 glsl.set_name(output.id, newName + std::string(semantic) + std::to_string(semanticIndex));
1193 LOG_TRACE(logger,
"%s Output: %s, [%s] %d", shaderSource.stage, output.name.c_str(), hlslSemantic.c_str(), location);
1196 spirv_cross::CompilerGLSL::Options options;
1197#if defined( __APPLE__ )
1198 options.enable_420pack_extension =
false;
1200 options.version = targetVersion;
1202 glsl.set_common_options(options);
1204 auto glslSource = glsl.compile();
1205 strings[shaderSource.type] = glslSource;
1207#ifdef COGS_DUMP_SHADERS
1210 sprintf(num,
"%04d", shaderSource.num);
1211 std::string file = IO::getTempPath() + num +
".glsl";
1212 FILE *fp = fopen(file.c_str(),
"wb");
1214 LOG_INFO(logger,
"Write GLSL to %s", file.c_str());
1215 fprintf(fp,
"%s", glslSource.c_str());
1221 if(shaderSource.type == ShaderType::VertexShader){
1222 vertexShader = loadShader(GL_VERTEX_SHADER, glslSource.c_str(), {});
1224 if(shaderSource.type == ShaderType::HullShader){
1225 hullShader = loadShader(GL_TESS_CONTROL_SHADER, glslSource.c_str(), {});
1227 if(shaderSource.type == ShaderType::DomainShader){
1228 domainShader = loadShader(GL_TESS_EVALUATION_SHADER, glslSource.c_str(), {});
1230 if(shaderSource.type == ShaderType::GeometryShader){
1231 geometryShader = loadShader(GL_GEOMETRY_SHADER, glslSource.c_str(), {});
1233 if(shaderSource.type == ShaderType::PixelShader){
1234 pixelShader = loadShader(GL_FRAGMENT_SHADER, glslSource.c_str(), {});
1238 glslang::FinalizeProcess();
1240 LOG_WARNING(logger,
"Cross compilation requested, but cross compilation is not supported.");
1243#ifdef COGS_ENABLE_GLSLANG
1249 vertexShader = loadShader(GL_VERTEX_SHADER, processedSource.vsSource.c_str(), desc.flags, usedDefinitions);
1250 if(processedSource.gsSource.size())
1251 geometryShader = loadShader(GL_GEOMETRY_SHADER, processedSource.gsSource.c_str(), desc.flags, usedDefinitions);
1252 if(processedSource.psSource.size())
1253 pixelShader = loadShader(GL_FRAGMENT_SHADER, processedSource.psSource.c_str(), desc.flags, usedDefinitions);
1257 auto effectHandle = loadProgram(vertexShader, hullShader, domainShader, geometryShader, pixelShader, desc.flags, hlslAttr);
1260 auto & effect = effects[effectHandle];
1261 effect.real_sampler = std::move(real_sampler);
1265 if(!isHlsl ||
true){
1267 glGetProgramiv(effect.programId, GL_ACTIVE_ATTRIBUTES, &attributes);
1269 glGetProgramiv(effect.programId, GL_ACTIVE_UNIFORMS, &uniforms);
1270 GLint uniformBlocks;
1271 glGetProgramiv(effect.programId, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlocks);
1273 for (
size_t i = 0; i < (size_t)ShaderType::NumShaderSlots; ++i) {
1275 shader.constantBuffers.resize(uniformBlocks);
1277 for (
unsigned int l = 0; l < unsigned(uniformBlocks); ++l) {
1278 GLchar blockName[256];
1280 glGetActiveUniformBlockName(effect.programId, l,
static_cast<GLsizei
>(
sizeof(blockName)), &length, blockName);
1281 blockName[255] =
'\0';
1284 glGetActiveUniformBlockiv(effect.programId, l, GL_UNIFORM_BLOCK_DATA_SIZE, &block_size);
1285 GLint block_uniforms;
1286 glGetActiveUniformBlockiv(effect.programId, l, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &block_uniforms);
1287 GLuint *indices =
new GLuint[block_uniforms];
1288 glGetActiveUniformBlockiv(effect.programId, l, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (GLint*)indices);
1290 auto & constantBuffer = shader.constantBuffers[l];
1291 constantBuffer.slot = l;
1292 constantBuffer.dirty =
true;
1293 shader.slots[
StringId(blockName)] = l;
1294 constantBuffer.name = blockName;
1296 constantBuffer.offsets.resize(0);
1297 constantBuffer.sizes.resize(0);
1298 constantBuffer.size = block_size;
1300 GLint *uOffset =
new GLint[block_uniforms];
1301 GLint *uSize =
new GLint[block_uniforms];
1302 GLint *uArrayStride =
new GLint[block_uniforms];
1303 glGetActiveUniformsiv(effect.programId, block_uniforms, indices, GL_UNIFORM_OFFSET, uOffset);
1304 glGetActiveUniformsiv(effect.programId, block_uniforms, indices, GL_UNIFORM_SIZE, uSize);
1306 glGetActiveUniformsiv(effect.programId, block_uniforms, indices, GL_UNIFORM_ARRAY_STRIDE, uArrayStride);
1307 for(
unsigned int j=0; j<unsigned(block_uniforms); j++){
1308 GLchar uniformName[256];
1309 GLsizei uniformNameLength;
1310 glGetActiveUniformName(effect.programId, indices[j],
static_cast<GLsizei
>(
sizeof(uniformName)), &uniformNameLength, uniformName);
1311 uniformName[255] =
'\0';
1314 strchr(uniformName,
'[')[0] =
'\0';
1315 GLchar *n = strchr(uniformName,
'.');
1316 if(!n) n = uniformName;
1320 for (
unsigned int k = 0; k<unsigned(uSize[j]); k++) {
1321 std::string indexedUniformName(nn+
"["+std::to_string(k)+
"]");
1322 constantBuffer.variables[
StringId(indexedUniformName)] =
static_cast<uint16_t
>(constantBuffer.offsets.size());
1323 constantBuffer.offsets.push_back(
static_cast<uint64_t
>(uOffset[j]) +
static_cast<uint64_t
>(uArrayStride[j])* k);
1324 constantBuffer.sizes.push_back(
static_cast<uint64_t
>(uArrayStride[j]));
1328 GLchar *n = strchr(uniformName,
'.');
1329 if(!n) n = uniformName;
1332 constantBuffer.variables[
StringId(n)] =
static_cast<uint16_t
>(constantBuffer.offsets.size());
1333 constantBuffer.offsets.push_back(uOffset[j]);
1334 constantBuffer.sizes.push_back(1);
1339 delete [] uArrayStride;
1345 for (
size_t i = 0; i < (size_t)ShaderType::NumShaderSlots; ++i) {
1346 effect.shaders[i].reflection = reflectionInfo[i];
1349 for (
size_t i = 0; i < (size_t)ShaderType::NumShaderSlots; ++i) {
1350 for (
auto & cb : effect.shaders[i].reflection.constantBuffers) {
1353 cb.memoryBuffer.resize(cb.size);
1357 if (cb.name ==
"$Globals") {
1359 cb.index = glGetUniformBlockIndex(effect.programId,
"Globals");
1361 cb.index = glGetUniformBlockIndex(effect.programId, cb.name.c_str());
1367 return effectHandle;
1375 if (!glDispatchCompute) {
1380 Utilities::preprocessFile(handler, fileName, csSourceProcessed);
1383 source.shaderSource = csSourceProcessed.content;
1385 std::unordered_map<size_t, std::vector<size_t>> real_sampler;
1387 if (fileName.find(
".hlsl") != std::string::npos || fileName.find(
".fx") != std::string::npos) {
1388#ifdef COGS_ENABLE_GLSLANG
1389 glslang::InitializeProcess();
1393 ShaderType::EShaderType type;
1395 const std::string & source;
1397 EShLanguage language;
1404 targetVersion = std::max(targetVersion, 430);
1406 ShaderInput shaderSource = {ShaderType::ComputeShader,
"CS", source.shaderSource,
"main", EShLangCompute, shader_num++ };
1408 glslang::TProgram program;
1409 std::unique_ptr<glslang::TShader> shaderp;
1410 std::unordered_map<size_t, std::string> variableMap;
1413 shaderp = std::make_unique<glslang::TShader>(shaderSource.language);
1414 auto & shader = *shaderp;
1416 std::vector<std::string> defs(definitions.size());
1417 std::vector<const char *> shaderStrings(definitions.size()+1);
1419 shaderStrings[0] =
"#pragma pack_matrix(row_major)\n";
1420 for (
size_t i = 0; i < definitions.size(); ++i) {
1421 auto & d = definitions[i];
1422 auto str =
"#define " + d.first +
" " + d.second +
"\n";
1424 shaderStrings[i+1] = defs[i].c_str();
1427 shaderStrings.emplace_back(shaderSource.source.c_str());
1429#ifdef COGS_DUMP_SHADERS
1432 sprintf(num,
"%04d", shaderSource.num);
1433 std::string file = IO::getTempPath() + num +
".hlsl";
1434 FILE *fp = fopen(file.c_str(),
"wb");
1436 LOG_INFO(logger,
"Write HLSL to %s", file.c_str());
1437 for(
auto &t : shaderStrings){
1438 fprintf(fp,
"%s", t);
1445 shader.setStrings(shaderStrings.data(), (
int)shaderStrings.size());
1446 shader.setEntryPoint(shaderSource.entryPoint.data());
1447 shader.setSourceEntryPoint(shaderSource.entryPoint.data());
1448 shader.setAutoMapBindings(
true);
1450 shader.setHlslIoMapping(
true);
1451 shader.setEnvInput(glslang::EShSourceHlsl, shaderSource.language, glslang::EShClientOpenGL, 100);
1452 shader.setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_3);
1453 shader.setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450);
1454 shader.setEnvTargetHlslFunctionality1();
1456 int defaultVersion = 460;
1457 bool forwardCompatible =
true;
1459 EShMessages messages = EShMsgDefault;
1460 std::string pOutput;
1461 glslang::TShader::ForbidIncluder includer;
1463 shader.parse(&resources, defaultVersion, ECoreProfile,
false, forwardCompatible, messages, includer);
1465 auto infoLog =
StringView(shader.getInfoLog());
1466 if(!infoLog.empty()){
1467 LOG_INFO(logger,
"glslang info_log: %s", infoLog.data());
1470 auto infoDebugLog =
StringView(shader.getInfoDebugLog());
1471 if(!infoDebugLog.empty()){
1472 LOG_INFO(logger,
"glslang info_debug_log: %s", infoDebugLog.data());
1475 program.addShader(&shader);
1478 EShMessages messages = EShMsgDefault;
1479 program.link(messages);
1481 auto linkInfo =
StringView(program.getInfoLog());
1482 if (!linkInfo.empty()) {
1483 LOG_WARNING(logger,
"%s", linkInfo.data());
1488 auto ioInfo =
StringView(program.getInfoLog());
1489 if (!ioInfo.empty()) {
1490 LOG_WARNING(logger,
"%s", ioInfo.data());
1493 program.buildReflection();
1495 auto reflectionInfoLog =
StringView(program.getInfoLog());
1496 if (!reflectionInfoLog.empty()) {
1497 LOG_WARNING(logger,
"%s", reflectionInfoLog.data());
1501 std::vector<unsigned int> spirv;
1503 spv::SpvBuildLogger buildLogger;
1505 glslang::SpvOptions spvOptions;
1506 spvOptions.generateDebugInfo =
false;
1507 spvOptions.disableOptimizer =
false;
1508 spvOptions.optimizeSize =
false;
1510 auto intermediateShader = program.getIntermediate(shaderSource.language);
1511 glslang::GlslangToSpv(*intermediateShader, spirv, &buildLogger, &spvOptions);
1515#ifdef COGS_DUMP_SHADERS
1518 sprintf(num,
"%04d", shaderSource.num);
1519 std::string file = IO::getTempPath() + num +
".spv";
1520 std::ofstream out(file.c_str(), std::ofstream::out);
1522 LOG_INFO(logger,
"Write SPV to %s", file.c_str());
1523 spv::Disassemble(out, spirv);
1528 spirv_cross::CompilerGLSL glsl(std::move(spirv));
1529 glsl.build_dummy_sampler_for_combined_images();
1530 glsl.build_combined_image_samplers();
1532 spirv_cross::ShaderResources shaderResources;
1533 auto active = glsl.get_active_interface_variables();
1534 shaderResources = glsl.get_shader_resources(active);
1535 glsl.set_enabled_interface_variables(move(active));
1537 auto & combinedSamplers = glsl.get_combined_image_samplers();
1539 for (
auto & c : combinedSamplers) {
1540 auto & tex = glsl.get_name(c.image_id);
1541 glsl.set_name(c.combined_id, tex);
1542 auto & sampler = glsl.get_name(c.sampler_id);
1543 auto & combined = glsl.get_name(c.combined_id);
1545 LOG_TRACE(logger,
" %s Image %s, Sampler: %s: Combined %s", shaderSource.stage, tex.c_str(), sampler.c_str(), combined.c_str());
1548 real_sampler[samplerHash].push_back(
Cogs::hash(combined));
1553 for (
auto & input : shaderResources.uniform_buffers) {
1554 auto loc = glsl.get_decoration(input.id, spv::DecorationBinding);
1556 LOG_TRACE(logger,
"%s Uniform buffer: %s, %d", shaderSource.stage, input.name.c_str(), loc);
1558 glsl.set_name(input.id,
"_" + input.name);
1560 auto activeMembers = glsl.get_active_buffer_ranges(input.id);
1561 auto & baseType = glsl.get_type(input.base_type_id);
1563 for (
auto & m : activeMembers) {
1564 auto & member = glsl.get_member_name(input.base_type_id, m.index);
1565 auto & memberTypeId = baseType.member_types[m.index];
1566 auto & memberType = glsl.get_type(memberTypeId);
1567 auto & memberBase = memberType.parent_type ? glsl.get_type(memberType.parent_type) : memberType;
1569 auto size = glsl.get_declared_struct_member_size(baseType, m.index);
1571 LOG_TRACE(logger,
" %s, size: %zu", member.c_str(), size);
1573 if (!memberType.array.empty()) {
1574 for (
size_t i = 0; i < memberType.array[0]; ++i) {
1575 if (memberBase.basetype == spirv_cross::SPIRType::Struct) {
1576 for (uint32_t j = 0; j < memberBase.member_types.size(); ++j) {
1577 auto & nestedMember = glsl.get_member_name(memberType.parent_type, j);
1579 auto mn = member +
"[" + std::to_string(i) +
"]." + nestedMember;
1580 auto nn =
"_" + input.name +
"." + mn;
1585 auto mn = member +
"[" + std::to_string(i) +
"]";
1586 auto nn =
"_" + input.name +
"." + mn;
1591 variableMap[
Cogs::hash(member)] =
"_" + input.name +
"." + member;
1596 for (
auto & input : shaderResources.storage_buffers) {
1597 auto loc = glsl.get_decoration(input.id, spv::DecorationBinding);
1599 LOG_TRACE(logger,
"%s Storage buffer: %s, %d", shaderSource.stage, input.name.c_str(), loc);
1601 glsl.set_name(input.id,
"_" + input.name);
1603 auto activeMembers = glsl.get_active_buffer_ranges(input.id);
1604 auto & baseType = glsl.get_type(input.base_type_id);
1606 for (
auto & m : activeMembers) {
1607 auto & member = glsl.get_member_name(input.base_type_id, m.index);
1608 auto & memberTypeId = baseType.member_types[m.index];
1609 auto & memberType = glsl.get_type(memberTypeId);
1610 auto & memberBase = memberType.parent_type ? glsl.get_type(memberType.parent_type) : memberType;
1612 auto size = glsl.get_declared_struct_member_size(baseType, m.index);
1614 LOG_TRACE(logger,
" %s, size: %zu", member.c_str(), size);
1616 if (!memberType.array.empty()) {
1617 for (
size_t i = 0; i < memberType.array[0]; ++i) {
1618 if (memberBase.basetype == spirv_cross::SPIRType::Struct) {
1619 for (uint32_t j = 0; j < memberBase.member_types.size(); ++j) {
1620 auto & nestedMember = glsl.get_member_name(memberType.parent_type, j);
1622 auto mn = member +
"[" + std::to_string(i) +
"]." + nestedMember;
1623 auto nn =
"_" + input.name +
"." + mn;
1628 auto mn = member +
"[" + std::to_string(i) +
"]";
1629 auto nn =
"_" + input.name +
"." + mn;
1634 variableMap[
Cogs::hash(member)] =
"_" + input.name +
"." + member;
1639 for (
auto & output : shaderResources.stage_outputs) {
1640 auto location = glsl.get_decoration(output.id, spv::DecorationLocation);
1641 auto hlslSemantic = glsl.get_decoration_string(output.id, spv::DecorationHlslSemanticGOOGLE);
1642 auto[semantic, semanticIndex] = getSemanticWithIndex(hlslSemantic);
1643 auto isBuiltIn = glsl.get_decoration(output.id, spv::DecorationBuiltIn);
1646 std::string newName;
1648 switch (shaderSource.type) {
1649 case ShaderType::GeometryShader: newName =
"gsOutput";
break;
1650 case ShaderType::VertexShader: newName =
"vsOutput";
break;
1652 glsl.set_name(output.id, newName + std::string(semantic) + std::to_string(semanticIndex));
1655 LOG_TRACE(logger,
"%s Output: %s, [%s] %d", shaderSource.stage, output.name.c_str(), hlslSemantic.c_str(), location);
1658 spirv_cross::CompilerGLSL::Options options;
1659 options.version = targetVersion;
1661 glsl.set_common_options(options);
1663 auto glslSource = glsl.compile();
1664 source.shaderSource = glslSource;
1666#ifdef COGS_DUMP_SHADERS
1669 sprintf(num,
"%04d", shaderSource.num);
1670 std::string file = IO::getTempPath() + num +
".glsl";
1671 FILE *fp = fopen(file.c_str(),
"wb");
1673 LOG_INFO(logger,
"Write GLSL to %s", file.c_str());
1674 fprintf(fp,
"%s", glslSource.c_str());
1683 glslang::FinalizeProcess();
1685 LOG_WARNING(logger,
"HLSL shader detected but cross compilation of shaders disabled.");
1690 effect.real_sampler = std::move(real_sampler);
1691 effect.computeShader.shaderHandle = loadShader(GL_COMPUTE_SHADER, source.shaderSource.c_str(), effectFlags);
1693 const GLuint programId = glCreateProgram();
1695 if (programId == GL_INVALID_INDEX) {
1699 glAttachShader(programId, this->shaderIds[effect.computeShader.shaderHandle]);
1700 checkGLError(
"glAttachShader");
1702 glLinkProgram(programId);
1704 GLint linkStatus = GL_FALSE;
1705 glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
1707 if (linkStatus != GL_TRUE) {
1708 printProgramError(programId, effectFlags);
1710 glDeleteProgram(programId);
1714 printProgramError(programId, effectFlags,
false);
1717 effect.programId = programId;
1722 glGetProgramiv(effect.programId, GL_ACTIVE_ATTRIBUTES, &attributes);
1724 glGetProgramiv(effect.programId, GL_ACTIVE_UNIFORMS, &uniforms2);
1725 GLint uniformBlocks;
1726 glGetProgramiv(effect.programId, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlocks);
1730 shader.constantBuffers.resize(uniformBlocks);
1732 for (GLint i = 0; i < uniformBlocks; ++i) {
1735 glGetActiveUniformBlockName(effect.programId, i,
static_cast<GLsizei
>(
sizeof(name2)), &length2, name2);
1739 glGetActiveUniformBlockiv(effect.programId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
1741 glGetActiveUniformBlockiv(effect.programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &uniforms);
1742 GLuint *indices =
new GLuint[uniforms];
1743 glGetActiveUniformBlockiv(effect.programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (GLint*)indices);
1745 auto & constantBuffer = shader.constantBuffers[i];
1746 constantBuffer.slot = i;
1747 constantBuffer.dirty =
true;
1749 constantBuffer.name = name2;
1751 constantBuffer.offsets.resize(0);
1752 constantBuffer.sizes.resize(0);
1753 constantBuffer.size = size;
1755 GLint *uOffset =
new GLint[uniforms];
1756 GLint *uSize =
new GLint[uniforms];
1757 GLint *uArrayStride =
new GLint[uniforms];
1758 glGetActiveUniformsiv(effect.programId, uniforms, indices, GL_UNIFORM_OFFSET, uOffset);
1759 glGetActiveUniformsiv(effect.programId, uniforms, indices, GL_UNIFORM_SIZE, uSize);
1761 glGetActiveUniformsiv(effect.programId, uniforms, indices, GL_UNIFORM_ARRAY_STRIDE, uArrayStride);
1762 for(GLint j=0; j<uniforms; j++){
1765 glGetActiveUniformName(effect.programId, indices[j],
static_cast<GLsizei
>(
sizeof(name3)), &length, name3);
1769 strchr(name3,
'[')[0] =
'\0';
1770 GLchar *n = strchr(name3,
'.');
1775 for(GLint k=0; k<uSize[j]; k++){
1776 std::string name(nn+
"["+std::to_string(k)+
"]");
1777 constantBuffer.variables[
StringId(name)] =
static_cast<uint16_t
>(constantBuffer.offsets.size());
1778 constantBuffer.offsets.push_back(
static_cast<uint64_t
>(uOffset[j]) +
static_cast<uint64_t
>(uArrayStride[j])*k);
1779 constantBuffer.sizes.push_back(uArrayStride[j]);
1783 GLchar *n = strchr(name3,
'.');
1787 constantBuffer.variables[
StringId(n)] =
static_cast<uint16_t
>(constantBuffer.offsets.size());
1788 constantBuffer.offsets.push_back(
static_cast<uint64_t
>(uOffset[j]));
1789 constantBuffer.sizes.push_back(1);
1794 delete [] uArrayStride;
1797 effect.shaders[ShaderType::ComputeShader].reflection = shader;
1802 size_t i = ShaderType::ComputeShader;
1803 for (
auto & cb : effect.shaders[i].reflection.constantBuffers) {
1805 if (cb.size && !HandleIsValid(cb.buffer)) {
1806 cb.memoryBuffer.resize(cb.size);
1810 if (cb.name ==
"$Globals") {
1812 cb.index = glGetUniformBlockIndex(effect.programId,
"Globals");
1814 cb.index = glGetUniformBlockIndex(effect.programId, cb.name.c_str());
1820 return this->effects.addResource(std::move(effect));
1825 if (!HandleIsValid(effectHandle)) {
1826 LOG_ERROR(logger,
"Tried to fetch texture variable from invalid/empty effect handle.");
1829 auto & effect = effects[effectHandle];
1831 auto it = effect.textures.find(
hash);
1832 if (it != effect.textures.end()) {
1833 auto unit = it->second;
1841 if (!HandleIsValid(effectHandle)) {
1842 LOG_WARNING(logger,
"Tried to fetch sampler variable from invalid/empty effect handle.");
1845 auto & effect = effects[effectHandle];
1847 auto it = effect.samplers.find(
hash);
1848 auto it2 = effect.real_sampler.find(
hash);
1849 if (it != effect.samplers.end() || it2 != effect.real_sampler.end()) {
1850 if(!effect.sampler_map.count(
hash)){
1852 tmp->effectHandle = effectHandle;
1854 effect.sampler_map[
hash] = tmp;
1864 if(name.
empty())
return;
1865 auto & effect = this->effects[handle];
1866 glObjectLabel(GL_PROGRAM, effect.programId,
static_cast<GLsizei
>(name.
size()), name.
data());
1875 if(name.
empty())
return;
1876 auto & effect = this->effects[handle];
1877 auto & shaderHandle = effect.shaders[ShaderType::VertexShader].shaderHandle;
1879 auto & shader = this->shaderIds[shaderHandle];
1880 glObjectLabel(GL_SHADER, shader,
static_cast<GLsizei
>(name.
size()), name.
data());
1890 if(name.
empty())
return;
1891 auto & effect = this->effects[handle];
1892 auto & shaderHandle = effect.shaders[ShaderType::GeometryShader].shaderHandle;
1894 auto & shader = this->shaderIds[shaderHandle];
1895 glObjectLabel(GL_SHADER, shader,
static_cast<GLsizei
>(name.
size()), name.
data());
1905 if(name.
empty())
return;
1906 auto & effect = this->effects[handle];
1907 auto & shaderHandle = effect.shaders[ShaderType::PixelShader].shaderHandle;
1909 auto & shader = this->shaderIds[shaderHandle];
1910 glObjectLabel(GL_SHADER, shader,
static_cast<GLsizei
>(name.
size()), name.
data());
1920 if(name.
empty())
return;
1921 auto & effect = this->effects[handle];
1922 auto & shaderHandle = effect.shaders[ShaderType::ComputeShader].shaderHandle;
1924 auto & shader = this->shaderIds[shaderHandle];
1925 glObjectLabel(GL_SHADER, shader,
static_cast<GLsizei
>(name.
size()), name.
data());
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr size_t size() const noexcept
Get the size of the string.
constexpr bool empty() const noexcept
Check if the string is empty.
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
std::vector< PreprocessorDefinition > PreprocessorDefinitions
A set of preprocessor definitions.
@ Write
The buffer can be mapped and written to by the CPU after creation.
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
void setEffect(EffectHandle effectHandle) override
Set the current effect.
Contains an effect description used to load a single effect.
EEffectFlags
Effect source flags.
@ LogShaderSource
Log the contents of the shader on error.
@ GLSL
Effect source is GLSL.
@ Pinned
Effect can only be released explicitly, not using releaseResources().
SamplerStateBindingHandle getSamplerStateBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot) override
Get a handle to a sampler state object binding, mapping how to bind the sampler state to the given ef...
BufferBindingHandle getBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a buffer binding.
ConstantBufferBindingHandle getConstantBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a constant buffer binding, mapping how to bind a constant buffer to the given effect.
void annotate(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
TextureBindingHandle getTextureBinding(EffectHandle effectHandle, const StringView &name, const unsigned int slot) override
Get a handle to a texture object binding, mapping how to bind textures to the given effect.
void annotateGS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void annotateVS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void annotatePS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void releaseResources() override
Release all allocated effect resources.
void annotateCS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void releaseEffect(EffectHandle handle) override
Release the effect with the given handle, freeing all resources generated during program loading.
void releaseBufferBinding(BufferBindingHandle bufferBindingHandle) override
Release a handle to a buffer binding.
EffectHandle loadComputeEffect(const StringView &fileName, EffectFlags::EEffectFlags effectFlags) override
Load the compute shader with the given file name and create an effect.
Settings for graphics device initialization.
int featureLevelMajor
Major feature level.
int featureLevelMinor
Minor feature level.
static const Handle_t NoHandle
Represents a handle to nothing.
static const Handle_t InvalidHandle
Represents an invalid handle.
Provides buffer management functionality.
virtual BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)=0
Loads a new buffer using the given data to populate the buffer.
@ Dynamic
Buffer will be loaded and modified with some frequency.