/*========================================================================= Program: Visualization Toolkit Module: vtkShaderProgram2.h 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. =========================================================================*/ /** * @class vtkShaderProgram2 * @brief GLSL Program * * vtkShaderProgram2 represents an implementation of the programmable OpenGL * pipeline. It consists of a list of vtkShader2 object. Each vtkShader2 is a * piece of source code associated with one of the shader units (vertex, * fragment, geometry). */ #ifndef vtkShaderProgram2_h #define vtkShaderProgram2_h #include // for templated functions #include "vtkRenderingOpenGLModule.h" // for export macro #include "vtkWeakPointer.h" // for weak ptr to rendering context #include "vtkObject.h" class vtkRenderWindow; class vtkOpenGLExtensionManager; class vtkShader2Collection; class vtkUniformVariables; // Values for GetLastBuildStatus() enum vtkShaderProgram2BuildStatus { // one of the shaders failed to compile VTK_SHADER_PROGRAM2_COMPILE_FAILED=0, // all the shaders compiled successfully but the link failed VTK_SHADER_PROGRAM2_LINK_FAILED=1, // all the shaders compiled successfully and the link succeeded VTK_SHADER_PROGRAM2_LINK_SUCCEEDED=2 }; enum vtkShaderProgram2GeometryInType { VTK_GEOMETRY_SHADER_IN_TYPE_POINTS, VTK_GEOMETRY_SHADER_IN_TYPE_LINES, VTK_GEOMETRY_SHADER_IN_TYPE_LINES_ADJACENCY, VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES, VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES_ADJACENCY }; enum vtkShaderProgram2GeometryOutType { VTK_GEOMETRY_SHADER_OUT_TYPE_POINTS, VTK_GEOMETRY_SHADER_OUT_TYPE_LINE_STRIP, VTK_GEOMETRY_SHADER_OUT_TYPE_TRIANGLE_STRIP }; class VTKRENDERINGOPENGL_EXPORT vtkShaderProgram2 : public vtkObject { public: static vtkShaderProgram2* New(); vtkTypeMacro(vtkShaderProgram2, vtkObject); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Returns if the context supports the required extensions. * Extensions are loaded when the context is set. */ static bool IsSupported(vtkRenderWindow *context); //@{ /** * Tell if vtkErrorMacro should be called when there is a build error or not. * It is useful to switch it to false when building a shader is * a way to test if some OpenGL implementation support it or not. * Initial value is true. * Build errors are always reported in the status flags and log whatever is * the value of PrintErrors flag. */ vtkGetMacro(PrintErrors,bool); vtkSetMacro(PrintErrors,bool); //@} //@{ /** * Get/Set the context. This does not increase the reference count of the * context to avoid reference loops. * SetContext() may raise an error is the OpenGL context does not support the * required OpenGL extensions. */ void SetContext(vtkRenderWindow *context); vtkRenderWindow *GetContext(); //@} //@{ /** * The list of shaders. Initially, the list is empty. * \post result_exists: result!=0 */ vtkGetObjectMacro(Shaders,vtkShader2Collection); //@} /** * 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 HasVertexShaders(); /** * Tells if at least one of the shaders is a tessellation control shader. */ bool HasTessellationControlShaders(); /** * Tells if at least one of the shaders is a tessellation evaluation shader. */ bool HasTessellationEvaluationShaders(); /** * Tells if at least one of the shaders is a geometry shader. */ bool HasGeometryShaders(); /** * 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 HasFragmentShaders(); /** * Tell if the shader program is valid with the current OpenGL state. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->Context()->IsCurrent() * \pre built this->GetLastBuildStatus()==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED */ bool IsValid(); /** * If not done yet, compile all the shaders and link the program. * The status of the build can then be query with GetLastBuildStatus() * and GetLastLinkLog(). * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ void Build(); /** * Send the uniform variables values to the program. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() * \pre built this->GetLastBuildStatus()==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED */ void SendUniforms(); /** * Introspection. Return the list of active uniform variables of the program. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->Context()->IsCurrent() * \pre built this->GetLastBuildStatus()==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED */ void PrintActiveUniformVariables(ostream &os, vtkIndent indent); /** * Call PrintActiveUniformVariables on cout. Useful for calling inside gdb. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->Context()->IsCurrent() * \pre built this->GetLastBuildStatus()==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED */ void PrintActiveUniformVariablesOnCout(); /** * Tell if the program is the one currently used by OpenGL. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ bool IsUsed(); /** * Use the shader program. * It saves the current shader program or fixed-pipeline in use. * As a side affect it also set the uniform variables. If you don't * want that then see UseProgram. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ void Use(); /** * Restore the previous shader program (or fixed-pipeline). * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ void Restore(); /** * Force the current shader program to be the fixed-pipeline. * Warning: this call will be compiled if called inside a display list * creation. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ void RestoreFixedPipeline(); //@{ /** * Simple direct use of the program without side affects and with * error check. The Unuse version restores the default program. */ void UseProgram(); void UnuseProgram(); //@} /** * 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 GetLastBuildStatus(); /** * Return the log of the last link as a string. * Initial value is the empty string ""='\0'. * \post result_exists: result!=0 */ const char *GetLastLinkLog(); /** * 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 *GetLastValidateLog(); /** * Release OpenGL resource (program id and sub-resources). */ virtual void ReleaseGraphicsResources(); /** * Returns the generic attribute location. * The shader must be bound before calling this. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() * \pre name_exists: name!=0 * \pre built: this->GetLastBuildStatus()==VTK_SHADER_PROGRAM2_LINK_SUCCEEDED */ int GetAttributeLocation(const char *name); //@{ /** * Get/Set the list of uniform variables values. * Initial value is an empty list (not null pointer). */ vtkGetObjectMacro(UniformVariables,vtkUniformVariables); virtual void SetUniformVariables(vtkUniformVariables *variables); //@} /** * 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. * \pre context_is_set: this->GetContext()!=0 * \pre current_context_matches: this->GetContext()->IsCurrent() */ bool DisplayListUnderCreationInCompileMode(); //@{ /** * Specific to the geometry shader part of the program. * Relevant only when HasGeometryShaders() is true. * From OpenGL 3.2, it is replaced by an input layout qualifier in GLSL * 1.50. * The input primitive type on which the geometry shader operate. * It can be VTK_GEOMETRY_SHADER_IN_TYPE_POINTS, * VTK_GEOMETRY_SHADER_IN_TYPE_LINES, * VTK_GEOMETRY_SHADER_IN_TYPE_LINES_ADJACENCY, * VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES or * VTK_GEOMETRY_SHADER_IN_TYPE_TRIANGLES_ADJACENCY * Initial value is VTK_GEOMETRY_SHADER_IN_TYPE_POINTS. */ vtkSetMacro(GeometryTypeIn,int); vtkGetMacro(GeometryTypeIn,int); //@} //@{ /** * Specific to the geometry shader part of the program. * Relevant only when HasGeometryShaders() is true. * This is a pre OpenGL 3.2 geometry shader setting. * From OpenGL 3.2, it is replaced by an output layout qualifier in GLSL * 1.50. * The maximum number of vertices the geometry shader will emit in one * invocation. * If a geometry shader, in one invocation, emits more vertices than this * value, these emits may have no effect. * Initial value is 1. */ vtkSetMacro(GeometryVerticesOut,int); vtkGetMacro(GeometryVerticesOut,int); //@} //@{ /** * Specific to the geometry shader part of the program. * Relevant only when HasGeometryShaders() is true. * From OpenGL 3.2, it is replaced by an output layout qualifier in GLSL * 1.50. * The output primitive type generated by the geometry shader. * It can be VTK_GEOMETRY_SHADER_OUT_TYPE_POINTS, * VTK_GEOMETRY_SHADER_OUT_TYPE_LINE_STRIP or * VTK_GEOMETRY_SHADER_OUT_TYPE_TRIANGLE_STRIP. * Initial value is VTK_GEOMETRY_SHADER_OUT_TYPE_POINTS. */ vtkSetMacro(GeometryTypeOut,int); vtkGetMacro(GeometryTypeOut,int); //@} /* Low level api -- this is provided as a way to avoid some of the overhead in this class's implementation of SendUniforms. One should use the following API if performance is a concern (eg. uniforms are set per primitive), or if the uniform management is not needed (eg. variables are already managed in other vtkObjects) */ /** * Get a uniform's location. * Low level API */ int GetUniformLocation(const char *name); /** * Set a uniform value directly. The driving use case for this api * is modifying a uniform per-primitive in a loop. In that case * we need the minimal implementtion passing the value directly to * the driver. It is an error to specify an invalid location. * Low level API */ void SetUniformf(const char *name, float val) { this->SetUniform1f(name, &val); } void SetUniform1f(const char *name, float *val) { this->SetUniform1f(this->GetUniformLocation(name), val); } void SetUniform2f(const char *name, float *val) { this->SetUniform2f(this->GetUniformLocation(name), val); } void SetUniform3f(const char *name, float *val) { this->SetUniform3f(this->GetUniformLocation(name), val); } void SetUniform4f(const char *name, float *val) { this->SetUniform4f(this->GetUniformLocation(name), val); } void SetUniformi(const char *name, int val) { this->SetUniform1i(name, &val); } void SetUniform1i(const char *name, int *val) { this->SetUniform1i(this->GetUniformLocation(name), val); } void SetUniform2i(const char *name, int *val) { this->SetUniform2i(this->GetUniformLocation(name), val); } void SetUniform3i(const char *name, int *val) { this->SetUniform3i(this->GetUniformLocation(name), val); } void SetUniform4i(const char *name, int *val) { this->SetUniform4i(this->GetUniformLocation(name), val); } void SetUniformf(int loc, float val) { this->SetUniform1f(loc, &val); } void SetUniform1f(int loc, float *val); void SetUniform2f(int loc, float *val); void SetUniform3f(int loc, float *val); void SetUniform4f(int loc, float *val); void SetUniformi(int loc, int val) { this->SetUniform1i(loc, &val); } void SetUniform1i(int loc, int *val); void SetUniform2i(int loc, int *val); void SetUniform3i(int loc, int *val); void SetUniform4i(int loc, int *val); //@{ /** * Convenience methods for copy/convert to supported type. Typically * this arises because VTK stores data in an internal format (eg double) * that's not supported. */ template void SetUniform1it(const char *name, T *value); template void SetUniform2it(const char *name, T *value); template void SetUniform3it(const char *name, T *value); template void SetUniform4it(const char *name, T *value); //@} template void SetUniform1ft(const char *name, T *value); template void SetUniform2ft(const char *name, T *value); template void SetUniform3ft(const char *name, T *value); template void SetUniform4ft(const char *name, T *value); template void SetUniform1it(int loc, T *value); template void SetUniform2it(int loc, T *value); template void SetUniform3it(int loc, T *value); template void SetUniform4it(int loc, T *value); template void SetUniform1ft(int loc, T *value); template void SetUniform2ft(int loc, T *value); template void SetUniform3ft(int loc, T *value); template void SetUniform4ft(int loc, T *value); protected: vtkShaderProgram2(); ~vtkShaderProgram2() override; /** * Load the required OpenGL extensions. */ bool LoadRequiredExtensions(vtkRenderWindow *context); /** * Get the location of a uniform, without * caring if it really exists. This is used * because this class will attempt to set *all* * uniforms knows about via the associated * vtkUniformVariables on *all* shaders it manages * regardless of if a given uniform actually * belongs to a given shader. */ int GetUniformLocationInternal(const char *name); unsigned int Id; // actually GLuint. Initial value is 0. unsigned int SavedId; vtkTimeStamp LastLinkTime; vtkTimeStamp LastSendUniformsTime; vtkShader2Collection *Shaders; vtkUniformVariables *UniformVariables; int LastBuildStatus; // Initial value is VTK_SHADER_PROGRAM2_COMPILE_FAILED char *LastLinkLog; // Initial value is the empty string ""='\0' size_t LastLinkLogCapacity; // Initial value is 8. char *LastValidateLog; // Initial value is the empty string ""='\0' size_t LastValidateLogCapacity; // Initial value is 8. bool PrintErrors; vtkWeakPointer Context; bool ExtensionsLoaded; int GeometryTypeIn; int GeometryTypeOut; int GeometryVerticesOut; private: vtkShaderProgram2(const vtkShaderProgram2&) = delete; void operator=(const vtkShaderProgram2&) = delete; }; // ---------------------------------------------------------------------------- #define vtkShaderProgram2SetUniformCopyCastMacro(toLetter, toType, num) \ template \ void vtkShaderProgram2::SetUniform##num##toLetter##t(const char *name, fromType *fvalues) \ { \ toType tvalues[num]; \ for (int i=0; i(fvalues[i]); \ } \ this->SetUniform##num##toLetter(name, tvalues); \ } \ template \ void vtkShaderProgram2::SetUniform##num##toLetter##t(int location, fromType *fvalues) \ { \ assert(location!=-1); \ toType tvalues[num]; \ for (int i=0; i(fvalues[i]); \ } \ this->SetUniform##num##toLetter(location, tvalues); \ } vtkShaderProgram2SetUniformCopyCastMacro(f, float, 1) vtkShaderProgram2SetUniformCopyCastMacro(f, float, 2) vtkShaderProgram2SetUniformCopyCastMacro(f, float, 3) vtkShaderProgram2SetUniformCopyCastMacro(f, float, 4) vtkShaderProgram2SetUniformCopyCastMacro(i, int, 1) vtkShaderProgram2SetUniformCopyCastMacro(i, int, 2) vtkShaderProgram2SetUniformCopyCastMacro(i, int, 3) vtkShaderProgram2SetUniformCopyCastMacro(i, int, 4) #endif