xoreos  0.0.5
shader.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <iostream>
26 #include <fstream>
27 #include <sstream>
28 #include <stdlib.h>
29 
30 #include "src/common/util.h"
31 
32 #include "src/graphics/graphics.h"
33 
36 
38 
39 /*--------------------------------------------------------------------*/
40 
42 
43 namespace Graphics {
44 
45 namespace Shader {
46 
47 /*--------------------------------------------------------------------*/
49 }
50 
52 }
53 
55  if (this->glid != 0) {
56  glDeleteShader(this->glid);
57  this->glid = 0;
58  }
59 }
60 /*--------------------------------------------------------------------*/
61 
62 /*--------------------------------------------------------------------*/
64 }
65 
67  ShaderMan.genGLProgram(this);
68 }
69 
71  if (this->glid != 0) {
72  glDeleteProgram(this->glid);
73  this->glid = 0;
74  }
75 }
76 /*--------------------------------------------------------------------*/
77 
78 
79 ShaderManager::ShaderManager() : _counterVID(1), _counterFID(1) {
80 }
81 
83  deinit();
84 }
85 
87  //_isGL3 = isGL3; // pull this from GfxMan
88  status("Initialising shaders...");
89 
90  ShaderObject *vObj;
91  ShaderObject *fObj;
92 
106 
107  Common::UString vertexStringFinal;
108  Common::UString fragmentStringFinal;
109  cripter.build(GfxMan.isGL3(), vertexStringFinal, fragmentStringFinal);
110  vObj = ShaderMan.getShaderObject("default/text.vert", vertexStringFinal, Shader::SHADER_VERTEX);
111  fObj = ShaderMan.getShaderObject("default/text.frag", fragmentStringFinal, Shader::SHADER_FRAGMENT);
112  registerShaderProgram(vObj, fObj);
113 
114  cripter.clear();
124 
125  vertexStringFinal.clear();
126  fragmentStringFinal.clear();
127  cripter.build(GfxMan.isGL3(), vertexStringFinal, fragmentStringFinal);
128  vObj = ShaderMan.getShaderObject("default/texture.vert", vertexStringFinal, Shader::SHADER_VERTEX);
129  fObj = ShaderMan.getShaderObject("default/texture.frag", fragmentStringFinal, Shader::SHADER_FRAGMENT);
130  registerShaderProgram(vObj, fObj);
131 
132  cripter.clear();
142 
143  vertexStringFinal.clear();
144  fragmentStringFinal.clear();
145  cripter.build(GfxMan.isGL3(), vertexStringFinal, fragmentStringFinal);
146  vObj = ShaderMan.getShaderObject("default/textureMatrix.vert", vertexStringFinal, Shader::SHADER_VERTEX);
147  fObj = ShaderMan.getShaderObject("default/texture.frag", Shader::SHADER_FRAGMENT);
148  registerShaderProgram(vObj, fObj);
149 
150  cripter.clear();
156 
157  vertexStringFinal.clear();
158  fragmentStringFinal.clear();
159  cripter.build(GfxMan.isGL3(), vertexStringFinal, fragmentStringFinal);
160  vObj = ShaderMan.getShaderObject("default/default.vert", vertexStringFinal, Shader::SHADER_VERTEX);
161  fObj = ShaderMan.getShaderObject("default/colour.frag", fragmentStringFinal, Shader::SHADER_FRAGMENT);
162  registerShaderProgram(vObj, fObj);
163 }
164 
166  status("Cleaning up shaders...");
167  glUseProgram(0);
168 
169  for (uint32 i = 0; i < _shaderProgramArray.size(); ++i) {
170  glDeleteProgram(_shaderProgramArray[i]->glid);
171  delete _shaderProgramArray[i];
172  }
173  _shaderProgramArray.clear();
174 
175  for (std::map<Common::UString, Shader::ShaderObject *>::iterator iter = _shaderObjectMap.begin(); iter != _shaderObjectMap.end(); ++iter) {
176  if (iter->second->glid) {
177  glDeleteShader(iter->second->glid);
178  }
179  delete iter->second;
180  }
181  _shaderObjectMap.clear();
182 }
183 
185  // In future, this should use Common::ReadFile to load file "name" into a string, and compile a shader object from there.
186  Common::UString shaderString;
187  //ShaderObject *shaderObject = 0;
188  //ShaderObject *shaderObject = (ShaderObject *)(_shaderObjectMap[filename.c_str()]);
189  std::map<Common::UString, Shader::ShaderObject *>::iterator it = _shaderObjectMap.find(name);
190  if (it != _shaderObjectMap.end()) {
191  return it->second;
192  } else {
193  return 0;
194  }
195 }
196 
198  _shaderMutex.lock();
199  ShaderObject *shaderObject = 0;
200  //ShaderObject *shaderObject = (ShaderObject *)(_shaderObjectMap[filename.c_str()]);
201  std::map<Common::UString, Shader::ShaderObject *>::iterator it = _shaderObjectMap.find(name);
202  if (it != _shaderObjectMap.end()) {
204  return it->second;
205  }
206 
207  shaderObject = new ShaderObject;
208  shaderObject->type = type;
209  shaderObject->glid = 0;
210  shaderObject->shaderString = source;
211 
212  status("shader %s loaded", name.c_str());
213 
214  _shaderObjectMap.insert(std::pair<Common::UString, ShaderObject *>(name, shaderObject));
216 
217  parseShaderVariables(source, shaderObject->variablesSelf);
218  genShaderVariableList(shaderObject, shaderObject->variablesCombined);
219  if (shaderObject->type == SHADER_VERTEX) {
220  shaderObject->id = _counterVID++; // Post decrement intentional.
221  } else {
222  shaderObject->id = _counterFID++; // Post decrement intentional.
223  }
224 
225  return shaderObject;
226 }
227 
229  switch (var.type) {
230  case SHADER_FLOAT: glUniform1fv(loc, var.count, static_cast<const float *>(data)); break;
231  case SHADER_VEC2: glUniform2fv(loc, var.count, static_cast<const float *>(data)); break;
232  case SHADER_VEC3: glUniform3fv(loc, var.count, static_cast<const float *>(data)); break;
233  case SHADER_VEC4: glUniform4fv(loc, var.count, static_cast<const float *>(data)); break;
234  case SHADER_INT: glUniform1iv(loc, var.count, static_cast<const GLint *>(data)); break;
235  case SHADER_IVEC2: glUniform2iv(loc, var.count, static_cast<const GLint *>(data)); break;
236  case SHADER_IVEC3: glUniform3iv(loc, var.count, static_cast<const GLint *>(data)); break;
237  case SHADER_IVEC4: glUniform4iv(loc, var.count, static_cast<const GLint *>(data)); break;
238 // Commented out those not really supported by older GLSL versions.
239 // case SHADER_UINT: glUniform1uiv(loc, var.count, static_cast<GLuint *>(data)); break;
240 // case SHADER_UVEC2: glUniform2uiv(loc, var.count, static_cast<GLuint *>(data)); break;
241 // case SHADER_UVEC3: glUniform3uiv(loc, var.count, static_cast<GLuint *>(data)); break;
242 // case SHADER_UVEC4: glUniform4uiv(loc, var.count, static_cast<GLuint *>(data)); break;
243 // case SHADER_BOOL: glUniform1uiv(loc, var.count, static_cast<GLuint *>(data)); break;
244 // case SHADER_BVEC2: glUniform2uiv(loc, var.count, static_cast<GLuint *>(data)); break;
245 // case SHADER_BVEC3: glUniform3uiv(loc, var.count, static_cast<GLuint *>(data)); break;
246 // case SHADER_BVEC4: glUniform4uiv(loc, var.count, static_cast<GLuint *>(data)); break;
247  case SHADER_MAT2: glUniformMatrix2fv(loc, var.count, 0, static_cast<const float *>(data)); break;
248  case SHADER_MAT3: glUniformMatrix3fv(loc, var.count, 0, static_cast<const float *>(data)); break;
249  case SHADER_MAT4: glUniformMatrix4fv(loc, var.count, 0, static_cast<const float *>(data)); break;
250  case SHADER_SAMPLER1D:
251  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
252  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
253  glBindTexture(GL_TEXTURE_1D, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
254  break;
255  case SHADER_SAMPLER2D:
256  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
257  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
258  glBindTexture(GL_TEXTURE_2D, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
259  break;
260  case SHADER_SAMPLER3D:
261  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
262  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
263  glBindTexture(GL_TEXTURE_3D, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
264  break;
265  case SHADER_SAMPLERCUBE:
266  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
267  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
268  glBindTexture(GL_TEXTURE_CUBE_MAP, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
269  break;
271  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
272  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
273  glBindTexture(GL_TEXTURE_1D_ARRAY, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
274  break;
276  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
277  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
278  glBindTexture(GL_TEXTURE_2D, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
279  break;
281  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
282  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
283  glBindTexture(GL_TEXTURE_1D_ARRAY, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
284  break;
286  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
287  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
288  glBindTexture(GL_TEXTURE_2D_ARRAY, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
289  break;
291  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
292  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
293  glBindTexture(GL_TEXTURE_1D_ARRAY, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
294  break;
296  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
297  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
298  glBindTexture(GL_TEXTURE_2D_ARRAY, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
299  break;
301  glUniform1i(loc, static_cast<const ShaderSampler *>(data)->unit);
302  glActiveTexture(GL_TEXTURE0 + static_cast<const ShaderSampler *>(data)->unit);
303  glBindTexture(GL_TEXTURE_BUFFER, static_cast<const ShaderSampler *>(data)->handle.getTexture().getID());
304  break;
305  case SHADER_ISAMPLER1D: break;
306  case SHADER_ISAMPLER2D: break;
307  case SHADER_ISAMPLER3D: break;
308  case SHADER_ISAMPLERCUBE: break;
309  case SHADER_ISAMPLER1DARRAY: break;
310  case SHADER_ISAMPLER2DARRAY: break;
311  case SHADER_USAMPLER1D: break;
312  case SHADER_USAMPLER2D: break;
313  case SHADER_USAMPLER3D: break;
314  case SHADER_USAMPLERCUBE: break;
315  case SHADER_USAMPLER1DARRAY: break;
316  case SHADER_USAMPLER2DARRAY: break;
318  glBindBufferBase(GL_UNIFORM_BUFFER, static_cast<const ShaderUBO *>(data)->index, static_cast<const ShaderUBO *>(data)->glid);
319  break;
320  default: break;
321  }
322 }
323 
324 void ShaderManager::bindShaderInstance(ShaderProgram *prog, const void **vertexVariables, const void **fragmentVariables) {
325  glUseProgram(prog->glid);
326  for (uint32 i = 0; i < prog->vertexObject->variablesCombined.size(); ++i) {
327  bindShaderVariable(prog->vertexObject->variablesCombined[i], prog->vertexVariableLocations[i], vertexVariables[i]);
328  }
329 
330  for (uint32 i = 0; i < prog->fragmentObject->variablesCombined.size(); ++i) {
331  bindShaderVariable(prog->fragmentObject->variablesCombined[i], prog->fragmentVariableLocations[i], fragmentVariables[i]);
332  }
333 }
334 
337  if (_shaderProgramArray.size() == 0) {
339  return NULL;
340  }
341 
342  uint32 search_high = _shaderProgramArray.size() - 1; // -1 is ok here, as a default shader will exist.
343  uint32 search_low = 0;
344  uint32 search_mid = _shaderProgramArray.size() >> 1;
345  uint64 key = (((uint64)(vertexObject->id)) << 32) | (uint64)(fragmentObject->id);
346  ShaderProgram *rvalue = 0; // Default to nothing found.
347 
348  while (search_high >= search_low) {
349  if (_shaderProgramArray[search_mid]->id == key) {
350  // Found the program.
351  search_low = search_high+1; // Break the loop.
352  rvalue = _shaderProgramArray[search_mid];
353  } else if (_shaderProgramArray[search_mid]->id < key) {
354  search_low = search_mid+1;
355  search_mid = (search_high + search_low) >> 1; // This will allow search_mid to gravitate towards the highest point.
356  } else {
357  // The key is higher than the mid point, so search higher in the array.
358  search_high = search_mid-1;
359  search_mid = (search_high + search_low) >> 1; // The will help search_mid to gravitate towards the lowest point.
360  }
361  }
363  return rvalue;
364 }
365 
367  glAttachShader(progid, obj->glid);
368  for (uint32 i = 0; i < obj->subObjects.size(); ++i) {
369  registerShaderAttachment(progid, obj->subObjects[i]);
370  }
371 }
372 
374  ShaderProgram *program = getShaderProgram(vertexObject, fragmentObject);
375  if (program != 0)
376  return program; // Shader already exists.
377  else if (vertexObject->id == 0 || fragmentObject->id == 0)
378  return 0; // One id or the other is invalid - shader program can not be created.
379 
380  vertexObject->usageCount++;
381  fragmentObject->usageCount++;
382 
384  uint64 key = (((uint64)(vertexObject->id)) << 32) | (uint64)(fragmentObject->id);
385  uint32 searchIndex = 0;
386  while ((searchIndex < _shaderProgramArray.size()) && (_shaderProgramArray[searchIndex]->id < key)) {
387  ++searchIndex;
388  }
389 
390  program = new ShaderProgram;
391  _shaderProgramArray.push_back(program);
392 
393  for (unsigned int i = (_shaderProgramArray.size() - 1); i > searchIndex; i--) {
395  }
396  _shaderProgramArray[searchIndex] = program;
398 
399  program->id = key;
400  program->glid = 0;
401  program->vertexObject = vertexObject;
402  program->fragmentObject = fragmentObject;
403 
404  program->queue();
405  return program;
406 }
407 
408 void ShaderManager::genShaderVariableList(ShaderObject *obj, std::vector<ShaderObject::ShaderObjectVariable> &vars) {
409  if (!obj) {
410  return;
411  }
412 
413  std::vector<ShaderObject *> shaderObjectStack;
414  std::map<Common::UString, uint32> shaderNameMap;
415 
416  do {
417  for (uint32 i = 0; i < obj->subObjects.size(); ++i) {
418  shaderObjectStack.push_back(obj->subObjects[i]);
419  }
420 
421  for (uint32 i = 0; i < obj->variablesSelf.size(); ++i) {
422  if (shaderNameMap.find(obj->variablesSelf[i].name) == shaderNameMap.end()) {
423  shaderNameMap.insert(std::pair<Common::UString, uint32>(obj->variablesSelf[i].name, i));
424  vars.push_back(obj->variablesSelf[i]);
425  }
426  }
427  if (shaderObjectStack.size() > 0) {
428  obj = shaderObjectStack.back();
429  shaderObjectStack.pop_back();
430  } else {
431  obj = 0;
432  }
433  } while (obj);
434 
435  vars.resize(vars.size()); // C++11 function is vars.shrink_to_fit().
436 }
437 
438 void ShaderManager::parseShaderVariables(const Common::UString &shaderString, std::vector<ShaderObject::ShaderObjectVariable> &varList) {
439  // todo: Better source parsing is required, rather than relying on newline / whitespace delimiting.
440  // #version in shader source needs a newline, but after that does not, so perhaps parse on ';' instead.
441 
442  std::string searchString = shaderString.c_str();
443  std::string sword, snum;
444  std::string::size_type pos, posEnd;
445  std::string::size_type posi, posEndi;
446  unsigned int parseState = 0;
447  unsigned int num; // Used if an array subscript is found.
448  ShaderVariableType varIdentityCrisis = SHADER_INVALID;
449 
450  pos = searchString.find_first_not_of("\t\r\n\f\v ", 0);
451  posEnd = searchString.find_first_of("\t\r\n\f\v ", pos);
452  while (pos != std::string::npos && posEnd != std::string::npos) {
453  sword = searchString.substr(pos, posEnd - pos);
454  switch (parseState) {
455  case 0:
456  if (sword.find("//") != std::string::npos) {
457  // Move to the end of the line, and continue.
458  posEnd = searchString.find_first_of("\n", pos);
459  } else if (sword.find("/*") != std::string::npos) {
460  // Find the next "*/" after this.
461  posEnd = searchString.find("*/", pos);
462  if (posEnd != std::string::npos)
463  posEnd += 2; // Go to after the comment end.
464  } else if (sword == "uniform") {
465  // Found the start of a uniform declaration. Go to the next parsing state.
466  parseState = 1;
467  }
468  pos = searchString.find_first_not_of("\t\r\n\f\v ", posEnd);
469  posEnd = searchString.find_first_of("\t\r\n\f\v ", pos);
470  break;
471 
472  case 1:
473  // sword should be the uniform type.
474  varIdentityCrisis = shaderstringToEnum(Common::UString(sword));
475  //printf("%s (%u) ", sword.c_str(), varIdentityCrisis);
476  if (varIdentityCrisis == SHADER_INVALID) {
477  // Uncomment below if uniform buffers are to be included. Right now, the shader should use the binding layout instead.
478  /*
479  varIdentityCrisis = SHADER_UNIFORM_BUFFER;
480 
481  posEndi = sword.find_first_of("{");
482  if (posEndi != std::string::npos)
483  sword.erase(sword.length(), posEndi - sword.length());
484  sword.erase(sword.find_last_not_of(whitespace)+1);
485 
486  status("unknown shader variable type encountered, assuming uniform buffer of name: %s\n", sword.c_str());
487 
488  new_var = new ShaderVariable;
489  new_var->count = 1;
490  new_var->type = SHADER_UNIFORM_BUFFER;
491  new_var->location = 0;
492  strncpy(new_var->name, sword.c_str(), 51);
493  var_list->append(new_var);
494  */
495  parseState = 0;
496  } else {
497  parseState = 2;
498  pos = searchString.find_first_not_of("\t\r\n\f\v ", posEnd);
499  posEnd = searchString.find_first_of(",;", pos); // Only check for , or ; to determine the next variable.
500  }
501  break;
502 
503  case 2:
504  posEndi = sword.length();
505  posi = sword.find('=');
506  if (posi != std::string::npos) {
507  sword.erase(posi, posEndi - posi); // Check for and remove any initialisers.
508  }
509 
510  num = 1; // Default to a single element.
511  posi = sword.find('[');
512  if (posi != std::string::npos) {
513  posEndi = sword.find(']'); // Assume for now that it exists.
514  snum = sword.substr(posi+1, posEndi - posi - 1);
515  num = atoi(snum.c_str());//std::stoi(snum);//atoi(snum.c_str());
516  sword.erase(posi, sword.length() - posi);
517  }
518  // sword may contain trailing whitespaces, so remove them.
519  sword.erase(sword.find_last_not_of("\t\r\n\f\v ")+1);
520 
521  // sword should now be the name of a variable, of type varIdentityCrisis, numbering num.
522  varList.push_back(ShaderObject::ShaderObjectVariable(varIdentityCrisis, num, sword));
523 
524  if (searchString.at(posEnd) == ';') {
525  ++posEnd; // As the first non-whitespace character is looked for next, increment posEnd to avoid picking up on the ';'.
526  // End of current uniform, reset parse state.
527  parseState = 0;
528  pos = searchString.find_first_not_of("\t\r\n\f\v ", posEnd);
529  posEnd = searchString.find_first_of("\t\r\n\f\v ", pos);
530  } else {
531  ++posEnd; // As the first non-whitespace character is looked for next, increment posEnd to avoid picking up on the ','.
532  pos = searchString.find_first_not_of("\t\r\n\f\v ", posEnd);
533  posEnd = searchString.find_first_of("\t\r\n\v\f ,;", pos);
534  }
535  break;
536 
537  default: parseState = 0; break;
538  }
539  }
540 
541  varList.resize(varList.size());
542 }
543 
545  if (object->glid != 0) {
546  return; // Shader object already initialised.
547  }
548 
549  object->glid = glCreateShader(object->type == SHADER_VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
550  const char *text = object->shaderString.c_str();
551  glShaderSource(object->glid, 1, (const GLchar **)(&text), 0);
552  glCompileShader(object->glid);
553 
554  GLint gl_status;
555  glGetShaderiv(object->glid, GL_COMPILE_STATUS, &gl_status);
556  if (gl_status == GL_FALSE) {
557  GLsizei logolength;
558  char logorama[4096];
559  glGetShaderInfoLog(object->glid, 4095, &logolength, logorama);
560  error("Shader compile failure! Driver output: %s", logorama);
561  }
562 }
563 
565  if (program->glid != 0) {
566  return;
567  }
568 
569  GLuint glid = glCreateProgram();
570  ShaderObject *vertexObject = program->vertexObject;
571  ShaderObject *fragmentObject = program->fragmentObject;
572 
573  // These functions will do nothing if the object has already been initialised.
574  genGLShader(vertexObject);
575  genGLShader(fragmentObject);
576 
577  registerShaderAttachment(glid, vertexObject);
578  registerShaderAttachment(glid, fragmentObject);
579 
580  // GL2.1 supports attribute binding, but apparently nvidia drivers can have a problem with aliasing to inbuilt functions.
581  // So only bind attribute locations for >= GL3.x, with 2.x using builtin.
582  if (GfxMan.isGL3()) {
583  // Attempt to bind some common attributes. Note that it doesn't hurt if the attributes don't exist in the shader program.
584  glBindAttribLocation(glid, (GLuint)(VERTEX_LOCATION), "inputPosition0");
585  glBindAttribLocation(glid, (GLuint)(VERTEX_TEXCOORD0), "inputUV0");
586  glBindAttribLocation(glid, (GLuint)(VERTEX_NORMAL), "inputNormal0");
587  glBindAttribLocation(glid, (GLuint)(VERTEX_TEXCOORD1), "inputUV1");
588  glBindAttribLocation(glid, (GLuint)(VERTEX_COLOR), "inputColour");
589  }
590 
591  glLinkProgram(glid);
592 
593  GLint linkStatus;
594  glGetProgramiv(glid, GL_LINK_STATUS, &linkStatus);
595  if (linkStatus == GL_FALSE) {
596  GLsizei logolength;
597  char logorama[4096];
598  glGetProgramInfoLog(glid, 4095, &logolength, logorama);
599  error("Shader link failure! Driver output: %s", logorama);
600 
601  glDeleteProgram(glid);
602 
603  return;
604  }
605 
606  program->glid = glid;
607 
608  for (uint32 i = 0; i < vertexObject->variablesCombined.size(); ++i) {
609  GLint location;
610  if (vertexObject->variablesCombined[i].type != SHADER_UNIFORM_BUFFER)
611  location = glGetUniformLocation(glid, vertexObject->variablesCombined[i].name.c_str());
612  else
613  location = glGetUniformBlockIndex(glid, vertexObject->variablesCombined[i].name.c_str());
614  program->vertexVariableLocations.push_back(location);
615  }
616 
617  for (uint32 i = 0; i < fragmentObject->variablesCombined.size(); ++i) {
618  GLint location;
619  if (fragmentObject->variablesCombined[i].type != SHADER_UNIFORM_BUFFER)
620  location = glGetUniformLocation(glid, fragmentObject->variablesCombined[i].name.c_str());
621  else
622  location = glGetUniformBlockIndex(glid, fragmentObject->variablesCombined[i].name.c_str());
623  program->fragmentVariableLocations.push_back(location);
624  }
625 
626  if (GfxMan.isGL3()) {
627  // Bind some common UBO points.
628  GLuint ubo_index;
629  ubo_index = glGetUniformBlockIndex(glid, "engine_ubo_view");
630  if (ubo_index != GL_INVALID_INDEX) {
631  glUniformBlockBinding(glid, ubo_index, UBO_VIEW_MATRICES);
632  }
633  ubo_index = glGetUniformBlockIndex(glid, "engine_ubo_screen");
634  if (ubo_index != GL_INVALID_INDEX) {
635  glUniformBlockBinding(glid, ubo_index, UBO_SCREEN_INFO);
636  }
637  ubo_index = glGetUniformBlockIndex(glid, "boneBlock");
638  if (ubo_index != GL_INVALID_INDEX) {
639  glUniformBlockBinding(glid, ubo_index, UBO_BONE_MATRICES);
640  }
641  }
642 
643  glUseProgram(0);
644 }
645 
646 static const char *shaderTypeChararray[] = {
647  "float",
648  "vec2",
649  "vec3",
650  "vec4",
651  "int",
652  "ivec2",
653  "ivec3",
654  "ivec4",
655  "uint",
656  "uvec2",
657  "uvec3",
658  "uvec4",
659  "bool",
660  "bvec2",
661  "bvec3",
662  "bvec4",
663  "mat2",
664  "mat2x2",
665  "mat2x3",
666  "mat2x4",
667  "mat3",
668  "mat3x2",
669  "mat3x3",
670  "mat3x4",
671  "mat4",
672  "mat4x2",
673  "mat4x3",
674  "mat4x4",
675  "sampler1D",
676  "sampler2D",
677  "sampler3D",
678  "samplerCube",
679  "sampler1DShadow",
680  "sampler2DShadow",
681  "sampler1DArray",
682  "sampler2DArray",
683  "sampler1DArrayShadow",
684  "sampler2DArrayShadow",
685  "samplerBuffer",
686  "isampler1D",
687  "isampler2D",
688  "isampler3D",
689  "isamplerCube",
690  "isampler1DArray",
691  "isampler2DArray",
692  "usampler1D",
693  "usampler2D",
694  "usampler3D",
695  "usamplerCube",
696  "usampler1DArray",
697  "usampler2DArray",
698  "uniformBufferInvalid"
699 };
700 
702  // Yes, using a hash table would make this an awful lot faster.
704  for (unsigned int i = 0; i < SHADER_INVALID; ++i) {
705  if (stringType == shaderTypeChararray[i]) {
706  varType = (ShaderVariableType)i;
707  break;
708  }
709  }
710  return varType;
711 }
712 
713 } // End of namespace Shader
714 
715 } // End of namespace Graphics
void parseShaderVariables(const Common::UString &shaderString, std::vector< ShaderObject::ShaderObjectVariable > &variableList)
Parses a given string, representing a GLSL shader, and extracts uniform variable information from it...
Definition: shader.cpp:438
void build(bool isGL3, Common::UString &v_string, Common::UString &f_string)
ShaderProgram * getShaderProgram(ShaderObject *vertexObject, ShaderObject *fragmentObject)
Definition: shader.cpp:335
The global graphics manager.
A class holding an UTF-8 string.
Definition: ustring.h:48
std::vector< ShaderObject::ShaderObjectVariable > variablesSelf
Definition: shader.h:205
uint64_t uint64
Definition: types.h:206
ShaderProgram * registerShaderProgram(ShaderObject *vertexObject, ShaderObject *fragmentObject)
Definition: shader.cpp:373
Shader runtime builder.
void declareSampler(ShaderDescriptor::Sampler sampler, ShaderDescriptor::SamplerType type)
Common::UString shaderString
Definition: shader.h:203
void bindShaderVariable(ShaderObject::ShaderObjectVariable &var, GLint loc, const void *data)
Definition: shader.cpp:228
Common::Mutex _programMutex
Definition: shader.h:285
void connect(ShaderDescriptor::Sampler sampler, ShaderDescriptor::Input input, ShaderDescriptor::Action action)
Connect an input to a sampler and an action.
ShaderObject * fragmentObject
Definition: shader.h:219
ShaderObject * getShaderObject(const Common::UString &name, ShaderType type)
Definition: shader.cpp:184
The shader manager.
Definition: shader.h:240
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
void clear()
Clear shader descriptor information.
The global shader manager.
#define UNUSED(x)
Definition: system.h:170
ShaderVariableType shaderstringToEnum(const Common::UString &stype)
Definition: shader.cpp:701
Utility templates and functions.
ShaderVariableType
Enum of all supported shader variable parsing and automatic binding.
Definition: shader.h:85
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Definition: singleton.h:122
void genGLShader(ShaderObject *object)
Generate GL ids for, and compile a shader object.
Definition: shader.cpp:544
Not really blending, but component-wise multiply.
std::vector< GLint > fragmentVariableLocations
Definition: shader.h:221
void declareUniform(ShaderDescriptor::Uniform uniform)
ShaderObject * vertexObject
Definition: shader.h:218
std::vector< Shader::ShaderProgram * > _shaderProgramArray
Definition: shader.h:282
void deinit()
Deinitialise shader subsystem.
Definition: shader.cpp:165
void registerShaderAttachment(GLuint progid, ShaderObject *obj)
Recursively attaches shader objects to a given program.
Definition: shader.cpp:366
void genShaderVariableList(ShaderObject *obj, std::vector< ShaderObject::ShaderObjectVariable > &vars)
Definition: shader.cpp:408
Same as INPUT_UV0, but specifies input matrix too.
Definition: shaderbuilder.h:61
std::vector< ShaderObject * > subObjects
Definition: shader.h:207
void genGLProgram(ShaderProgram *program)
Generate GL id for, and link, a shader program.
Definition: shader.cpp:564
Uniform variable colour information.
A texture as used in the Aurora engines.
void init()
Initialise shader management, including default shader set creation.
Definition: shader.cpp:86
#define ShaderMan
Shortcut for accessing the shader manager.
Definition: shader.h:293
uint32_t uint32
Definition: types.h:204
std::map< Common::UString, Shader::ShaderObject * > _shaderObjectMap
Definition: shader.h:281
void lock()
Definition: mutex.cpp:41
void status(const char *s,...)
Definition: util.cpp:52
std::vector< GLint > vertexVariableLocations
Definition: shader.h:220
void addPass(ShaderDescriptor::Action action, ShaderDescriptor::Blend blend)
A container of OpenGL elements.
Definition: glcontainer.h:35
void unlock()
Definition: mutex.cpp:47
static const char * shaderTypeChararray[]
Definition: shader.cpp:646
void declareInput(ShaderDescriptor::Input input)
void bindShaderInstance(ShaderProgram *program, const void **vertexVariables, const void **fragmentVariables)
Definition: shader.cpp:324
void NORETURN_PRE error(const char *s,...)
Definition: util.cpp:86
void clear()
Clear the string&#39;s contents.
Definition: ustring.cpp:236
Common::Mutex _shaderMutex
Definition: shader.h:284
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
std::vector< ShaderObject::ShaderObjectVariable > variablesCombined
Definition: shader.h:206
Per-vertex colour information.