From c5a331010d813e56f332fabd2bef108564f6df84 Mon Sep 17 00:00:00 2001 From: Robert Menzel <menzel@informatik.rwth-aachen.de> Date: Sun, 26 Aug 2012 18:59:01 +0200 Subject: [PATCH] refactored shader type detection, added compute shader detection --- include/ACGL/Base/FileHelpers.hh | 6 ++ .../Controller/ShaderProgramControlFiles.hh | 8 --- include/ACGL/OpenGL/Tools.hh | 32 +++++++++++ src/ACGL/Base/FileHelpers.cc | 14 +++++ .../OpenGL/Controller/ShaderControlFile.cc | 32 ++--------- .../Controller/ShaderProgramControlFiles.cc | 38 +------------ src/ACGL/OpenGL/Tools.cc | 57 ++++++++++++++++++- 7 files changed, 116 insertions(+), 71 deletions(-) diff --git a/include/ACGL/Base/FileHelpers.hh b/include/ACGL/Base/FileHelpers.hh index 91d04c03..0ad994c8 100644 --- a/include/ACGL/Base/FileHelpers.hh +++ b/include/ACGL/Base/FileHelpers.hh @@ -41,6 +41,12 @@ namespace FileHelpers */ bool stringEndsWith( const std::string &theString, const std::string &theEnding ); + /* + * Returns the lowercase fileending if the filename has a '.' in it, otherwise + * an empty string. + */ + std::string getFileEnding( const std::string &_fileName ); + /* * Checks if a string begins with a certain prefix. */ diff --git a/include/ACGL/OpenGL/Controller/ShaderProgramControlFiles.hh b/include/ACGL/OpenGL/Controller/ShaderProgramControlFiles.hh index eb687e75..38cfec3a 100644 --- a/include/ACGL/OpenGL/Controller/ShaderProgramControlFiles.hh +++ b/include/ACGL/OpenGL/Controller/ShaderProgramControlFiles.hh @@ -31,14 +31,6 @@ namespace OpenGL{ class ShaderProgramControlFiles : public Resource::MultiFileController<ShaderProgram> { - struct ShaderEndings - { - const char *ending; - GLenum type; - }; - static const unsigned int sShaderEndingsSize; // size of the array sShaderEndings - static const ShaderEndings sShaderEndings[]; // all supported endings (see .cc file) - // ========================================================================================================= \/ // ============================================================================================ CONSTRUCTORS \/ // ========================================================================================================= \/ diff --git a/include/ACGL/OpenGL/Tools.hh b/include/ACGL/OpenGL/Tools.hh index 9de2a540..aef3e0b5 100644 --- a/include/ACGL/OpenGL/Tools.hh +++ b/include/ACGL/OpenGL/Tools.hh @@ -46,8 +46,40 @@ uint32_t getOpenGLMajorVersionNumber(); // returns the combined version number as 10*major + minor for easy comparing uint32_t getOpenGLVersionNumber(); +// query support for specific shader stages: bool doesSupportGeometryShader(); bool doesSupportTessellationShader(); +bool doesSupportComputeShader(); + + +struct ShaderEndings +{ + const char *ending; + GLenum type; +}; +const ShaderEndings sShaderEndings[ ] = { + {"vsh", GL_VERTEX_SHADER}, + {"vert", GL_VERTEX_SHADER}, + {"tcsh", GL_TESS_CONTROL_SHADER}, + {"tcs", GL_TESS_CONTROL_SHADER}, + {"tesh", GL_TESS_EVALUATION_SHADER}, + {"tes", GL_TESS_EVALUATION_SHADER}, + {"gsh", GL_GEOMETRY_SHADER}, + {"geo", GL_GEOMETRY_SHADER}, + {"fsh", GL_FRAGMENT_SHADER}, + {"frag", GL_FRAGMENT_SHADER}, + {"csh", GL_COMPUTE_SHADER}, + {"cs", GL_COMPUTE_SHADER} +}; + +// returns the GL_TESS_CONTROL_SHADER GL_TESS_EVALUATION_SHADER GL_GEOMETRY_SHADER GL_COMPUTE_SHADER +// GL_VERTEX_SHADER GL_FRAGMENT_SHADER or GL_INVALID_VALUE in case the shadertype was not detected +// if _ignoreUnsupportedShaderTypes is true, types unsupported by the current runtime will return +// an GL_INVALID_ENUM also. +GLenum getShaderTypeByFileEnding( const std::string _fileName, bool _ignoreUnsupportedShaderTypes = true ); + +// looks up the enum and gives a human readable version +const GLubyte* acglShaderTypeString( GLenum _shaderType ); // for every OpenGL error enum this will return a human readable version of it // similar to gluErrorString, but that function is not available on all plattforms diff --git a/src/ACGL/Base/FileHelpers.cc b/src/ACGL/Base/FileHelpers.cc index 7abe3903..4d153a5f 100644 --- a/src/ACGL/Base/FileHelpers.cc +++ b/src/ACGL/Base/FileHelpers.cc @@ -8,6 +8,8 @@ #include <cstdio> // fopen etc. #include <string> +#include <algorithm> // transform +#include <cctype> // tolower #include <vector> #include <sstream> #include <iostream> @@ -59,6 +61,18 @@ namespace FileHelpers return false; } + std::string getFileEnding( const std::string &_fileName ) + { + size_t lastDot = _fileName.rfind('.'); + if (lastDot == std::string::npos) { + return ""; + } + std::string ending = _fileName.substr( lastDot+1, _fileName.size() ); + std::transform(ending.begin(), ending.end(), ending.begin(), ::tolower); + + return ending; + } + /* bool stringBeginsWith( const std::string &theString, const std::string &thePrefix ) { diff --git a/src/ACGL/OpenGL/Controller/ShaderControlFile.cc b/src/ACGL/OpenGL/Controller/ShaderControlFile.cc index 625fcf3f..863d187f 100644 --- a/src/ACGL/OpenGL/Controller/ShaderControlFile.cc +++ b/src/ACGL/OpenGL/Controller/ShaderControlFile.cc @@ -6,6 +6,7 @@ #include <ACGL/OpenGL/Controller/ShaderControlFile.hh> #include <ACGL/Base/StringOperations.hh> +#include <ACGL/OpenGL/Tools.hh> using namespace ACGL::Base; using namespace ACGL::OpenGL; @@ -14,37 +15,14 @@ SharedShader ShaderControlFile::create(void) { updateFileModificationTime(); - if(mType == GL_INVALID_ENUM) + if (mType == GL_INVALID_ENUM) { - std::string filename; - std::string extension; - if(!StringOperations::splitFileExtension(mFilename, filename, extension)) - return SharedShader(); - - if(extension == "vsh") - mType = GL_VERTEX_SHADER; - else if(extension == "fsh") - mType = GL_FRAGMENT_SHADER; -#if (ACGL_OPENGL_VERSION >= 43) - else if(extension == "csh") - mType = GL_COMPUTE_SHADER; -#endif -#if (ACGL_OPENGL_VERSION >= 40) - else if(extension == "tcsh") - mType = GL_TESS_CONTROL_SHADER; - else if(extension == "tesh") - mType = GL_TESS_EVALUATION_SHADER; -#endif -#if (ACGL_OPENGL_VERSION >= 32) - else if(extension == "gsh") - mType = GL_GEOMETRY_SHADER; -#endif - else - return SharedShader(); + mType = ACGL::OpenGL::getShaderTypeByFileEnding( mFilename ); + if (mType == GL_INVALID_ENUM) return SharedShader(); } SharedShader shader(new Shader(mType)); - if(shader->setFromFile(mFullFilePath)) + if (shader->setFromFile(mFullFilePath)) return shader; return SharedShader(); } diff --git a/src/ACGL/OpenGL/Controller/ShaderProgramControlFiles.cc b/src/ACGL/OpenGL/Controller/ShaderProgramControlFiles.cc index 624c3e41..87ae6e07 100644 --- a/src/ACGL/OpenGL/Controller/ShaderProgramControlFiles.cc +++ b/src/ACGL/OpenGL/Controller/ShaderProgramControlFiles.cc @@ -6,6 +6,7 @@ #include <ACGL/OpenGL/Controller/ShaderProgramControlFiles.hh> #include <ACGL/OpenGL/Controller/ShaderControlFile.hh> +#include <ACGL/OpenGL/Tools.hh> #include <ACGL/Resource/FileManager.hh> #include <ACGL/OpenGL/Managers.hh> #include <ACGL/Base/Settings.hh> @@ -17,37 +18,11 @@ using namespace ACGL::Base; using namespace ACGL::OpenGL; -#ifndef ACGL_OPENGL_ES -#if (ACGL_OPENGL_VERSION >= 43) -const unsigned int ShaderProgramControlFiles::sShaderEndingsSize = 9; -#else -const unsigned int ShaderProgramControlFiles::sShaderEndingsSize = 8; -#endif -#else -const unsigned int ShaderProgramControlFiles::sShaderEndingsSize = 4; -#endif - -const ShaderProgramControlFiles::ShaderEndings ShaderProgramControlFiles::sShaderEndings[ ShaderProgramControlFiles::sShaderEndingsSize ] = { -#ifndef ACGL_OPENGL_ES - {"tcsh", GL_TESS_CONTROL_SHADER}, - {"tesh", GL_TESS_EVALUATION_SHADER}, - {"gsh", GL_GEOMETRY_SHADER}, - {"geo", GL_GEOMETRY_SHADER}, -#if (ACGL_OPENGL_VERSION >= 43) - {"csh", GL_COMPUTE_SHADER}, -#endif -#endif - {"vsh", GL_VERTEX_SHADER}, - {"vert", GL_VERTEX_SHADER}, - {"fsh", GL_FRAGMENT_SHADER}, - {"frag", GL_FRAGMENT_SHADER} -}; - ShaderProgramControlFiles& ShaderProgramControlFiles::autoFiles(const std::string &_fileName) { //Utils::debug() << "autoFiles: " << _fileName << std::endl; std::string baseFileName = _fileName + "."; - for (unsigned int ending = 0; ending < sShaderEndingsSize; ++ending) + for (unsigned int ending = 0; ending < sizeof(sShaderEndings) / sizeof(ShaderEndings); ++ending) { std::string fileName = baseFileName + sShaderEndings[ending].ending; if ( FileHelpers::fileExists( mBasePath + fileName ) ) @@ -71,14 +46,7 @@ SharedShaderProgram ShaderProgramControlFiles::create(void) if ( mShaderType[file] == GL_INVALID_VALUE ) { // guess the shader type: - for (unsigned int ending = 0; ending < sShaderEndingsSize; ++ending) - { - if ( FileHelpers::stringEndsWith( mFileNames[file], sShaderEndings[ending].ending ) ) - { - mShaderType[file] = sShaderEndings[ending].type; - continue; - } - } + mShaderType[file] = ACGL::OpenGL::getShaderTypeByFileEnding( mFileNames[file] ); } } diff --git a/src/ACGL/OpenGL/Tools.cc b/src/ACGL/OpenGL/Tools.cc index d7b66b83..bdc82b4f 100644 --- a/src/ACGL/OpenGL/Tools.cc +++ b/src/ACGL/OpenGL/Tools.cc @@ -6,6 +6,7 @@ #include <ACGL/ACGL.hh> #include <ACGL/OpenGL/Tools.hh> +#include <ACGL/Base/FileHelpers.hh> namespace ACGL{ namespace OpenGL{ @@ -14,7 +15,7 @@ namespace OpenGL{ // This is a "private" function that should not be called from outside of this file. // // glGetIntegerv(GL_MAJOR_VERSION... and glGetIntegerv(GL_MINOR_VERSION... are great, but -// require OpenGL 3.0 and are not supported on ES :-( so the VERSION string has to get parsed... +// require OpenGL 3.0 and are not supported on ES 2 :-( so the VERSION string has to get parsed... // // OpenGL spec: // The VERSION ... strings are laid out as follows: @@ -104,6 +105,60 @@ bool doesSupportTessellationShader() #endif } +bool doesSupportComputeShader() +{ +#ifdef ACGL_OPENGL_ES + return false; +#else +# if defined(ACGL_USE_GLEW) + return ( GLEW_ARB_compute_shader || (getOpenGLVersionNumber() >= 43)); +# else + return (getOpenGLVersionNumber() >= 43); +# endif +#endif +} + + +GLenum getShaderTypeByFileEnding( const std::string _fileName, bool _ignoreUnsupportedShaderTypes ) +{ + std::string fileEnding = ACGL::Base::FileHelpers::getFileEnding( _fileName ); + if( fileEnding.size() == 0 ) return GL_INVALID_ENUM; + + GLenum foundType = GL_INVALID_ENUM; + + // guess the shader type: + for (unsigned int ending = 0; ending < sizeof(sShaderEndings) / sizeof(ShaderEndings); ++ending) + { + if ( fileEnding == sShaderEndings[ending].ending ) + { + foundType = sShaderEndings[ending].type; + break; + } + } + + if (_ignoreUnsupportedShaderTypes) { + if (foundType == GL_GEOMETRY_SHADER && !doesSupportGeometryShader() ) return GL_INVALID_ENUM; + if (foundType == GL_TESS_CONTROL_SHADER && !doesSupportTessellationShader()) return GL_INVALID_ENUM; + if (foundType == GL_TESS_EVALUATION_SHADER && !doesSupportTessellationShader()) return GL_INVALID_ENUM; + if (foundType == GL_COMPUTE_SHADER && !doesSupportComputeShader() ) return GL_INVALID_ENUM; + } + + return foundType; +} + +const GLubyte* acglShaderTypeString( GLenum _shaderType ) +{ + if (_shaderType == GL_VERTEX_SHADER) { return (GLubyte*) "vertex shader"; } + else if (_shaderType == GL_TESS_CONTROL_SHADER) { return (GLubyte*) "tessellation control shader"; } + else if (_shaderType == GL_TESS_EVALUATION_SHADER) { return (GLubyte*) "tessellation evaluation shader"; } + else if (_shaderType == GL_GEOMETRY_SHADER) { return (GLubyte*) "geometry shader"; } + else if (_shaderType == GL_FRAGMENT_SHADER) { return (GLubyte*) "fragment shader"; } + else if (_shaderType == GL_COMPUTE_SHADER) { return (GLubyte*) "compute shader"; } + else { + return (GLubyte*) "unknown shader type"; + } +} + const GLubyte* acglErrorString( GLenum _errorCode ) { // no gluErrorString on iOS, problems on visual studio... -- GitLab