Stellarium 0.12.4
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  void * const * 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)");
314  }
315 
320  {
321  Q_ASSERT_X(bound && state == State_Built, Q_FUNC_INFO,
322  "clearUniforms() called when the shader is not bound");
323  // We don't zero out the storage - we'll overwrite it as we add new uniforms.
325  }
326 
327 protected:
330 
332  QVector<QGLShader*> defaultVertexShaders;
333 
335  QMap<QString, OptionalShader> namedVertexShaders;
336 
337  // There are no namedFragmentShaders, but they can be added if/when needed.
339  QVector<QGLShader*> defaultFragmentShaders;
340 
361  QMap<uintptr_t, QGLShaderProgram*> programCache;
362 
364  QGLShaderProgram* program;
365 
370  QString aggregatedLog;
371 
373  State state;
374 
376  bool bound;
377 
381 
385  const bool internal;
386 
395  void* uniformStorage [UNIFORM_STORAGE / sizeof(void*)];
396 
400  unsigned char uniformTypes [MAX_UNIFORMS];
401 
406  const char* uniformNames [MAX_UNIFORMS];
407 
410 
413 
417  unsigned int uniformStorageUsedStack[MAX_UNIFORMS];
418 
422  unsigned char uniformCountStack[MAX_UNIFORMS];
423 
426 
427  void* setUniformValue_helper(const char* const name, const enum UniformType kind)
428  {
429  Q_ASSERT_X(bound, Q_FUNC_INFO,
430  "Trying to set a uniform value with an unbound shader");
431  Q_ASSERT_X(uniformCount < MAX_UNIFORMS, Q_FUNC_INFO, "Too many uniforms");
432  Q_ASSERT_X((unsigned)(uniformStorageUsed + UNIFORM_SIZES[kind]) < (UNIFORM_STORAGE / sizeof uniformStorage[0]), Q_FUNC_INFO,
433  "Uniform storage exceeded");
434  void* ret = static_cast<void*>(&uniformStorage[uniformStorageUsed]);
435  uniformNames[uniformCount] = name;
436  uniformTypes[uniformCount++] = kind;
437  uniformStorageUsed += UNIFORM_SIZES[kind];
438  return ret;
439  }
440 
441  virtual void setUniformValue_(const char* const name, const float value)
442  {
443  *static_cast<float*>(setUniformValue_helper(name, UniformType_float)) = value;
444  }
445 
446  virtual void setUniformValue_(const char* const name, const Vec2f value)
447  {
448  *static_cast<Vec2f*>(setUniformValue_helper(name, UniformType_vec2)) = value;
449  }
450 
451  virtual void setUniformValue_(const char* const name, const Vec3f& value)
452  {
453  *static_cast<Vec3f*>(setUniformValue_helper(name, UniformType_vec3)) = value;
454  }
455 
456  virtual void setUniformValue_(const char* const name, const Vec4f& value)
457  {
458  *static_cast<Vec4f*>(setUniformValue_helper(name, UniformType_vec4)) = value;
459  }
460 
461  virtual void setUniformValue_(const char* const name, const Mat4f& m)
462  {
463  *static_cast<Mat4f*>(setUniformValue_helper(name, UniformType_mat4)) = m;
464  }
465 
466  virtual void setUniformValue_(const char* const name, const bool value)
467  {
468  *static_cast<bool*>(setUniformValue_helper(name, UniformType_bool)) = value;
469  }
470 
471  virtual void setUniformValue_(const char* const name, const int value)
472  {
473  *static_cast<int*>(setUniformValue_helper(name, UniformType_int)) = value;
474  }
475 
476 private:
482  QGLShaderProgram* getProgramFromCache();
483 
489  QGLShader* createVertexShader(const QString& source);
490 };
491 
492 #endif // _STELQGLGLSLSHADER_HPP_