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 return effects.addResource(program);
451}
452
454{
455 LOG_ERROR(logger, "loadComputeEffect: compute shaders not supported");
457}
458
460{
461 LOG_ERROR(logger, "loadComputeEffect: compute shaders not supported");
463}
464
465Cogs::TextureBindingHandle Cogs::EffectsGLES30::getTextureBinding(EffectHandle effectHandle, const StringView & name, const unsigned int /*slot*/)
466{
467 if (!HandleIsValid(effectHandle) || name.empty()) {
468 return TextureBindingHandle::NoHandle; // Invalid effect or empty name.
469 }
470
471 const size_t nameHash = Cogs::hash(name);
472 const EffectGLES30& effect = effects[effectHandle];
473 for (size_t i = 0; i < effect.activeTextureUnits; i++) {
474 if (effect.textureSlots[i].nameHash == nameHash) {
475 return TextureBindingHandle(i + 1);
476 }
477 }
478 return TextureBindingHandle::NoHandle; // Name not recognized.
479}
480
482{
483 const char suffix[] = "Sampler";
484 constexpr size_t suffixLength = sizeof(suffix) - 1;
485 if (HandleIsValid(effectHandle)) {
486 const EffectGLES30& effect = effects[effectHandle];
487
488 // Try with naming scheme
489 if ((suffixLength < name.length()) &&
490 (std::memcmp(name.data() + name.size() - suffixLength, suffix, suffixLength) == 0))
491 {
492 const size_t nameHash = Cogs::hash(name.substr(0, name.length() - suffixLength));
493 for (size_t i = 0; i < effect.activeTextureUnits; i++) {
494 if (effect.textureSlots[i].nameHash == nameHash) {
495 return SamplerStateBindingHandle(i + 1);
496 }
497 }
498 }
499 }
500
501 return SamplerStateBindingHandle::NoHandle; // Name not recognized
502}
503
504void Cogs::EffectsGLES30::initialize(ContextGLES30* context)
505{
506 this->context = context;
507 EffectsCommon::initialize(buffers);
508}
509
511{
512 if (!HandleIsValid(effectHandle)) return EffectVariableHandle::NoHandle;
513
514 const GLint programId = effects[effectHandle].programId;
515 const GLint location = glGetUniformLocation(programId, name.data());
516 if(location == -1) return EffectVariableHandle::NoHandle;
517
518 EffectVariableHandle handle(programId << 16 | location);
519 return handle;
520}
521
523{
524 if (name.empty()) {
526 }
527 if (!HandleIsValid(effectHandle)) {
528 LOG_ERROR_ONCE(logger, "getConstantBufferBinding: Invalid effect handle");
530 }
531 EffectGLES30& effect = effects[effectHandle];
532
533 size_t nameHash = Cogs::hash(name);
534 for (size_t index = 0; index < OpenGLES30::maxUniformBuffers; index++) {
535 if (effect.uniformBlockBindings[index].nameHash == nameHash) {
536 return ConstantBufferBindingHandle(size_t(index) + 1);
537 }
538 }
539
541}
542
543EffectHandle Cogs::EffectsGLES30::load(const ProcessedContent & vsSource,
544 const ProcessedContent& hsSource,
545 const ProcessedContent& dsSource,
546 const ProcessedContent& gsSource,
547 const ProcessedContent& psSource,
548 const StringView& vsEntryPoint,
549 const StringView& hsEntryPoint,
550 const StringView& dsEntryPoint,
551 const StringView& gsEntryPoint,
552 const StringView& psEntryPoint,
553 const EffectDescription& desc)
554{
555 if (!hsSource.content.empty() || !dsSource.content.empty()) {
556 LOG_ERROR(logger, "load: Tessellation shaders are not supported.");
558 }
559 if (!gsSource.content.empty()) {
560 LOG_ERROR(logger, "load: Geometry shaders are not supported.");
562 }
563 if (!(vsEntryPoint.empty() || vsEntryPoint == "main") ||
564 !(hsEntryPoint.empty() || hsEntryPoint == "main") ||
565 !(dsEntryPoint.empty() || dsEntryPoint == "main") ||
566 !(gsEntryPoint.empty() || gsEntryPoint == "main") ||
567 !(psEntryPoint.empty() || psEntryPoint == "main"))
568 {
569 LOG_ERROR(logger, "load: Shader entry points not named main are not supported.");
571 }
572
573 return loadEffect(vsSource.content.c_str(), psSource.content.c_str(), desc.definitions, desc.flags);
574}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
constexpr size_t size() const noexcept
Get the size of the string.
Definition: StringView.h:178
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:185
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:258
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
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:10
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:13
void setEffect(EffectHandle handle) override
Set the current effect.
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ LogShaderInfo
Log detailed info about shaders.
Definition: IEffects.h:32
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.
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:77
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80