/*========================================================================= 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 #include #include #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(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(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 resources this->ReleaseGraphicsResources(); this->Context = NULL; this->Modified(); // all done if assigned null if (!renWin) { return; } // check for support vtkOpenGLRenderWindow *context = dynamic_cast(renWin); if ( !context || !this->LoadRequiredExtensions(renWin) ) { vtkErrorMacro("The context does not support the required extensions."); return; } // initialize 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(value) == static_cast(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(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(value) != progId) { this->SavedId = static_cast(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(value) != static_cast(this->Id)) { vtkErrorMacro("Restore failed because the porgram is not in use"); } vtkgl::UseProgram(static_cast(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->LastLinkTimeMTime || (this->Shaders && this->LastLinkTimeShaders->GetMTime())) { this->LastBuildStatus=VTK_SHADER_PROGRAM2_COMPILE_FAILED; GLuint progId = static_cast(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(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(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(vtkGeometryTypeInVTKToGL[this->GeometryTypeIn])); vtkgl::ProgramParameteriARB(progId, vtkgl::GEOMETRY_OUTPUT_TYPE_ARB, static_cast(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(value)>this->LastLinkLogCapacity) { delete[] this->LastLinkLog; this->LastLinkLogCapacity = static_cast(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(this->Shaders->GetNumberOfItems()); this->Shaders->InitTraversal(); s = this->Shaders->GetNextShader(); while (s) { vtkErrorMacro(<<"shader #" << i << "/" << c << " (" <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->LastSendUniformsTimeLastLinkTime; if (!needUpdate) { needUpdate=this->UniformVariables!=0 && this->LastSendUniformsTimeUniformVariables->GetMTime(); } this->Shaders->InitTraversal(); vtkShader2 *s = this->Shaders->GetNextShader(); vtkUniformVariables *list; while (!needUpdate && s) { list = s->GetUniformVariables(); needUpdate = (list!=0 && this->LastSendUniformsTimeGetMTime()); 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(this->Id); // info about the list of active uniform variables vtkgl::GetProgramiv(progId, vtkgl::ACTIVE_UNIFORMS, ¶ms); os<< indent << "There are " << params << " active uniform variables."<(params); vtkgl::GetProgramiv(progId, vtkgl::ACTIVE_UNIFORM_MAX_LENGTH, ¶ms); 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 1) { ost2<<"["< 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 << ""; } 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( static_cast(savedActiveTextureUnit) - vtkgl::TEXTURE0); if (savedActiveTextureUnit != ivalues[0]) { vtkgl::ActiveTexture(vtkgl::TEXTURE0 + static_cast(ivalues[0])); } GLint textureObject; glGetIntegerv(textureBinding, &textureObject); if (savedActiveTextureUnit != ivalues[0]) { vtkgl::ActiveTexture( vtkgl::TEXTURE0 + static_cast(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(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(value)>this->LastValidateLogCapacity) { delete[] this->LastValidateLog; this->LastValidateLogCapacity = static_cast(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(this->Context) <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; } }