1 /*=========================================================================
2
3 Program: Visualization Toolkit
4
5 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
6 All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notice for more information.
12
13 =========================================================================*/
14 #include "vtkShaderProgram.h"
15 #include "vtkObjectFactory.h"
16
17 #include "vtk_glew.h"
18 #include "vtkShader.h"
19 #include "vtkMatrix3x3.h"
20 #include "vtkMatrix4x4.h"
21 #include "vtkOpenGLRenderWindow.h"
22 #include "vtkOpenGLShaderCache.h"
23 #include "vtkTypeTraits.h"
24
25 # include <sstream>
26
27 namespace {
28
convertTypeToGL(int type)29 inline GLenum convertTypeToGL(int type)
30 {
31 switch (type)
32 {
33 case VTK_CHAR:
34 return GL_BYTE;
35 case VTK_UNSIGNED_CHAR:
36 return GL_UNSIGNED_BYTE;
37 case VTK_SHORT:
38 return GL_SHORT;
39 case VTK_UNSIGNED_SHORT:
40 return GL_UNSIGNED_SHORT;
41 case VTK_INT:
42 return GL_INT;
43 case VTK_UNSIGNED_INT:
44 return GL_UNSIGNED_INT;
45 case VTK_FLOAT:
46 return GL_FLOAT;
47 case VTK_DOUBLE:
48 #ifdef GL_DOUBLE
49 return GL_DOUBLE;
50 #else
51 vtkGenericWarningMacro(<< "Attempt to use GL_DOUBLE when not supported");
52 return 0;
53 #endif
54 default:
55 return 0;
56 }
57 }
58
59 } // end anon namespace
60
vtkStandardNewMacro(vtkShaderProgram)61 vtkStandardNewMacro(vtkShaderProgram)
62
63 vtkShaderProgram::vtkShaderProgram() : Handle(0), VertexShaderHandle(0),
64 FragmentShaderHandle(0), Linked(false), Bound(false)
65 {
66 this->VertexShader = vtkShader::New();
67 this->VertexShader->SetType(vtkShader::Vertex);
68 this->FragmentShader = vtkShader::New();
69 this->FragmentShader->SetType(vtkShader::Fragment);
70 this->GeometryShader = vtkShader::New();
71 this->GeometryShader->SetType(vtkShader::Geometry);
72
73 this->Compiled = false;
74 }
75
~vtkShaderProgram()76 vtkShaderProgram::~vtkShaderProgram()
77 {
78 if (this->VertexShader)
79 {
80 this->VertexShader->Delete();
81 this->VertexShader = NULL;
82 }
83 if (this->FragmentShader)
84 {
85 this->FragmentShader->Delete();
86 this->FragmentShader = NULL;
87 }
88 if (this->GeometryShader)
89 {
90 this->GeometryShader->Delete();
91 this->GeometryShader = NULL;
92 }
93 }
94
SetAttributeArray(const char * name,const T & array,int tupleSize,NormalizeOption normalize)95 template <class T> bool vtkShaderProgram::SetAttributeArray(const char *name,
96 const T &array, int tupleSize,
97 NormalizeOption normalize)
98 {
99 if (array.empty())
100 {
101 this->Error = "Refusing to upload empty array for attribute " + std::string(name) + ".";
102 return false;
103 }
104 int type = vtkTypeTraits<typename T::value_type>::VTKTypeID();
105 return this->SetAttributeArrayInternal(name, &array[0], type, tupleSize,
106 normalize);
107 }
108
AttachShader(const vtkShader * shader)109 bool vtkShaderProgram::AttachShader(const vtkShader *shader)
110 {
111 if (shader->GetHandle() == 0)
112 {
113 this->Error = "Shader object was not initialized, cannot attach it.";
114 return false;
115 }
116 if (shader->GetType() == vtkShader::Unknown)
117 {
118 this->Error = "Shader object is of type Unknown and cannot be used.";
119 return false;
120 }
121
122 if (this->Handle == 0)
123 {
124 GLuint handle_ = glCreateProgram();
125 if (handle_ == 0)
126 {
127 this->Error = "Could not create shader program.";
128 return false;
129 }
130 this->Handle = static_cast<int>(handle_);
131 this->Linked = false;
132 }
133
134 if (shader->GetType() == vtkShader::Vertex)
135 {
136 if (VertexShaderHandle != 0)
137 {
138 glDetachShader(static_cast<GLuint>(Handle),
139 static_cast<GLuint>(VertexShaderHandle));
140 }
141 this->VertexShaderHandle = shader->GetHandle();
142 }
143 else if (shader->GetType() == vtkShader::Fragment)
144 {
145 if (FragmentShaderHandle != 0)
146 {
147 glDetachShader(static_cast<GLuint>(Handle),
148 static_cast<GLuint>(FragmentShaderHandle));
149 }
150 this->FragmentShaderHandle = shader->GetHandle();
151 }
152 else
153 {
154 this->Error = "Unknown shader type encountered - this should not happen.";
155 return false;
156 }
157
158 glAttachShader(static_cast<GLuint>(this->Handle),
159 static_cast<GLuint>(shader->GetHandle()));
160 this->Linked = false;
161 return true;
162 }
163
DetachShader(const vtkShader * shader)164 bool vtkShaderProgram::DetachShader(const vtkShader *shader)
165 {
166 if (shader->GetHandle() == 0)
167 {
168 this->Error = "Shader object was not initialized, cannot attach it.";
169 return false;
170 }
171 if (shader->GetType() == vtkShader::Unknown)
172 {
173 this->Error = "Shader object is of type Unknown and cannot be used.";
174 return false;
175 }
176 if (this->Handle == 0)
177 {
178 this->Error = "This shader prorgram has not been initialized yet.";
179 }
180
181 switch (shader->GetType())
182 {
183 case vtkShader::Vertex:
184 if (this->VertexShaderHandle != shader->GetHandle())
185 {
186 Error = "The supplied shader was not attached to this program.";
187 return false;
188 }
189 else
190 {
191 glDetachShader(static_cast<GLuint>(this->Handle),
192 static_cast<GLuint>(shader->GetHandle()));
193 this->VertexShaderHandle = 0;
194 this->Linked = false;
195 return true;
196 }
197 case vtkShader::Fragment:
198 if (this->FragmentShaderHandle != shader->GetHandle())
199 {
200 this->Error = "The supplied shader was not attached to this program.";
201 return false;
202 }
203 else
204 {
205 glDetachShader(static_cast<GLuint>(this->Handle),
206 static_cast<GLuint>(shader->GetHandle()));
207 this->FragmentShaderHandle = 0;
208 this->Linked = false;
209 return true;
210 }
211 default:
212 return false;
213 }
214 }
215
Link()216 bool vtkShaderProgram::Link()
217 {
218 if (this->Linked)
219 {
220 return true;
221 }
222
223 if (this->Handle == 0)
224 {
225 this->Error = "Program has not been initialized, and/or does not have shaders.";
226 return false;
227 }
228
229 GLint isCompiled;
230 glLinkProgram(static_cast<GLuint>(this->Handle));
231 glGetProgramiv(static_cast<GLuint>(this->Handle), GL_LINK_STATUS, &isCompiled);
232 if (isCompiled == 0)
233 {
234 GLint length(0);
235 glGetProgramiv(static_cast<GLuint>(this->Handle), GL_INFO_LOG_LENGTH, &length);
236 if (length > 1)
237 {
238 char *logMessage = new char[length];
239 glGetProgramInfoLog(static_cast<GLuint>(this->Handle), length, NULL, logMessage);
240 this->Error = logMessage;
241 delete[] logMessage;
242 }
243 return false;
244 }
245 this->Linked = true;
246 this->Attributes.clear();
247 return true;
248 }
249
Bind()250 bool vtkShaderProgram::Bind()
251 {
252 if (!this->Linked && !this->Link())
253 {
254 return false;
255 }
256
257 glUseProgram(static_cast<GLuint>(this->Handle));
258 this->Bound = true;
259 return true;
260 }
261
262 // return 0 if there is an issue
CompileShader()263 int vtkShaderProgram::CompileShader()
264 {
265 if (!this->GetVertexShader()->Compile())
266 {
267 int lineNum = 1;
268 std::istringstream stream(this->GetVertexShader()->GetSource());
269 std::stringstream sstm;
270 std::string aline;
271 while (std::getline(stream, aline))
272 {
273 sstm << lineNum << ": " << aline << "\n";
274 lineNum++;
275 }
276 vtkErrorMacro(<< sstm.str());
277 vtkErrorMacro(<< this->GetVertexShader()->GetError());
278 return 0;
279 }
280 if (!this->GetFragmentShader()->Compile())
281 {
282 int lineNum = 1;
283 std::istringstream stream(this->GetFragmentShader()->GetSource());
284 std::stringstream sstm;
285 std::string aline;
286 while (std::getline(stream, aline))
287 {
288 sstm << lineNum << ": " << aline << "\n";
289 lineNum++;
290 }
291 vtkErrorMacro(<< sstm.str());
292 vtkErrorMacro(<< this->GetFragmentShader()->GetError());
293 return 0;
294 }
295 if (!this->AttachShader(this->GetVertexShader()))
296 {
297 vtkErrorMacro(<< this->GetError());
298 return 0;
299 }
300 if (!this->AttachShader(this->GetFragmentShader()))
301 {
302 vtkErrorMacro(<< this->GetError());
303 return 0;
304 }
305 if (!this->Link())
306 {
307 vtkErrorMacro(<< "Links failed: " << this->GetError());
308 return 0;
309 }
310
311 this->Compiled = true;
312 return 1;
313 }
314
315
316
Release()317 void vtkShaderProgram::Release()
318 {
319 glUseProgram(0);
320 this->Bound = false;
321 }
322
ReleaseGraphicsResources(vtkWindow * win)323 void vtkShaderProgram::ReleaseGraphicsResources(vtkWindow *win)
324 {
325 this->Release();
326
327 if (this->Compiled)
328 {
329 this->DetachShader(this->VertexShader);
330 this->DetachShader(this->FragmentShader);
331 this->VertexShader->Cleanup();
332 this->FragmentShader->Cleanup();
333 this->Compiled = false;
334 }
335
336 vtkOpenGLRenderWindow *renWin = vtkOpenGLRenderWindow::SafeDownCast(win);
337 if (renWin->GetShaderCache()->GetLastShaderBound() == this)
338 {
339 renWin->GetShaderCache()->ClearLastShaderBound();
340 }
341
342 if (this->Handle != 0)
343 {
344 glDeleteProgram(this->Handle);
345 this->Handle = 0;
346 this->Linked = false;
347 }
348
349 }
350
EnableAttributeArray(const char * name)351 bool vtkShaderProgram::EnableAttributeArray(const char *name)
352 {
353 GLint location = static_cast<GLint>(this->FindAttributeArray(name));
354 if (location == -1)
355 {
356 this->Error = "Could not enable attribute " + std::string(name) + ". No such attribute.";
357 return false;
358 }
359 glEnableVertexAttribArray(location);
360 return true;
361 }
362
DisableAttributeArray(const char * name)363 bool vtkShaderProgram::DisableAttributeArray(const char *name)
364 {
365 GLint location = static_cast<GLint>(this->FindAttributeArray(name));
366 if (location == -1)
367 {
368 this->Error = "Could not disable attribute " + std::string(name) + ". No such attribute.";
369 return false;
370 }
371 glDisableVertexAttribArray(location);
372 return true;
373 }
374
375 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
376
UseAttributeArray(const char * name,int offset,size_t stride,int elementType,int elementTupleSize,NormalizeOption normalize)377 bool vtkShaderProgram::UseAttributeArray(const char *name, int offset,
378 size_t stride, int elementType,
379 int elementTupleSize,
380 NormalizeOption normalize)
381 {
382 GLint location = static_cast<GLint>(this->FindAttributeArray(name));
383 if (location == -1)
384 {
385 this->Error = "Could not use attribute " + std::string(name) + ". No such attribute.";
386 return false;
387 }
388 glVertexAttribPointer(location, elementTupleSize, convertTypeToGL(elementType),
389 normalize == Normalize ? GL_TRUE : GL_FALSE,
390 static_cast<GLsizei>(stride), BUFFER_OFFSET(offset));
391 return true;
392 }
393
SetUniformi(const char * name,int i)394 bool vtkShaderProgram::SetUniformi(const char *name, int i)
395 {
396 GLint location = static_cast<GLint>(this->FindUniform(name));
397 if (location == -1)
398 {
399 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
400 return false;
401 }
402 glUniform1i(location, static_cast<GLint>(i));
403 return true;
404 }
405
SetUniformf(const char * name,float f)406 bool vtkShaderProgram::SetUniformf(const char *name, float f)
407 {
408 GLint location = static_cast<GLint>(this->FindUniform(name));
409 if (location == -1)
410 {
411 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
412 return false;
413 }
414 glUniform1f(location, static_cast<GLfloat>(f));
415 return true;
416 }
417
SetUniformMatrix(const char * name,vtkMatrix4x4 * matrix)418 bool vtkShaderProgram::SetUniformMatrix(const char *name,
419 vtkMatrix4x4 *matrix)
420 {
421 GLint location = static_cast<GLint>(this->FindUniform(name));
422 if (location == -1)
423 {
424 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
425 return false;
426 }
427 float data[16];
428 for (int i = 0; i < 16; ++i)
429 {
430 data[i] = matrix->Element[i / 4][i % 4];
431 }
432 glUniformMatrix4fv(location, 1, GL_FALSE, data);
433 return true;
434 }
435
SetUniformMatrix3x3(const char * name,float * matrix)436 bool vtkShaderProgram::SetUniformMatrix3x3(const char *name,
437 float *matrix)
438 {
439 GLint location = static_cast<GLint>(this->FindUniform(name));
440 if (location == -1)
441 {
442 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
443 return false;
444 }
445 glUniformMatrix3fv(location, 1, GL_FALSE, matrix);
446 return true;
447 }
448
SetUniformMatrix4x4(const char * name,float * matrix)449 bool vtkShaderProgram::SetUniformMatrix4x4(const char *name,
450 float *matrix)
451 {
452 GLint location = static_cast<GLint>(this->FindUniform(name));
453 if (location == -1)
454 {
455 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
456 return false;
457 }
458 glUniformMatrix4fv(location, 1, GL_FALSE, matrix);
459 return true;
460 }
461
SetUniformMatrix(const char * name,vtkMatrix3x3 * matrix)462 bool vtkShaderProgram::SetUniformMatrix(const char *name,
463 vtkMatrix3x3 *matrix)
464 {
465 GLint location = static_cast<GLint>(this->FindUniform(name));
466 if (location == -1)
467 {
468 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
469 return false;
470 }
471 float data[9];
472 for (int i = 0; i < 9; ++i)
473 {
474 data[i] = matrix->GetElement(i / 3, i % 3);
475 }
476 glUniformMatrix3fv(location, 1, GL_FALSE, data);
477 return true;
478 }
479
SetUniform1fv(const char * name,const int count,const float * v)480 bool vtkShaderProgram::SetUniform1fv(const char *name, const int count,
481 const float *v)
482 {
483 GLint location = static_cast<GLint>(this->FindUniform(name));
484 if (location == -1)
485 {
486 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
487 return false;
488 }
489 glUniform1fv(location, count, static_cast<const GLfloat *>(v));
490 return true;
491 }
492
SetUniform1iv(const char * name,const int count,const int * v)493 bool vtkShaderProgram::SetUniform1iv(const char *name, const int count,
494 const int *v)
495 {
496 GLint location = static_cast<GLint>(this->FindUniform(name));
497 if (location == -1)
498 {
499 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
500 return false;
501 }
502 glUniform1iv(location, count, static_cast<const GLint *>(v));
503 return true;
504 }
505
SetUniform3fv(const char * name,const int count,const float (* v)[3])506 bool vtkShaderProgram::SetUniform3fv(const char *name, const int count,
507 const float (*v)[3])
508 {
509 GLint location = static_cast<GLint>(this->FindUniform(name));
510 if (location == -1)
511 {
512 Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
513 return false;
514 }
515 glUniform3fv(location, count, (const GLfloat *)v);
516 return true;
517 }
518
SetUniform4fv(const char * name,const int count,const float (* v)[4])519 bool vtkShaderProgram::SetUniform4fv(const char *name, const int count,
520 const float (*v)[4])
521 {
522 GLint location = static_cast<GLint>(this->FindUniform(name));
523 if (location == -1)
524 {
525 Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
526 return false;
527 }
528 glUniform4fv(location, count, (const GLfloat *)v);
529 return true;
530 }
531
SetUniform2f(const char * name,const float v[2])532 bool vtkShaderProgram::SetUniform2f(const char *name, const float v[2])
533 {
534 GLint location = static_cast<GLint>(this->FindUniform(name));
535 if (location == -1)
536 {
537 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
538 return false;
539 }
540 glUniform2fv(location, 1, v);
541 return true;
542 }
543
SetUniform2fv(const char * name,const int count,const float (* f)[2])544 bool vtkShaderProgram::SetUniform2fv(const char *name, const int count,
545 const float (*f)[2])
546 {
547 GLint location = static_cast<GLint>(this->FindUniform(name));
548 if (location == -1)
549 {
550 Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
551 return false;
552 }
553 glUniform2fv(location, count, (const GLfloat *)f);
554 return true;
555 }
556
SetUniform3f(const char * name,const float v[3])557 bool vtkShaderProgram::SetUniform3f(const char *name, const float v[3])
558 {
559 GLint location = static_cast<GLint>(this->FindUniform(name));
560 if (location == -1)
561 {
562 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
563 return false;
564 }
565 glUniform3fv(location, 1, v);
566 return true;
567 }
568
SetUniform4f(const char * name,const float v[4])569 bool vtkShaderProgram::SetUniform4f(const char *name, const float v[4])
570 {
571 GLint location = static_cast<GLint>(this->FindUniform(name));
572 if (location == -1)
573 {
574 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
575 return false;
576 }
577 glUniform4fv(location, 1, v);
578 return true;
579 }
580
SetUniform2i(const char * name,const int v[2])581 bool vtkShaderProgram::SetUniform2i(const char *name, const int v[2])
582 {
583 GLint location = static_cast<GLint>(this->FindUniform(name));
584 if (location == -1)
585 {
586 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
587 return false;
588 }
589 glUniform2iv(location, 1, v);
590 return true;
591 }
592
SetUniform3uc(const char * name,const unsigned char v[3])593 bool vtkShaderProgram::SetUniform3uc(const char *name,
594 const unsigned char v[3])
595 {
596 GLint location = static_cast<GLint>(this->FindUniform(name));
597 if (location == -1)
598 {
599 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
600 return false;
601 }
602 float colorf[3] = {v[0] / 255.0f, v[1] / 255.0f, v[2] / 255.0f};
603 glUniform3fv(location, 1, colorf);
604 return true;
605 }
606
SetUniform4uc(const char * name,const unsigned char v[4])607 bool vtkShaderProgram::SetUniform4uc(const char *name,
608 const unsigned char v[4])
609 {
610 GLint location = static_cast<GLint>(this->FindUniform(name));
611 if (location == -1)
612 {
613 this->Error = "Could not set uniform " + std::string(name) + ". No such uniform.";
614 return false;
615 }
616 float colorf[4] = {v[0] / 255.0f, v[1] / 255.0f, v[2] / 255.0f, v[3] / 255.0f};
617 glUniform4fv(location, 1, colorf);
618 return true;
619 }
620
SetAttributeArrayInternal(const char * name,void * buffer,int type,int tupleSize,vtkShaderProgram::NormalizeOption normalize)621 bool vtkShaderProgram::SetAttributeArrayInternal(
622 const char *name, void *buffer, int type, int tupleSize,
623 vtkShaderProgram::NormalizeOption normalize)
624 {
625 if (type == -1)
626 {
627 this->Error = "Unrecognized data type for attribute " + std::string(name) + ".";
628 return false;
629 }
630 GLint location = static_cast<GLint>(this->FindAttributeArray(name));
631 if (location == -1)
632 {
633 this->Error = "Could not set attribute " + std::string(name) + ". No such attribute.";
634 return false;
635 }
636 const GLvoid *data = static_cast<const GLvoid *>(buffer);
637 glVertexAttribPointer(location, tupleSize, convertTypeToGL(type),
638 normalize == Normalize ? GL_TRUE : GL_FALSE, 0, data);
639 return true;
640 }
641
FindAttributeArray(const char * name)642 inline int vtkShaderProgram::FindAttributeArray(const char *name)
643 {
644 if (name == NULL || !this->Linked)
645 {
646 return -1;
647 }
648 GLint location =
649 static_cast<int>(glGetAttribLocation(static_cast<GLuint>(Handle),
650 (const GLchar *)name));
651 if (location == -1)
652 {
653 this->Error = "Specified attribute not found in current shader program: ";
654 this->Error += name;
655 }
656
657 return location;
658 }
659
FindUniform(const char * name)660 inline int vtkShaderProgram::FindUniform(const char *name)
661 {
662 if (name == NULL || !this->Linked)
663 {
664 return -1;
665 }
666 GLint location =
667 static_cast<int>(glGetUniformLocation(static_cast<GLuint>(Handle),
668 (const GLchar *)name));
669 if (location == -1)
670 {
671 this->Error = "Uniform " + std::string(name) + " not found in current shader program.";
672 }
673
674 return location;
675 }
676
677 // ----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)678 void vtkShaderProgram::PrintSelf(ostream& os, vtkIndent indent)
679 {
680 this->Superclass::PrintSelf(os,indent);
681 }
682