You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/3rd/VTK7.1/source/VTK-7.1.1/Rendering/OpenGL/vtkShaderProgram2.cxx

1161 lines
34 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkShaderProgram2.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkShaderProgram2.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkShader2Collection.h"
#include "vtkShader2.h"
#include "vtkUniformVariables.h"
#include "vtkgl.h"
#include "vtkOpenGLError.h"
#include <vector>
#include <sstream>
#include <cassert>
#include "vtkStdString.h"
static GLenum vtkGeometryTypeInVTKToGL[5] = {
GL_POINTS, // VTK_GEOMETRY_SHADER_IN_TYPE_POINTS=0
GL_LINES, // VTK_GEOMETRY_SHADER_IN_TYPE_LINES=1,
vtkgl::LINES_ADJACENCY_ARB, // VTK_GEOMETRY_SHADER_IN_TYPE_LINES_ADJACENCY=2
GL_TRIANGLES, // VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES=3
vtkgl::TRIANGLES_ADJACENCY_ARB // VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES_ADJACENCY=4
};
static const char *vtkGeometryTypeInAsStringArray[5] = {
"points",
"lines",
"lines with adjacency",
"triangles",
"triangles with adjacency"
};
static GLenum vtkGeometryTypeOutVTKToGL[3] = {
GL_POINTS, // VTK_GEOMETRY_SHADER_OUT_TYPE_POINTS=0
GL_LINE_STRIP, // VTK_GEOMETRY_SHADER_OUT_TYPE_LINE_STRIP=1,
GL_TRIANGLE_STRIP, // VTK_GEOMETRY_SHADER_OUT_TYPE_TRIANGLE_STRIP=2
};
//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkShaderProgram2);
//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkShaderProgram2, UniformVariables, vtkUniformVariables);
//----------------------------------------------------------------------------
vtkShaderProgram2::vtkShaderProgram2()
{
this->Context = NULL;
this->ExtensionsLoaded = false;
this->Id = 0;
this->SavedId = 0;
this->Shaders = vtkShader2Collection::New(); // an empty list.
this->LastBuildStatus = VTK_SHADER_PROGRAM2_COMPILE_FAILED;
this->GeometryTypeIn = VTK_GEOMETRY_SHADER_IN_TYPE_POINTS;
this->GeometryTypeOut = VTK_GEOMETRY_SHADER_OUT_TYPE_POINTS;
this->GeometryVerticesOut = 1;
// 8 as an initial capacity is nice because the allocation is aligned on
// 32-bit or 64-bit architecture.
this->LastLinkLogCapacity = 8;
this->LastLinkLog = new char[this->LastLinkLogCapacity];
this->LastLinkLog[0] = '\0'; // empty string
this->LastValidateLogCapacity = 8;
this->LastValidateLog = new char[this->LastValidateLogCapacity];
this->LastValidateLog[0] = '\0'; // empty string
this->UniformVariables = vtkUniformVariables::New(); // empty list
this->PrintErrors = true;
}
//-----------------------------------------------------------------------------
void vtkShaderProgram2::ReleaseGraphicsResources()
{
// because we don't hold a reference to the render
// context we don't have any control on when it is
// destroyed. In fact it may be destroyed before
// we are(eg smart pointers), in which case we should
// do nothing.
this->Shaders->ReleaseGraphicsResources();
if (this->Context && (this->Id != 0))
{
vtkgl::DeleteProgram(this->Id);
vtkOpenGLCheckErrorMacro("failed at glDeleteProgram");
this->Id = 0;
}
this->LastBuildStatus = VTK_SHADER_PROGRAM2_COMPILE_FAILED;
}
//----------------------------------------------------------------------------
vtkShaderProgram2::~vtkShaderProgram2()
{
this->ReleaseGraphicsResources();
delete[] this->LastLinkLog;
delete[] this->LastValidateLog;
if (this->UniformVariables)
{
this->UniformVariables->Delete();
}
if (this->Shaders)
{
this->Shaders->Delete();
}
}
//----------------------------------------------------------------------------
bool vtkShaderProgram2::IsSupported(vtkRenderWindow *renWin)
{
vtkOpenGLRenderWindow *context
= dynamic_cast<vtkOpenGLRenderWindow*>(renWin);
if (!context) return false;
vtkOpenGLExtensionManager *e = context->GetExtensionManager();
bool multiTexture = e->ExtensionSupported("GL_VERSION_1_3") ||
e->ExtensionSupported("GL_ARB_multitexture");
bool glsl = e->ExtensionSupported("GL_VERSION_2_0") ||
(e->ExtensionSupported("GL_ARB_shading_language_100") &&
e->ExtensionSupported("GL_ARB_shader_objects") &&
e->ExtensionSupported("GL_ARB_vertex_shader") &&
e->ExtensionSupported("GL_ARB_fragment_shader"));
return multiTexture && glsl;
}
//----------------------------------------------------------------------------
bool vtkShaderProgram2::LoadRequiredExtensions(vtkRenderWindow *renWin)
{
vtkOpenGLRenderWindow *context
= dynamic_cast<vtkOpenGLRenderWindow*>(renWin);
this->ExtensionsLoaded = false;
if (!context) return false;
vtkOpenGLExtensionManager *e = context->GetExtensionManager();
bool gl13 = e->ExtensionSupported("GL_VERSION_1_3") == 1;
bool gl20 = e->ExtensionSupported("GL_VERSION_2_0") == 1;
bool multiTexture = gl13 || e->ExtensionSupported("GL_ARB_multitexture");
bool glsl = gl20 || (e->ExtensionSupported("GL_ARB_shading_language_100") &&
e->ExtensionSupported("GL_ARB_shader_objects") &&
e->ExtensionSupported("GL_ARB_vertex_shader") &&
e->ExtensionSupported("GL_ARB_fragment_shader"));
this->ExtensionsLoaded = (multiTexture && glsl);
if (this->ExtensionsLoaded)
{
if (gl13)
{
e->LoadExtension("GL_VERSION_1_3");
}
else
{
e->LoadCorePromotedExtension("GL_ARB_multitexture");
}
if (gl20)
{
e->LoadExtension("GL_VERSION_2_0");
}
else
{
e->LoadCorePromotedExtension("GL_ARB_shading_language_100");
e->LoadCorePromotedExtension("GL_ARB_shader_objects");
e->LoadCorePromotedExtension("GL_ARB_vertex_shader");
e->LoadCorePromotedExtension("GL_ARB_fragment_shader");
}
}
return this->ExtensionsLoaded;
}
// ----------------------------------------------------------------------------
vtkRenderWindow *vtkShaderProgram2::GetContext()
{
return this->Context;
}
// ----------------------------------------------------------------------------
void vtkShaderProgram2::SetContext(vtkRenderWindow *renWin)
{
// avoid pointless reassignment
if (this->Context == renWin)
{
return;
}
// free ressources
this->ReleaseGraphicsResources();
this->Context = NULL;
this->Modified();
// all done if assigned null
if (!renWin)
{
return;
}
// check for support
vtkOpenGLRenderWindow *context
= dynamic_cast<vtkOpenGLRenderWindow*>(renWin);
if ( !context
|| !this->LoadRequiredExtensions(renWin) )
{
vtkErrorMacro("The context does not support the required extensions.");
return;
}
// intialize
this->Context = renWin;
this->Context->MakeCurrent();
}
// ----------------------------------------------------------------------------
// Description:
// Tells if at least one of the shaders is a vertex shader.
// If yes, it means the vertex processing of the fixed-pipeline is bypassed.
// If no, it means the vertex processing of the fixed-pipeline is used.
bool vtkShaderProgram2::HasVertexShaders()
{
return (this->Shaders) ? this->Shaders->HasVertexShaders() : false;
}
// ----------------------------------------------------------------------------
// Description:
// Tells if at least one of the shaders is a tessellation control shader.
bool vtkShaderProgram2::HasTessellationControlShaders()
{
return (this->Shaders) ? this->Shaders->HasTessellationControlShaders() : false;
}
// ----------------------------------------------------------------------------
// Description:
// Tells if at least one of the shaders is a tessellation evaluation shader.
bool vtkShaderProgram2::HasTessellationEvaluationShaders()
{
return (this->Shaders) ? this->Shaders->HasTessellationEvaluationShaders() : false;
}
// ----------------------------------------------------------------------------
// Description:
// Tells if at least one of the shaders is a geometry shader.
bool vtkShaderProgram2::HasGeometryShaders()
{
return (this->Shaders) ? this->Shaders->HasGeometryShaders() : false;
}
// ----------------------------------------------------------------------------
// Description:
// Tells if at least one of the shaders is a fragment shader.
// If yes, it means the fragment processing of the fixed-pipeline is
// bypassed.
// If no, it means the fragment processing of the fixed-pipeline is used.
bool vtkShaderProgram2::HasFragmentShaders()
{
return (this->Shaders) ? this->Shaders->HasFragmentShaders() : false;
}
// ----------------------------------------------------------------------------
// Description:
// Tell if the program is the one currently used by OpenGL.
bool vtkShaderProgram2::IsUsed()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
GLint value;
glGetIntegerv(vtkgl::CURRENT_PROGRAM,&value);
return static_cast<GLuint>(value) == static_cast<GLuint>(this->Id);
}
// ----------------------------------------------------------------------------
// Description:
// Tells if a display list is under construction with GL_COMPILE mode.
// Return false if there is no display list under construction of if the
// mode is GL_COMPILE_AND_EXECUTE.
// Used internally and provided as a public method for whoever find it
// useful.
bool vtkShaderProgram2::DisplayListUnderCreationInCompileMode()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
bool result = false;
GLint value;
glGetIntegerv(GL_LIST_INDEX, &value);
if (value != 0) // some display list is under construction.
{
glGetIntegerv(GL_LIST_MODE, &value);
if (value == GL_COMPILE)
{
result = true;
}
else
{
if (value != GL_COMPILE_AND_EXECUTE)
{
std::ostringstream ost;
ost << "Unexpected display list creation mode:" << hex << value << dec;
vtkErrorMacro(<< ost.str().c_str());
}
}
}
return result;
}
// ----------------------------------------------------------------------------
void vtkShaderProgram2::Use()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
this->Build();
// We need to know if this call happens in a display list or not because
// glGetIntegerv(vtkgl::CURRENT_PROGRAM,&value) is executed immediately
// while vtkgl::UseProgram(id) is just compiled and its execution is
// postpone in GL_COMPILE mode.
if (this->LastBuildStatus == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED)
{
GLuint progId = static_cast<GLuint>(this->Id);
if (this->DisplayListUnderCreationInCompileMode())
{
// don't look at current program, don't save it, don't restore it
// later.
vtkgl::UseProgram(progId);
vtkOpenGLCheckErrorMacro("failed at glUseProgram");
}
else
{
GLint value;
glGetIntegerv(vtkgl::CURRENT_PROGRAM, &value);
if (static_cast<GLuint>(value) != progId)
{
this->SavedId = static_cast<unsigned int>(value);
#ifndef NDEBUG
if (this->SavedId != 0)
{
vtkWarningMacro(<<"another program was used (id=" << this->SavedId
<<"), our id is" << progId << ".");
}
#endif
vtkgl::UseProgram(progId);
vtkOpenGLCheckErrorMacro("failed at glUseProgram");
}
assert("check: in_use" && this->IsUsed());
}
this->SendUniforms();
}
}
// ----------------------------------------------------------------------------
// Description:
// Restore the previous shader program (or fixed-pipeline).
void vtkShaderProgram2::Restore()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
if (this->DisplayListUnderCreationInCompileMode())
{
vtkgl::UseProgram(0);
this->SavedId = 0;
}
else
{
GLint value;
glGetIntegerv(vtkgl::CURRENT_PROGRAM, &value);
if (static_cast<GLuint>(value) != static_cast<GLuint>(this->Id))
{
vtkErrorMacro("Restore failed because the porgram is not in use");
}
vtkgl::UseProgram(static_cast<GLuint>(this->SavedId));
vtkOpenGLCheckErrorMacro("failed at glUseProgram");
this->SavedId = 0;
}
}
// ----------------------------------------------------------------------------
// Description:
// Force the current shader program to be the fixed-pipeline.
// Warning: this call will be compiled if called inside a display list
// creation.
void vtkShaderProgram2::RestoreFixedPipeline()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
vtkgl::UseProgram(0);
this->SavedId = 0;
}
// ----------------------------------------------------------------------------
void vtkShaderProgram2::Build()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
if (this->Id == 0 || this->LastLinkTime<this->MTime ||
(this->Shaders && this->LastLinkTime<this->Shaders->GetMTime()))
{
this->LastBuildStatus=VTK_SHADER_PROGRAM2_COMPILE_FAILED;
GLuint progId = static_cast<GLuint>(this->Id);
if (progId == 0)
{
progId = vtkgl::CreateProgram();
vtkOpenGLCheckErrorMacro("failed at glCreateProgram");
if (progId == 0)
{
vtkErrorMacro("failed to create program");
return;
}
this->Id = static_cast<unsigned int>(progId);
}
// Detach all previous shaders (some may have disappeared
// from this->Shaders)
GLint numberOfAttachedShaders;
vtkgl::GetProgramiv(progId, vtkgl::ATTACHED_SHADERS, &numberOfAttachedShaders);
if (numberOfAttachedShaders > 0)
{
GLuint *attachedShaders = new GLuint[numberOfAttachedShaders];
vtkgl::GetAttachedShaders(progId,numberOfAttachedShaders,0, attachedShaders);
int i = 0;
while(i < numberOfAttachedShaders)
{
vtkgl::DetachShader(progId, attachedShaders[i]);
vtkOpenGLCheckErrorMacro("failed at glDettachShader");
++i;
}
delete[] attachedShaders;
}
// We compile all the shaders, even if one fails so that
// we can get info logs for all shaders.
bool compileDone = true;
this->Shaders->InitTraversal();
vtkShader2 *s = this->Shaders->GetNextShader();
while (s)
{
// Propagate the context to the shader.
s->SetContext(this->Context);
s->Compile();
if (s->GetLastCompileStatus())
{
vtkgl::AttachShader(progId, static_cast<GLuint>(s->GetId()));
vtkOpenGLCheckErrorMacro("failed at glAttachShader");
}
else
{
compileDone = false;
if (this->PrintErrors)
{
vtkErrorMacro(
<<" a shader failed to compile. Its log is:\n"
<< s->GetLastCompileLog() << "\n. Its source code is:\n"
<< s->GetSourceCode());
}
}
s = this->Shaders->GetNextShader();
}
if (compileDone)
{
this->LastBuildStatus = VTK_SHADER_PROGRAM2_LINK_FAILED;
// It is required to pass geometry shader parameters before linking.
if (this->HasGeometryShaders())
{
vtkgl::ProgramParameteriARB(progId, vtkgl::GEOMETRY_INPUT_TYPE_ARB,
static_cast<GLint>(vtkGeometryTypeInVTKToGL[this->GeometryTypeIn]));
vtkgl::ProgramParameteriARB(progId, vtkgl::GEOMETRY_OUTPUT_TYPE_ARB,
static_cast<GLint>(vtkGeometryTypeOutVTKToGL[this->GeometryTypeOut]));
vtkgl::ProgramParameteriARB(progId, vtkgl::GEOMETRY_VERTICES_OUT_ARB,
this->GeometryVerticesOut);
}
vtkgl::LinkProgram(progId);
vtkOpenGLCheckErrorMacro("failed at glLinkProgram");
GLint value;
vtkgl::GetProgramiv(progId, vtkgl::LINK_STATUS ,&value);
if (value == GL_TRUE)
{
this->LastBuildStatus = VTK_SHADER_PROGRAM2_LINK_SUCCEEDED;
}
vtkgl::GetProgramiv(progId, vtkgl::INFO_LOG_LENGTH, &value);
if (static_cast<size_t>(value)>this->LastLinkLogCapacity)
{
delete[] this->LastLinkLog;
this->LastLinkLogCapacity = static_cast<size_t>(value);
this->LastLinkLog = new char[this->LastLinkLogCapacity];
}
vtkgl::GetProgramInfoLog(progId, value, 0, this->LastLinkLog);
if (this->LastBuildStatus == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED)
{
this->LastLinkTime.Modified();
}
else
{
if (this->PrintErrors)
{
vtkErrorMacro(<<" the shader program failed to link. Its log is:\n"
<< this->GetLastLinkLog() << "the shaders are: ");
size_t i = 0;
size_t c = static_cast<size_t>(this->Shaders->GetNumberOfItems());
this->Shaders->InitTraversal();
s = this->Shaders->GetNextShader();
while (s)
{
vtkErrorMacro(<<"shader #" << i << "/" << c <<
" (" <<s->GetTypeAsString()
<<") log is:\n" << s->GetLastCompileLog()
<< "\n. Its source code is:\n" << s->GetSourceCode());
s = this->Shaders->GetNextShader();
++i;
}
}
}
}
}
}
// ----------------------------------------------------------------------------
void vtkShaderProgram2::SendUniforms()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
assert("pre: built" &&
this->GetLastBuildStatus() == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED);
bool needUpdate = this->LastSendUniformsTime<this->LastLinkTime;
if (!needUpdate)
{
needUpdate=this->UniformVariables!=0 &&
this->LastSendUniformsTime<this->UniformVariables->GetMTime();
}
this->Shaders->InitTraversal();
vtkShader2 *s = this->Shaders->GetNextShader();
vtkUniformVariables *list;
while (!needUpdate && s)
{
list = s->GetUniformVariables();
needUpdate = (list!=0 && this->LastSendUniformsTime<list->GetMTime());
s = this->Shaders->GetNextShader();
}
if (needUpdate)
{
bool inListCreation = this->DisplayListUnderCreationInCompileMode();
bool isUsed = false;
if (!inListCreation)
{
isUsed = this->IsUsed();
if (!isUsed)
{
this->Use();
}
}
// NOTE -- a given uniform variable state is held and is set from
// two different places, in the program and in the shader. If not
// used carefully this is both inefficient and error prone!! However
// it's done like that to simplify support for arbitrary collections of
// shaders.
this->Shaders->InitTraversal();
s = this->Shaders->GetNextShader();
while (s)
{
list = s->GetUniformVariables();
list->Start();
while(!list->IsAtEnd())
{
const char *name = list->GetCurrentName();
GLint uniformId = this->GetUniformLocationInternal(name);
vtkOpenGLCheckErrorMacro("failed at glGetUniformLocation");
if (uniformId != -1)
{
// -1 means is not an active uniform
// it does not mean it is an error.
list->SendCurrentUniform(uniformId);
}
list->Next();
}
s = this->Shaders->GetNextShader();
}
// override some of the values of the uniform variables set at the shader
// level with the uniform values set at the program level.
list = this->GetUniformVariables();
list->Start();
while (!list->IsAtEnd())
{
const char *name = list->GetCurrentName();
GLint uniformId = this->GetUniformLocationInternal(name);
if (uniformId != -1)
{
// -1 means is not an active uniform
// it does not mean it is an error.
list->SendCurrentUniform(uniformId);
}
list->Next();
}
if (!inListCreation && !isUsed)
{
this->Restore();
}
}
}
// ----------------------------------------------------------------------------
int vtkShaderProgram2::GetUniformLocationInternal(const char *name)
{
assert(this->Id!=0);
assert(name!=NULL);
int loc = (int)vtkgl::GetUniformLocation((GLuint)this->Id, name);
vtkOpenGLCheckErrorMacro("failed at glGetUniformLocation");
return loc;
}
// ----------------------------------------------------------------------------
int vtkShaderProgram2::GetUniformLocation(const char *name)
{
assert(this->Id!=0);
assert(name!=NULL);
int loc = (int)vtkgl::GetUniformLocation((GLuint)this->Id, name);
vtkOpenGLCheckErrorMacro("failed at glGetUniformLocation");
#ifndef NDEBUG
if (loc==-1)
{ vtkErrorMacro("no variable named " << name); }
#endif
return loc;
}
// ----------------------------------------------------------------------------
#define vtkSetUniformAPIMacro(ctype, num, letter) \
void vtkShaderProgram2::SetUniform##num##letter(int loc, ctype *val) \
{ \
assert(loc!=-1); \
vtkgl::Uniform##num##letter##v(loc, 1, val); \
vtkOpenGLCheckErrorMacro("failed at glUniform" #num #letter "v"); \
}
vtkSetUniformAPIMacro(float, 1, f);
vtkSetUniformAPIMacro(float, 2, f);
vtkSetUniformAPIMacro(float, 3, f);
vtkSetUniformAPIMacro(float, 4, f);
vtkSetUniformAPIMacro(int, 1, i);
vtkSetUniformAPIMacro(int, 2, i);
vtkSetUniformAPIMacro(int, 3, i);
vtkSetUniformAPIMacro(int, 4, i);
// ----------------------------------------------------------------------------
void vtkShaderProgram2::UseProgram()
{
assert(this->Context);
vtkgl::UseProgram((GLuint)this->Id);
vtkOpenGLCheckErrorMacro("failed at glUseProgram");
}
// ----------------------------------------------------------------------------
void vtkShaderProgram2::UnuseProgram()
{
assert(this->Context);
vtkgl::UseProgram((GLuint)0U);
vtkOpenGLCheckErrorMacro("failed at glUseProgram");
}
// ----------------------------------------------------------------------------
// Description:
// Introspection. Return the list of active uniform variables of the program.
void vtkShaderProgram2::PrintActiveUniformVariables(
ostream &os,
vtkIndent indent)
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
assert("pre: built" &&
this->GetLastBuildStatus() == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED);
GLint params;
GLuint progId = static_cast<GLuint>(this->Id);
// info about the list of active uniform variables
vtkgl::GetProgramiv(progId, vtkgl::ACTIVE_UNIFORMS, &params);
os<< indent << "There are " << params << " active uniform variables."<<endl;
GLuint i = 0;
GLuint c = static_cast<GLuint>(params);
vtkgl::GetProgramiv(progId, vtkgl::ACTIVE_UNIFORM_MAX_LENGTH, &params);
GLint buffSize = params;
char *name = new char[buffSize + 1];
GLint size;
GLenum type;
bool isInt;
int elementSize;
bool isSampler;
GLenum textureBinding;
while (i < c)
{
vtkgl::GetActiveUniform(progId, i, buffSize, 0, &size, &type, name);
os << indent << i <<" ";
os << indent;
isInt = true;
isSampler = false;
textureBinding = GL_TEXTURE_BINDING_1D;
elementSize = 1;
switch(type)
{
case GL_FLOAT:
os << "float";
isInt = false;
break;
case vtkgl::FLOAT_VEC2:
os << "vec2";
isInt = false;
elementSize = 2;
break;
case vtkgl::FLOAT_VEC3:
os << "vec3";
isInt = false;
elementSize = 3;
break;
case vtkgl::FLOAT_VEC4:
os << "vec4";
isInt = false;
elementSize = 4;
break;
case GL_INT:
os << "int";
break;
case vtkgl::INT_VEC2:
os << "ivec2";
elementSize = 2;
break;
case vtkgl::INT_VEC3:
os << "ivec3";
elementSize = 3;
break;
case vtkgl::INT_VEC4:
os << "ivec4";
elementSize = 4;
break;
case vtkgl::BOOL:
os << "bool";
break;
case vtkgl::BOOL_VEC2:
os << "bvec2";
elementSize = 2;
break;
case vtkgl::BOOL_VEC3:
os << "bvec3";
elementSize = 3;
break;
case vtkgl::BOOL_VEC4:
os << "bvec4";
elementSize = 4;
break;
case vtkgl::FLOAT_MAT2:
os << "mat2";
isInt = false;
elementSize = 4;
break;
case vtkgl::FLOAT_MAT3:
os << "mat3";
isInt = false;
elementSize = 9;
break;
case vtkgl::FLOAT_MAT4:
os << "mat4";
isInt = false;
elementSize = 16;
break;
case vtkgl::FLOAT_MAT2x3:
os << "mat2x3";
isInt = false;
elementSize = 6;
break;
case vtkgl::FLOAT_MAT2x4:
os << "mat2x4";
isInt = false;
elementSize = 8;
break;
case vtkgl::FLOAT_MAT3x2:
os << "mat3x2";
isInt = false;
elementSize = 6;
break;
case vtkgl::FLOAT_MAT3x4:
os << "mat3x4";
isInt = false;
elementSize = 12;
break;
case vtkgl::FLOAT_MAT4x2:
os << "mat4x2";
isInt = false;
elementSize = 8;
break;
case vtkgl::FLOAT_MAT4x3:
os << "mat4x3";
isInt = false;
elementSize = 12;
break;
case vtkgl::SAMPLER_1D:
os << "sampler1D";
isSampler = true;
textureBinding = GL_TEXTURE_BINDING_1D;
break;
case vtkgl::SAMPLER_2D:
os << "sampler2D";
isSampler = true;
textureBinding = GL_TEXTURE_BINDING_2D;
break;
case vtkgl::SAMPLER_3D:
os << "sampler3D";
isSampler = true;
textureBinding = vtkgl::TEXTURE_BINDING_3D;
break;
case vtkgl::SAMPLER_CUBE:
os<<"samplerCube";
isSampler = true;
textureBinding = vtkgl::TEXTURE_BINDING_CUBE_MAP;
break;
case vtkgl::SAMPLER_1D_SHADOW:
os << "sampler1DShadow";
isSampler = true;
textureBinding = GL_TEXTURE_BINDING_1D;
break;
case vtkgl::SAMPLER_2D_SHADOW:
os << "sampler2DShadow";
isSampler = true;
textureBinding = GL_TEXTURE_BINDING_2D;
break;
case vtkgl::SAMPLER_2D_RECT_ARB:
os << "sampler2DRect";
isSampler = true;
textureBinding = vtkgl::TEXTURE_BINDING_RECTANGLE_ARB;
break;
case vtkgl::SAMPLER_2D_RECT_SHADOW_ARB:
os << "sampler2DRectShadow";
isSampler = true;
textureBinding = vtkgl::TEXTURE_BINDING_RECTANGLE_ARB;
break;
}
os << " " << name;
if (size>1)
{
os << "[" << size << "]";
}
os << "=";
if (size > 1)
{
os << "{";
}
GLint *ivalues = 0;
GLfloat *fvalues = 0;
if (isInt)
{
ivalues = new GLint[elementSize];
}
else
{
fvalues = new GLfloat[elementSize];
}
int element = 0;
while (element<size)
{
std::ostringstream ost2;
ost2 << name;
if (size > 1)
{
ost2<<"["<<element<<"]";
}
vtkStdString arrayElementName;
arrayElementName = ost2.str();
GLint loc = vtkgl::GetUniformLocation(progId,arrayElementName);
if (elementSize > 1)
{
os << "{";
}
if (loc == -1)
{
// this a built-in variable like:
// gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff,
// gl_ProjectionMatrixInverse, ...
// we cannot get the value through vtkgl::GetUniform*()
os << "<built-in value>";
}
else
{
if (isInt)
{
vtkgl::GetUniformiv(progId, loc, ivalues);
int j = 0;
while (j < elementSize)
{
os << ivalues[j];
if (j < (elementSize - 1))
{
os << " ";
}
++j;
}
if (isSampler)
{
os << " (Texture Unit)->";
GLint savedActiveTextureUnit;
glGetIntegerv(vtkgl::ACTIVE_TEXTURE,&savedActiveTextureUnit);
savedActiveTextureUnit = static_cast<GLint>(
static_cast<GLenum>(savedActiveTextureUnit) - vtkgl::TEXTURE0);
if (savedActiveTextureUnit != ivalues[0])
{
vtkgl::ActiveTexture(vtkgl::TEXTURE0 +
static_cast<GLenum>(ivalues[0]));
}
GLint textureObject;
glGetIntegerv(textureBinding, &textureObject);
if (savedActiveTextureUnit != ivalues[0])
{
vtkgl::ActiveTexture(
vtkgl::TEXTURE0 + static_cast<GLenum>(savedActiveTextureUnit));
}
os << textureObject << " (Texture Object)";
}
}
else
{
vtkgl::GetUniformfv(progId, loc, fvalues);
int j = 0;
while(j < elementSize)
{
os << fvalues[j];
if (j < (elementSize - 1))
{
os << " ";
}
++j;
}
}
}
if (elementSize > 1)
{
os << "}";
}
if (element < (size - 1))
{
os << " ";
}
++element;
}
delete[] ivalues;
delete[] fvalues;
if (size > 1)
{
os << "}";
}
os << endl;
++i;
}
delete[] name;
}
//----------------------------------------------------------------------------
// Description:
// Call PrintActiveUniformVariables on cout. Useful for calling inside gdb.
void vtkShaderProgram2::PrintActiveUniformVariablesOnCout()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
assert("pre: built" &&
this->GetLastBuildStatus() == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED);
vtkIndent i;
this->PrintActiveUniformVariables(cout, i);
}
//----------------------------------------------------------------------------
// Description:
// Tell if the shader program is valid with the current OpenGL state.
bool vtkShaderProgram2::IsValid()
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
assert("pre: built" &&
this->GetLastBuildStatus() == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED);
// this line change the program log.
GLuint progId = static_cast<GLuint>(this->Id);
vtkgl::ValidateProgram(progId);
GLint value;
vtkgl::GetProgramiv(progId, vtkgl::VALIDATE_STATUS, &value);
bool result = (value == GL_TRUE);
vtkgl::GetProgramiv(progId, vtkgl::INFO_LOG_LENGTH, &value);
if (static_cast<size_t>(value)>this->LastValidateLogCapacity)
{
delete[] this->LastValidateLog;
this->LastValidateLogCapacity = static_cast<size_t>(value);
this->LastValidateLog = new char[this->LastValidateLogCapacity];
}
vtkgl::GetProgramInfoLog(progId, value, 0, this->LastValidateLog);
return result;
}
//----------------------------------------------------------------------------
// Description:
// Tells if the last build: failed during compilation of one of the
// shader, fails during link of the program or succeeded to link the
// program.
// Initial value is VTK_SHADER_PROGRAM2_COMPILE_FAILED.
// \post valid_value: result== VTK_SHADER_PROGRAM2_COMPILE_FAILED ||
// result==VTK_SHADER_PROGRAM2_LINK_FAILED ||
// result==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED
int vtkShaderProgram2::GetLastBuildStatus()
{
return this->LastBuildStatus;
}
//----------------------------------------------------------------------------
// Description:
// Return the log of the last link as a string.
// Initial value is the empty string ""='\0'.
// \post result_exists: result!=0
const char *vtkShaderProgram2::GetLastLinkLog()
{
assert("post: result_exists" && this->LastLinkLog);
return this->LastLinkLog;
}
//----------------------------------------------------------------------------
// Description:
// Return the log of the last call to IsValid as a string.
// Initial value is the empty string ""='\0'.
// \post result_exists: result!=0
const char *vtkShaderProgram2::GetLastValidateLog()
{
assert("post: result_exists" && this->LastValidateLog);
return this->LastValidateLog;
}
//----------------------------------------------------------------------------
int vtkShaderProgram2::GetAttributeLocation(const char *name)
{
assert("pre: context_is_set" && this->Context);
assert("pre: current_context_matches" && this->Context->IsCurrent());
assert("pre: name_exists" && name);
assert("pre: built" &&
this->LastBuildStatus == VTK_SHADER_PROGRAM2_LINK_SUCCEEDED);
int loc = vtkgl::GetAttribLocation(this->Id, name);
vtkOpenGLCheckErrorMacro("glGetAttribLocation");
return loc;
}
//----------------------------------------------------------------------------
void vtkShaderProgram2::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Context: ";
if (this->Context)
{
os << static_cast<void *>(this->Context) <<endl;
}
else
{
os << "none" << endl;
}
os << indent << "PrintErrors: ";
if (this->PrintErrors)
{
os << "true" << endl;
}
else
{
os << "false" << endl;
}
os << indent << "LastBuildStatus: ";
switch(this->LastBuildStatus)
{
case VTK_SHADER_PROGRAM2_COMPILE_FAILED:
os << "Compile failed";
break;
case VTK_SHADER_PROGRAM2_LINK_FAILED:
os << "Link failed";
break;
case VTK_SHADER_PROGRAM2_LINK_SUCCEEDED:
os << "Link succeeded";
break;
default:
os << "ERROR unknown value!";
break;
}
os << endl;
os << indent << "OpenGL Id: " << this->Id << endl;
os << indent << "GeometryTypeIn: " <<
vtkGeometryTypeInAsStringArray[this->GeometryTypeIn] << endl;
os << indent << "GeometryTypeOut: " <<
vtkGeometryTypeInAsStringArray[this->GeometryTypeOut] << endl;
os << indent << "GeometryVerticesOut: " << this->GeometryVerticesOut << endl;
os << indent << "UniformVariables: ";
if (this->UniformVariables)
{
this->UniformVariables->PrintSelf(os, indent);
}
else
{
os << "none" << endl;
}
os << indent << "Shaders: ";
if (this->Shaders)
{
this->Shaders->PrintSelf(os, indent);
}
else
{
os << "none" << endl;
}
}