Stellarium 0.12.2
StelQGLGLSLShader.hpp
1 /*
2  * Stellarium
3  * Copyright (C) 2012 Ferdinand Majerech
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  */
19 
20 #ifndef _STELQGLGLSLSHADER_HPP_
21 #define _STELQGLGLSLSHADER_HPP_
22 
23 #include <QGLShader>
24 #include <QGLShaderProgram>
25 #include <QMap>
26 #include <QtOpenGL>
27 
28 #include "StelGLSLShader.hpp"
29 #include "StelGLUtilityFunctions.hpp"
30 
31 
33 typedef float RAW_GL_MATRIX [4][4];
34 
39 {
40 private:
42  struct OptionalShader
43  {
45  bool enabled;
47  QGLShader* shader;
48  };
49 
51  enum State
52  {
57  State_Unlocked,
62  State_Modified,
65  State_Built,
66  };
67 
69  enum UniformType
70  {
75  UniformType_none = 0,
77  UniformType_float = 1,
79  UniformType_vec2 = 2,
81  UniformType_vec3 = 3,
83  UniformType_vec4 = 4,
85  UniformType_mat4 = 5,
87  UniformType_bool = 6,
89  UniformType_int = 7,
91  UniformType_max = 8
92  };
93 
97  static const unsigned int UNIFORM_STORAGE = 512;
98 
100  static const int MAX_UNIFORMS = 32;
101 
105  static int UNIFORM_SIZES[UniformType_max];
106 
107 public:
115  StelQGLGLSLShader(class StelQGL2Renderer* renderer, bool internal);
116 
117  virtual ~StelQGLGLSLShader()
118  {
119  Q_ASSERT_X(!bound, Q_FUNC_INFO,
120  "Forgot to release() a bound shader before destroying");
121  foreach(QGLShader* shader, defaultVertexShaders) {delete shader;}
122  foreach(OptionalShader shader, namedVertexShaders){delete shader.shader;}
123  foreach(QGLShader* shader, defaultFragmentShaders){delete shader;}
124  foreach(QGLShaderProgram* program, programCache) {delete program;}
125  }
126 
127  virtual bool addVertexShader(const QString& source);
128 
129  virtual bool addFragmentShader(const QString& source);
130 
131  virtual bool build();
132 
133  virtual QString log() const
134  {
135  return aggregatedLog + ((NULL == program) ? QString() : program->log());
136  }
137 
138  virtual void unlock()
139  {
140  switch(state)
141  {
142  case State_Unlocked:
143  case State_Modified:
144  return;
145  case State_Built:
146  state = State_Unlocked;
147  return;
148  }
149  }
150 
151  virtual bool addVertexShader(const QString& name, const QString& source);
152 
153  virtual bool hasVertexShader(const QString& name) const
154  {
155  return namedVertexShaders.contains(name);
156  }
157 
158  virtual void enableVertexShader(const QString& name)
159  {
160  Q_ASSERT_X(namedVertexShaders.contains(name), Q_FUNC_INFO,
161  "Trying to enable a vertex shader with an unknown name");
162  Q_ASSERT_X(state == State_Unlocked || state == State_Modified, Q_FUNC_INFO,
163  "Can't enable a vertex shader after the shader has been built");
164 
165  OptionalShader& shader(namedVertexShaders[name]);
166  if(shader.enabled) {return;}
167  shader.enabled = true;
168  state = State_Modified;
169  }
170 
171  virtual void disableVertexShader(const QString& name)
172  {
173  Q_ASSERT_X(namedVertexShaders.contains(name), Q_FUNC_INFO,
174  "Trying to disable a vertex shader with an unknown name");
175  Q_ASSERT_X(state == State_Unlocked || state == State_Modified, Q_FUNC_INFO,
176  "Can't disable a vertex shader after the shader has been built");
177 
178  OptionalShader& shader(namedVertexShaders[name]);
179  if(!shader.enabled) {return;}
180  shader.enabled = false;
181  state = State_Modified;
182  }
183 
184  virtual void bind();
185 
186  virtual void release();
187 
189  {
191  }
192 
196  QGLShaderProgram& getProgram()
197  {
198  Q_ASSERT_X(bound && state == State_Built,
199  Q_FUNC_INFO, "Trying to use an unbound shader for drawing");
200  return *program;
201  }
202 
207  {
209  }
210 
216  {
217  Q_ASSERT_X(bound && state == State_Built, Q_FUNC_INFO,
218  "uploadUniforms called on a shader that is not bound");
219  const unsigned char* data = uniformStorage;
220  for (int u = 0; u < uniformCount; u++)
221  {
222  const UniformType type = static_cast<UniformType>(uniformTypes[u]);
223  switch(type)
224  {
225  case UniformType_float:
226  {
227  const float& value(*reinterpret_cast<const float* const>(data));
228  program->setUniformValue(uniformNames[u], value);
229  break;
230  }
231  case UniformType_vec2:
232  {
233  const Vec2f& v(*reinterpret_cast<const Vec2f* const>(data));
234  program->setUniformValue(uniformNames[u], v[0], v[1]);
235  break;
236  }
237  case UniformType_vec3:
238  {
239  const Vec3f& v(*reinterpret_cast<const Vec3f* const>(data));
240  program->setUniformValue(uniformNames[u], v[0], v[1], v[2]);
241  break;
242  }
243  case UniformType_vec4:
244  {
245  const Vec4f& v(*reinterpret_cast<const Vec4f* const>(data));
246  program->setUniformValue(uniformNames[u], v[0], v[1], v[2], v[3]);
247  break;
248  }
249  case UniformType_mat4:
250  {
251  const RAW_GL_MATRIX& m(*reinterpret_cast<const RAW_GL_MATRIX* const>(data));
252  program->setUniformValue(uniformNames[u], m);
253  break;
254  }
255  case UniformType_bool:
256  {
257  const bool& value(*reinterpret_cast<const bool* const>(data));
258  program->setUniformValue(uniformNames[u], value);
259  break;
260  }
261  case UniformType_int:
262  {
263  const int& value(*reinterpret_cast<const int* const>(data));
264  program->setUniformValue(uniformNames[u], value);
265  break;
266  }
267  default:
268  Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown or invalid uniform type");
269  }
270  data += UNIFORM_SIZES[type];
271  }
272  }
273 
292  {
293  Q_ASSERT_X(bound && state == State_Built, Q_FUNC_INFO,
294  "pushUniformStorage() called when the shader is not bound");
295  Q_ASSERT_X(uniformStorageStackSize < MAX_UNIFORMS - 1, Q_FUNC_INFO,
296  "Too many uniform storage stack pushes");
300  }
301 
306  {
307  Q_ASSERT_X(bound && state == State_Built, Q_FUNC_INFO,
308  "popUniformStorage() called when the shader is not bound");
309  Q_ASSERT_X(uniformStorageStackSize >= 1, Q_FUNC_INFO,
310  "Too many uniform storage stack pops (nothing left to pop)");
315  }
316 
321  {
322  Q_ASSERT_X(bound && state == State_Built, Q_FUNC_INFO,
323  "clearUniforms() called when the shader is not bound");
324  // We don't zero out the storage - we'll overwrite it as we add new uniforms.
327  }
328 
329 protected:
332 
334  QVector<QGLShader*> defaultVertexShaders;
335 
337  QMap<QString, OptionalShader> namedVertexShaders;
338 
339  // There are no namedFragmentShaders, but they can be added if/when needed.
341  QVector<QGLShader*> defaultFragmentShaders;
342 
363  QMap<uintptr_t, QGLShaderProgram*> programCache;
364 
366  QGLShaderProgram* program;
367 
372  QString aggregatedLog;
373 
375  State state;
376 
378  bool bound;
379 
383 
387  const bool internal;
388 
397  unsigned char uniformStorage [UNIFORM_STORAGE];
398 
401 
405  unsigned char uniformTypes [MAX_UNIFORMS];
406 
411  const char* uniformNames [MAX_UNIFORMS];
412 
415 
418 
422  unsigned int uniformStorageUsedStack[MAX_UNIFORMS];
423 
427  unsigned char uniformCountStack[MAX_UNIFORMS];
428 
431 
432  virtual void setUniformValue_(const char* const name, const float value)
433  {
434  Q_ASSERT_X(bound, Q_FUNC_INFO,
435  "Trying to set a uniform value with an unbound shader");
436  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
437  Q_ASSERT_X((uniformStorageUsed + sizeof(float)) < UNIFORM_STORAGE, Q_FUNC_INFO,
438  "Uniform storage exceeded");
439  *static_cast<float*>(uniformStoragePointer) = value;
440  uniformNames[uniformCount] = name;
441  uniformTypes[uniformCount++] = UniformType_float;
442  uniformStorageUsed += sizeof(float);
444  }
445 
446  virtual void setUniformValue_(const char* const name, const Vec2f value)
447  {
448  Q_ASSERT_X(bound, Q_FUNC_INFO,
449  "Trying to set a uniform value with an unbound shader");
450  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
451  Q_ASSERT_X((uniformStorageUsed + sizeof(Vec2f)) < UNIFORM_STORAGE, Q_FUNC_INFO,
452  "Uniform storage exceeded");
453  *static_cast<Vec2f*>(uniformStoragePointer) = value;
454  uniformNames[uniformCount] = name;
455  uniformTypes[uniformCount] = UniformType_vec2;
456  ++uniformCount;
457  uniformStorageUsed += sizeof(Vec2f);
459  }
460 
461  virtual void setUniformValue_(const char* const name, const Vec3f& value)
462  {
463  Q_ASSERT_X(bound, Q_FUNC_INFO,
464  "Trying to set a uniform value with an unbound shader");
465  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
466  Q_ASSERT_X((uniformStorageUsed + sizeof(Vec3f)) < UNIFORM_STORAGE, Q_FUNC_INFO,
467  "Uniform storage exceeded");
468  *static_cast<Vec3f*>(uniformStoragePointer) = value;
469  uniformNames[uniformCount] = name;
470  uniformTypes[uniformCount] = UniformType_vec3;
471  ++uniformCount;
472  uniformStorageUsed += sizeof(Vec3f);
474  }
475 
476  virtual void setUniformValue_(const char* const name, const Vec4f& value)
477  {
478  Q_ASSERT_X(bound, Q_FUNC_INFO,
479  "Trying to set a uniform value with an unbound shader");
480  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
481  *static_cast<Vec4f*>(uniformStoragePointer) = value;
482  Q_ASSERT_X((uniformStorageUsed + sizeof(Vec4f)) < UNIFORM_STORAGE, Q_FUNC_INFO,
483  "Uniform storage exceeded");
484  uniformNames[uniformCount] = name;
485  uniformTypes[uniformCount] = UniformType_vec4;
486  ++uniformCount;
487  uniformStorageUsed += sizeof(Vec4f);
489  }
490 
491  virtual void setUniformValue_(const char* const name, const Mat4f& m)
492  {
493  Q_ASSERT_X(bound, Q_FUNC_INFO,
494  "Trying to set a uniform value with an unbound shader");
495  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
496  Q_ASSERT_X((uniformStorageUsed + sizeof(Mat4f)) < UNIFORM_STORAGE, Q_FUNC_INFO,
497  "Uniform storage exceeded");
498  *static_cast<Mat4f*>(uniformStoragePointer) = m;
499  uniformNames[uniformCount] = name;
500  uniformTypes[uniformCount] = UniformType_mat4;
501  ++uniformCount;
502  uniformStorageUsed += sizeof(Mat4f);
504  }
505 
506  virtual void setUniformValue_(const char* const name, const bool value)
507  {
508  Q_ASSERT_X(bound, Q_FUNC_INFO,
509  "Trying to set a uniform value with an unbound shader");
510  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
511  Q_ASSERT_X((uniformStorageUsed + sizeof(bool)) < UNIFORM_STORAGE, Q_FUNC_INFO,
512  "Uniform storage exceeded");
513  *static_cast<bool*>(uniformStoragePointer) = value;
514  uniformNames[uniformCount] = name;
515  uniformTypes[uniformCount] = UniformType_bool;
516  ++uniformCount;
517  uniformStorageUsed += sizeof(bool);
519  }
520 
521  virtual void setUniformValue_(const char* const name, const int value)
522  {
523  Q_ASSERT_X(bound, Q_FUNC_INFO,
524  "Trying to set a uniform value with an unbound shader");
525  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
526  Q_ASSERT_X((uniformStorageUsed + sizeof(int)) < UNIFORM_STORAGE, Q_FUNC_INFO,
527  "Uniform storage exceeded");
528  *static_cast<int*>(uniformStoragePointer) = value;
529  uniformNames[uniformCount] = name;
530  uniformTypes[uniformCount] = UniformType_int;
531  ++uniformCount;
532  uniformStorageUsed += sizeof(int);
534  }
535 
536 private:
542  QGLShaderProgram* getProgramFromCache();
543 
549  QGLShader* createVertexShader(const QString& source);
550 };
551 
552 #endif // _STELQGLGLSLSHADER_HPP_