Cogs.Core
EffectsGLES30.cpp
1#include "EffectsGLES30.h"
2#include "ContextGLES30.h"
3#include "Foundation/StringView.h"
4
5#include <cstring>
6#include <memory>
7
8#include "../Base/Utilities.h"
9#include "../Base/DefaultIOHandler.h"
10
11using namespace Cogs;
12
13namespace
14{
15 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EffectsGLES30");
16
17 const char* getGLTypeName(GLenum type)
18 {
19 switch (type) {
20 case GL_FLOAT: return "float";
21 case GL_FLOAT_VEC2: return "vec2";
22 case GL_FLOAT_VEC3: return "vec3";
23 case GL_FLOAT_VEC4: return "vec4";
24 case GL_INT: return "int";
25 case GL_INT_VEC2: return "ivec2";
26 case GL_INT_VEC3: return "ivec3";
27 case GL_INT_VEC4: return "ivec4";
28 case GL_UNSIGNED_INT: return "uint";
29 case GL_UNSIGNED_INT_VEC2: return "uvec2";
30 case GL_UNSIGNED_INT_VEC3: return "uvec3";
31 case GL_UNSIGNED_INT_VEC4: return "uvec4";
32 case GL_BOOL: return "bool";
33 case GL_BOOL_VEC2: return "bvec2";
34 case GL_BOOL_VEC3: return "bvec3";
35 case GL_BOOL_VEC4: return "bvec4";
36 case GL_FLOAT_MAT2: return "mat2";
37 case GL_FLOAT_MAT3: return "mat3";
38 case GL_FLOAT_MAT4: return "mat4";
39 case GL_FLOAT_MAT2x3: return "mat2x3";
40 case GL_FLOAT_MAT2x4: return "mat2x4";
41 case GL_FLOAT_MAT3x2: return "mat3x2";
42 case GL_FLOAT_MAT3x4: return "mat3x4";
43 case GL_FLOAT_MAT4x2: return "mat4x2";
44 case GL_FLOAT_MAT4x3: return "mat4x3";
45 case GL_SAMPLER_2D: return "sampler2D";
46 case GL_SAMPLER_3D: return "sampler3D";
47 case GL_SAMPLER_CUBE: return "samplerCube";
48 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
49 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
50 case GL_SAMPLER_2D_ARRAY_SHADOW: return "sampler2DArrayShadow";
51 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
52 case GL_INT_SAMPLER_2D: return "isampler2D";
53 case GL_INT_SAMPLER_3D: return "isampler3D";
54 case GL_INT_SAMPLER_CUBE: return "isamplerCube";
55 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray";
56 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D";
57 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D";
58 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube";
59 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray";
60 default: return "???";
61 }
62 }
63
64 void printShaderSource(GLint shaderId)
65 {
66 GLint sourceLength = 0;
67 glGetShaderiv(shaderId, GL_SHADER_SOURCE_LENGTH, &sourceLength);
68 if (sourceLength) {
69 std::vector<char> source(sourceLength);
70 glGetShaderSource(shaderId, sourceLength, &sourceLength, source.data());
71
72 char* start = source.data();
73 char* stop;
74 int line = 1;
75 do {
76 stop = start;
77 while ((*stop != '\0') && (*stop != '\n') && (*stop != '\r')) { stop++; }
78
79 LOG_DEBUG(logger, "%3d: %s", line++, std::string(start, stop - start).c_str());
80
81 while ((*stop != '\0') && (*stop != '\n')) { stop++; }
82 while ((*stop != '\0') && (*stop == '\r')) { stop++; }
83
84 start = stop + 1;
85 } while (*stop != '\0');
86 }
87 }
88
89 void printShaderError(GLenum shaderType, GLint shaderId, Cogs::EffectFlags::EEffectFlags effectFlags)
90 {
91 GLint bufferLength = 0;
92 glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &bufferLength);
93
94 if (bufferLength) {
95 std::vector<char> buffer(bufferLength);
96
97 glGetShaderInfoLog(shaderId, bufferLength, NULL, buffer.data());
98
99 if ((effectFlags & EffectFlags::EEffectFlags::LogShaderSource) == EffectFlags::EEffectFlags::LogShaderSource) {
100 printShaderSource(shaderId);
101 }
102 LOG_ERROR(logger, "Could not compile shader %d:\n%s\n", shaderType, buffer.data());
103 }
104 else if ((effectFlags & (EffectFlags::EEffectFlags::LogShaderInfo | EffectFlags::EEffectFlags::LogShaderSource)) == (EffectFlags::EEffectFlags::LogShaderInfo | EffectFlags::EEffectFlags::LogShaderSource)) {
105 printShaderSource(shaderId);
106 }
107 }
108
109 void printProgramError(GLint programId)
110 {
111 GLint bufferLength = 0;
112 glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &bufferLength);
113
114 if (bufferLength) {
115 std::vector<char> buffer(bufferLength);
116
117 glGetProgramInfoLog(programId, bufferLength, NULL, buffer.data());
118
119 LOG_ERROR(logger, "Could not link program:\n%s\n", buffer.data());
120 }
121 }
122}
123
125{
126 if (!effectHandle) return;
127
128 if (context->getEffect() == effectHandle) {
129 LOG_DEBUG_ONCE(logger, "Releasing currently active effect");
131 }
132
133 EffectGLES30& effect = effects[effectHandle];
134 glDeleteProgram(effect.programId);
135 effect.programId = 0;
136 effects.removeResource(effectHandle);
137}
138
140{
141 std::vector<EffectHandle> handles;
142 for (auto& resource : effects) {
143 handles.push_back(effects.getHandle(resource));
144 }
145 for (auto& handle : handles) {
146 releaseEffect(handle);
147 }
148}
149
150GLint Cogs::EffectsGLES30::loadShader(GLenum shaderType, const char * pSource, PreprocessorDefinitions definitions)
151{
152 assert(pSource);
153
154#if defined(ANDROID) || defined(__APPLE__)
155 LOG_INFO(logger, "Loading shader from source:\n(Start source)\n%s", pSource);
156 LOG_INFO(logger, "(End source)");
157#endif
158
159 GLuint shaderId = glCreateShader(shaderType);
160 if (shaderId == 0) {
161 LOG_ERROR(logger, "loadShader: glCreateShader failed.");
162 return 0;
163 }
164
165 std::vector<std::string> source;
166 source.reserve(definitions.size() + 2);
167
168 // skip past the version directive
169 {
170 size_t o = 0;
171 // Find first #
172 while ((pSource[o] != '\0') && (pSource[o] != '#')) { o++; }
173
174 // Check if that is #version
175 if ((pSource[o] == '#') && (strncmp("version", pSource + o + 1, 7) == 0)) {
176 // Jumpt to end of lines (will consume multiple successive blank lines, but that doesn't matter)
177 while (pSource[o] != '\0' && pSource[o] != '\n') { o++; }
178 while (pSource[o] != '\0' && (pSource[o] == '\n' || pSource[o] == '\r')) { o++; }
179 source.emplace_back(pSource, pSource + o);
180 source.emplace_back(pSource + o);
181 }
182 }
183 if (source.empty()) {
184 source.push_back(pSource);
185 }
186
187 if (!definitions.empty()) {
188 std::string tail = std::move(source.back());
189 source.pop_back();
190 for (const PreprocessorDefinition& def : definitions) {
191 source.emplace_back("#define " + def.first + " " + def.second + "\n");
192 }
193 source.emplace_back(std::move(tail));
194 }
195
196 std::vector<const char*> strings(source.size());
197 for (size_t i = 0, n = source.size(); i < n; i++) {
198 strings[i] = source[i].c_str();
199 }
200
201 glShaderSource(shaderId, static_cast<GLsizei>(strings.size()), strings.data(), NULL);
202 glCompileShader(shaderId);
203
204 return shaderId;
205}
206
207
208EffectHandle Cogs::EffectsGLES30::loadEffect(const char * pVertexSource, const char * pFragmentSource, const PreprocessorDefinitions & definitions, EffectFlags::EEffectFlags effectFlags)
209{
210 EffectGLES30 program{};
211
212 std::vector<char> buffer;
213
214 GLuint programId = glCreateProgram();
215 if (programId == 0) {
216 LOG_ERROR(logger, "loadEffect: glCreateProgram failed.");
218 }
219 program.programId = programId;
220
221 GLint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource, definitions);
222 GLint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource, definitions);
223 glAttachShader(programId, vertexShader);
224 glAttachShader(programId, pixelShader);
225 glLinkProgram(programId);
226
227 GLint linkStatus = GL_FALSE;
228 glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
229 if (linkStatus != GL_TRUE) {
230 printShaderError(GL_VERTEX_SHADER, vertexShader, effectFlags);
231 printShaderError(GL_FRAGMENT_SHADER, pixelShader, effectFlags);
232 printProgramError(programId);
233
234 glDeleteShader(vertexShader);
235 glDeleteShader(pixelShader);
236 glDeleteProgram(programId);
237
238 LOG_ERROR(logger, "loadEffect: Failed to link shader program.");
240 }
241 else {
242
244 printShaderSource(vertexShader);
245 printShaderSource(pixelShader);
246 }
247
248 printShaderError(GL_VERTEX_SHADER, vertexShader, effectFlags);
249 printShaderError(GL_FRAGMENT_SHADER, pixelShader, effectFlags);
250 }
251 glDeleteShader(vertexShader); // ref kept until program is deleted
252 glDeleteShader(pixelShader); // ref kept until program is deleted
253
254
255 GLint activeAttributes = 0;
256 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
257
258 GLint attributeMaxLength = 0;
259 glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attributeMaxLength);
260
261
262 GLint activeUniforms = 0;
263 glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &activeUniforms);
264
265 GLint activeUniformBlocks = 0;
266 glGetProgramiv(programId, GL_ACTIVE_UNIFORM_BLOCKS, &activeUniformBlocks);
267
268 LOG_DEBUG(logger, "Built GLSL program id: %d (active attribs=%d, uniforms=%d, blocks=%d)", programId, activeAttributes, activeUniforms, activeUniformBlocks);
269
270 buffer.resize(attributeMaxLength);
271 for (int i = 0; i < activeAttributes; ++i) {
272 GLsizei length = 0;
273 GLint size = 0;
274 GLenum type = GL_INVALID_ENUM;
275
276 glGetActiveAttrib(programId, static_cast<GLsizei>(i), static_cast<GLsizei>(buffer.size()), &length, &size, &type, buffer.data());
277
278 const char* beg = buffer.data();
279 const char* end = beg + attributeMaxLength;
280
281 // Find end of semantic name
282 ElementSemantic semantic = ElementSemantic::Semantic_Size;
283 const char* ptr = beg;
284 while ((ptr < end) && (*ptr != '\0') && ((*ptr < '0') || ('9' < *ptr))) { ptr++; }
285
286 StringView semanticName(beg, ptr - beg);
287 switch (Cogs::hash(semanticName)) {
288 case Cogs::hash("gl_VertexID"): semantic = ElementSemantic::Semantic_Size; break;
289 case Cogs::hash("gl_InstanceID"): semantic = ElementSemantic::Semantic_Size; break;
290 case Cogs::hash("gl_ViewID_OVR"): semantic = ElementSemantic::Semantic_Size; break;
291 case Cogs::hash("a_POSITION"): semantic = ElementSemantic::Position; break;
292 case Cogs::hash("a_NORMAL"): semantic = ElementSemantic::Normal; break;
293 case Cogs::hash("a_COLOR"): semantic = ElementSemantic::Color; break;
294 case Cogs::hash("a_TEXCOORD"): semantic = ElementSemantic::TextureCoordinate; break;
295 case Cogs::hash("a_TANGENT"): semantic = ElementSemantic::Tangent; break;
296 case Cogs::hash("a_INSTANCEVECTOR"): semantic = ElementSemantic::InstanceVector; break;
297 case Cogs::hash("a_INSTANCEMATRIX"): semantic = ElementSemantic::InstanceMatrix; break;
298 default:
299 LOG_ERROR(logger, "Unrecognized attribute name '%.*s'", StringViewFormat(semanticName));
300 glDeleteProgram(programId);
302 }
303 if (semantic == ElementSemantic::Semantic_Size) {
305 LOG_DEBUG(logger, "Attrib -: name=%s type=%s", buffer.data(), getGLTypeName(type));
306 }
307 // built-in attribute, skip
308 continue;
309 }
310
311 program.attributeSemantic[i].semantic = uint8_t(semantic);
312
313 // Find end of slot number
314 uint32_t slot = 0;
315 while ((ptr < end) && (*ptr != '\0') && ('0' <= *ptr) && (*ptr <= '9')) { slot = 10 * slot + uint32_t(*ptr - '0'); ptr++; }
316 if (255 < slot) {
317 LOG_ERROR(logger, "Invalid attribute slot index %u in name '%s'", slot, buffer.data());
318 glDeleteProgram(programId);
320 }
321 if (*ptr != '\0') {
322 LOG_ERROR(logger, "Unrecognized characters after attribute index in name '%s'", buffer.data());
323 glDeleteProgram(programId);
325 }
326 program.attributeSemantic[i].slot = uint8_t(slot);
327
328 const GLint location = glGetAttribLocation(programId, buffer.data());
329 if (location < 0 || 0xffff < location) {
330 LOG_ERROR(logger, "Invalid attribute location %d, assumptions broken", location);
331 glDeleteProgram(programId);
333 }
334 program.attributeLocation[i] = location;
335
337 LOG_DEBUG(logger, "Attrib %d: name=%s type=%s semantic=%.*s::%u", location, buffer.data(), getGLTypeName(type), StringViewFormat(getElementSemanticName(semantic)), slot);
338 }
339 }
340 program.activeAttributes = static_cast<uint8_t>(std::max(0, activeAttributes));
341
342 GLint uniformMaxLength = 0;
343 glGetProgramiv(programId, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxLength);
344
345 // Switch to newly built program so we can use glUniform-calls.
346 // But first query currently bound program so we can restore it.
347 GLint currentProgram = 0;
348 glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
349 glUseProgram(program.programId);
350
351 size_t allocatedTexUnits = 0;
352 buffer.resize(uniformMaxLength);
353 for (int i = 0; i < activeUniforms; i++) {
354 GLsizei length = 0;
355 GLint size = 0;
356 GLenum type = GL_INVALID_ENUM;
357 glGetActiveUniform(programId, static_cast<GLsizei>(i), static_cast<GLsizei>(buffer.size()), &length, &size, &type, buffer.data());
358
359 const GLint location = glGetUniformLocation(programId, buffer.data());
360 if (0 <= location) {
361 bool isActiveSampler = false;
362 switch (type) {
363 case GL_SAMPLER_2D: isActiveSampler = true; break;
364 case GL_SAMPLER_3D: isActiveSampler = true; break;
365 case GL_SAMPLER_CUBE: isActiveSampler = true; break;
366 case GL_SAMPLER_2D_SHADOW: isActiveSampler = true; break;
367 case GL_SAMPLER_2D_ARRAY: isActiveSampler = true; break;
368 case GL_SAMPLER_2D_ARRAY_SHADOW: isActiveSampler = true; break;
369 case GL_SAMPLER_CUBE_SHADOW: isActiveSampler = true; break;
370 case GL_INT_SAMPLER_2D: isActiveSampler = true; break;
371 case GL_INT_SAMPLER_3D: isActiveSampler = true; break;
372 case GL_INT_SAMPLER_CUBE: isActiveSampler = true; break;
373 case GL_INT_SAMPLER_2D_ARRAY: isActiveSampler = true; break;
374 case GL_UNSIGNED_INT_SAMPLER_2D: isActiveSampler = true; break;
375 case GL_UNSIGNED_INT_SAMPLER_3D: isActiveSampler = true; break;
376 case GL_UNSIGNED_INT_SAMPLER_CUBE: isActiveSampler = true; break;
377 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: isActiveSampler = true; break;
378 default: break;
379 }
380 if (isActiveSampler) {
381
382 size_t unit = 0;
383 if (allocatedTexUnits == OpenGLES30::maxTexUnits) {
384 LOG_ERROR(logger, "Active texture units exceed OpenGLES30::maxTexUnits");
385 }
386 else {
387 unit = allocatedTexUnits++;
388 program.textureSlots[unit].nameHash = Cogs::hash(StringView(buffer.data()));
389 glUniform1i(location, GLint(unit));
390 }
392 LOG_DEBUG(logger, "Uniform %d: name=%s type=%s sampler unit=%zu", location, buffer.data(), getGLTypeName(type), unit);
393 }
394 continue;
395 }
396 }
397
399 LOG_DEBUG(logger, "Uniform %d: name=%s type=%s", location, buffer.data(), getGLTypeName(type));
400 }
401 }
402 assert(allocatedTexUnits <= OpenGLES30::maxTexUnits);
403 program.activeTextureUnits = static_cast<uint8_t>(allocatedTexUnits);
404
405 // Query uniform block bindings.
406 //
407 // We currently just use the binding order determined by GL, we could become more clever
408 // if we end up with a lot of buffer-switching at runtime.
409 //
410 {
411 GLuint nextBinding = 1; // First binding slot for uniform blocks in use.
412 std::memset(&program.uniformBlockBindings[0], 0, sizeof(program.uniformBlockBindings));
413 for (GLuint activeBlockIndex = 0; GLint(activeBlockIndex) < activeUniformBlocks; activeBlockIndex++) {
414 char uniformBlockNameChars[256] = {};
415 GLsizei uniformBlockNameLength = 0;
416 glGetActiveUniformBlockName(programId, activeBlockIndex, GLsizei(sizeof(uniformBlockNameChars)), &uniformBlockNameLength, uniformBlockNameChars);
417 StringView uniformBlockName(uniformBlockNameChars, uniformBlockNameLength);
418
419 GLint vRef = 0;
420 glGetActiveUniformBlockiv(programId, activeBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &vRef);
421
422 GLint fRef = 0;
423 glGetActiveUniformBlockiv(programId, activeBlockIndex, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &fRef);
424
425 // Not referenced by VS or FS, bind it to empty uniform buffer at slot 0.
426 GLuint binding = 0; // Start at binding 1, 0 is reserved
427 if (!uniformBlockName.empty() && (vRef != 0 || fRef != 0)) {
428
429 binding = nextBinding++;
430
431 size_t nameHash = Cogs::hash(uniformBlockName);
432 assert(nameHash);
433 program.uniformBlockBindings[binding].nameHash = nameHash;
434 }
435 glUniformBlockBinding(programId, activeBlockIndex, binding);
436
438 GLint dataSize = 0;
439 glGetActiveUniformBlockiv(programId, activeBlockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &dataSize);
440
441 LOG_DEBUG(logger, "block %d: bind=%d size=%5d %c%c name='%.*s'", activeBlockIndex, binding, dataSize, vRef ? 'V' : ' ', fRef ? 'F' : ' ', StringViewFormat(uniformBlockName));
442 }
443 }
444 }
446 LOG_DEBUG(logger, "Loaded GLSL program id: %d", programId);
447 }
448
449 glUseProgram(currentProgram); // Restore ppreviously bound program
450
451 if (delayFrames) {
452 program.readyAtFrame = currentFrame + delayFrames;
453 if (program.readyAtFrame > allEffectsReadyFrame) allEffectsReadyFrame = program.readyAtFrame;
454 }
455
456 return effects.addResource(program);
457}
458
460{
461 LOG_ERROR(logger, "loadComputeEffect: compute shaders not supported");
463}
464
466{
467 LOG_ERROR(logger, "loadComputeEffect: compute shaders not supported");
469}
470
471Cogs::TextureBindingHandle Cogs::EffectsGLES30::getTextureBinding(EffectHandle effectHandle, const StringView & name, const unsigned int /*slot*/)
472{
473 if (!HandleIsValid(effectHandle) || name.empty()) {
474 return TextureBindingHandle::NoHandle; // Invalid effect or empty name.
475 }
476
477 const size_t nameHash = Cogs::hash(name);
478 const EffectGLES30& effect = effects[effectHandle];
479 for (size_t i = 0; i < effect.activeTextureUnits; i++) {
480 if (effect.textureSlots[i].nameHash == nameHash) {
481 return TextureBindingHandle(i + 1);
482 }
483 }
484 return TextureBindingHandle::NoHandle; // Name not recognized.
485}
486
488{
489 const char suffix[] = "Sampler";
490 constexpr size_t suffixLength = sizeof(suffix) - 1;
491 if (HandleIsValid(effectHandle)) {
492 const EffectGLES30& effect = effects[effectHandle];
493
494 // Try with naming scheme
495 if ((suffixLength < name.length()) &&
496 (std::memcmp(name.data() + name.size() - suffixLength, suffix, suffixLength) == 0))
497 {
498 const size_t nameHash = Cogs::hash(name.substr(0, name.length() - suffixLength));
499 for (size_t i = 0; i < effect.activeTextureUnits; i++) {
500 if (effect.textureSlots[i].nameHash == nameHash) {
501 return SamplerStateBindingHandle(i + 1);
502 }
503 }
504 }
505 }
506
507 return SamplerStateBindingHandle::NoHandle; // Name not recognized
508}
509
510void Cogs::EffectsGLES30::initialize(ContextGLES30* context, uint32_t delayFrames)
511{
512 this->context = context;
513 this->delayFrames = delayFrames;
514 EffectsCommon::initialize(buffers);
515}
516
518{
519 if (!HandleIsValid(effectHandle)) return ResourceStatus::Error;
520 if (delayFrames == 0) return ResourceStatus::Ready; // Simulation disabled: skip frame comparison and overflow concerns entirely.
521
522 return currentFrame < effects[effectHandle].readyAtFrame ? ResourceStatus::Pending : ResourceStatus::Ready;
523}
524
526{
527 if (!HandleIsValid(effectHandle)) return EffectVariableHandle::NoHandle;
528
529 const GLint programId = effects[effectHandle].programId;
530 const GLint location = glGetUniformLocation(programId, name.data());
531 if(location == -1) return EffectVariableHandle::NoHandle;
532
533 EffectVariableHandle handle(programId << 16 | location);
534 return handle;
535}
536
538{
539 if (name.empty()) {
541 }
542 if (!HandleIsValid(effectHandle)) {
543 LOG_ERROR_ONCE(logger, "getConstantBufferBinding: Invalid effect handle");
545 }
546 EffectGLES30& effect = effects[effectHandle];
547
548 size_t nameHash = Cogs::hash(name);
549 for (size_t index = 0; index < OpenGLES30::maxUniformBuffers; index++) {
550 if (effect.uniformBlockBindings[index].nameHash == nameHash) {
551 return ConstantBufferBindingHandle(size_t(index) + 1);
552 }
553 }
554
556}
557
558EffectHandle Cogs::EffectsGLES30::load(const ProcessedContent & vsSource,
559 const ProcessedContent& hsSource,
560 const ProcessedContent& dsSource,
561 const ProcessedContent& gsSource,
562 const ProcessedContent& psSource,
563 const StringView& vsEntryPoint,
564 const StringView& hsEntryPoint,
565 const StringView& dsEntryPoint,
566 const StringView& gsEntryPoint,
567 const StringView& psEntryPoint,
568 const EffectDescription& desc)
569{
570 if (!hsSource.content.empty() || !dsSource.content.empty()) {
571 LOG_ERROR(logger, "load: Tessellation shaders are not supported.");
573 }
574 if (!gsSource.content.empty()) {
575 LOG_ERROR(logger, "load: Geometry shaders are not supported.");
577 }
578 if (!(vsEntryPoint.empty() || vsEntryPoint == "main") ||
579 !(hsEntryPoint.empty() || hsEntryPoint == "main") ||
580 !(dsEntryPoint.empty() || dsEntryPoint == "main") ||
581 !(gsEntryPoint.empty() || gsEntryPoint == "main") ||
582 !(psEntryPoint.empty() || psEntryPoint == "main"))
583 {
584 LOG_ERROR(logger, "load: Shader entry points not named main are not supported.");
586 }
587
588 return loadEffect(vsSource.content.c_str(), psSource.content.c_str(), desc.definitions, desc.flags);
589}
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:197
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:204
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:211
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:148
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:284
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
ResourceStatus
Status of an asynchronously loaded resource, such as an effect or a pipeline.
Definition: Common.h:198
@ Pending
The resource is still loading.
@ Error
The resource failed to load.
@ Ready
The resource has loaded successfully and is ready for use.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
std::pair< std::string, std::string > PreprocessorDefinition
Preprocessor definition.
Definition: IEffects.h:17
ElementSemantic
Element semantics used to map data to the shader stage.
Definition: VertexFormat.h:14
@ Position
Position semantic.
@ Tangent
Tangent semantic.
@ Normal
Normal semantic.
@ InstanceMatrix
Instance matrix semantic.
@ InstanceVector
Instance vector semantic.
@ Color
Color semantic.
@ TextureCoordinate
Texture coordinate semantic.
std::vector< PreprocessorDefinition > PreprocessorDefinitions
A set of preprocessor definitions.
Definition: IEffects.h:20
void setEffect(EffectHandle handle) override
Set the current effect.
Contains an effect description used to load a single effect.
Definition: IEffects.h:62
EEffectFlags
Effect source flags.
Definition: IEffects.h:27
@ LogShaderInfo
Log detailed info about shaders.
Definition: IEffects.h:39
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...
EffectVariableHandle getEffectVariable(EffectHandle effectHandle, const StringView &name) override
Get a handle to the variable with the given name in the effect with the given effectHandle.
virtual EffectHandle loadComputeEffect(const StringView &fileName, EffectFlags::EEffectFlags effectFlags) override
Load the compute shader with the given file name and create an effect.
ResourceStatus checkEffect(EffectHandle effectHandle) override
Check the load status of the effect with the given effectHandle.
void releaseResources()
Release all allocated effect resources.
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.
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 releaseEffect(EffectHandle handle)
Release the effect with the given handle, freeing all resources generated during program loading.
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:81