I've noticed that my GLSL shaders are not compilable when the GLSL version is lower than 130.
What are the most cr开发者_如何学Goitical elements for having a backward compatible shader source? I don't want to have a full backward compatibility, but I'd like to understand the main guidelines for having simple (forward compatible) shaders running on GPU with GLSL lower than 130.
Of course the problem could be solved with the preprocessor
#if __VERSION__ < 130
#define VERTEX_IN attribute
#else
#define VERTER_IN in
#endif
But there probably many issues that I ignore.
Recent activities has pushed up this old question, and I realized that I resolved the issue. It was not easy, but it is a successful solution, proven by many shaders based on it and the number of drivers that compiles the shader source.
Essentially, I used the GL_ARB_shading_language_include extension (and I've also implemented a source preprocessor for those system that does not implement it), and I ended up to define the following shader include source:
// Copyright (C) 2011-2013 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// @BeginInterface
// Shader renderer
// Symbol defined if running on NVIDIA renderer.
#define DS_VENDOR_NVIDIA 1
// Symbol defined if running on ATI/AMD renderer.
#define DS_VENDOR_AMD 2
// Symbol defined if running on INTEL renderer
#define DS_VENDOR_INTEL 3
// Shader inputs and outputs keywords
//
// - ATTRIBUTE: used to mark a vertex shader inputs
// - SHADER_IN: used to mark a non-vertex shader inputs
// - SHADER_OUT: used to mark a non-fragment shader output
// - OUT: used to mark a fragment shader output
#if __VERSION__ >= 130
#define ATTRIBUTE in
#define SHADER_IN in
#define SHADER_OUT out
#define OUT out
#else
#define ATTRIBUTE attribute
#define SHADER_IN varying
#define SHADER_OUT varying
#define OUT
#endif
// Support array attributes
#if __VERSION__ >= 130
#define ARRAY_ATTRIBUTE(name, size) name[size]
#else
#define ARRAY_ATTRIBUTE(name, size) name[size]
#endif
// Uniform blocks
#if __VERSION__ >= 130
#define BEGIN_UNIFORM_BLOCK(name) uniform name {
#define END_UNIFORM_BLOCK() };
#else
#define BEGIN_UNIFORM_BLOCK(name)
#define END_UNIFORM_BLOCK()
#endif
// Input and output blocks
#if __VERSION__ >= 150
#define BEGIN_INPUT_BLOCK(name) in name {
#define END_INPUT_BLOCK() };
#define BEGIN_OUTPUT_BLOCK(name) out name {
#define END_OUTPUT_BLOCK() };
#else
#define BEGIN_INPUT_BLOCK(name)
#define END_INPUT_BLOCK()
#define BEGIN_OUTPUT_BLOCK(name)
#define END_OUTPUT_BLOCK()
#endif
// Texturing functions
#if __VERSION__ >= 130
#define TEXTURE_2D texture
#define TEXTURE_3D texture
#define TEXTURE_RECT texture
#define TEXTURE_CUBE texture
#if __VERSION__ >= 150
#define TEXTURE_SIZE(sampler) textureSize(sampler)
#else
#define TEXTURE_SIZE(sampler) sampler ## _Size
#endif
#else
#define TEXTURE_2D texture2D
#define TEXTURE_3D texture3D
#define TEXTURE_RECT texture2DRect
#define TEXTURE_CUBE textureCube
#endif
// Invariance
#if __VERSION__ >= 120
#define INVARIANT invariant
#else
#define INVARIANT
#endif
// Attribute location
#if defined(GL_ARB_explicit_attrib_location)
#define LOCATION(loc) layout(location = loc)
#else
#define LOCATION(loc)
#endif
// Geometry shader layout
#if __VERSION__ >= 150
#define GEOMETRY_LAYOUT_IN(from) layout (from) in
#define GEOMETRY_LAYOUT(to, max) layout (to, max_vertices = max) out
#else
#define GEOMETRY_LAYOUT_IN(from)
#define GEOMETRY_LAYOUT(to, max)
#endif
// @EndInterface
Indeed, including the shader include before the shader source the framework can compile on a wide range of compilers. Of course, the framework must detect the actual system capabilities and define the compiler parameters in order to get the things done right (think about a line shader because the the line width > 1.0 deprecation).
Of course, the shader infrastructure can define minimum requirement. Once the shader requires GLSL 1.50 or later core profile, there's no need anymore of the shader include above.
- put #version 110 or #version 120 as the first line of your shaders
- test them into the ShaderAnalyst from ATI
- test your code on a LOT of actual graphic cards from different vendors
Read "OpenGL Shading Language, Bill Licea-Kane, AMD, SIGGRAPH 2009". You are probably need to add the following code to your application in order to support GLSL-140, 130 and 120 versions:
#version 150 compatibility
take out the #version line from your shaders and test your code on many different computers with varying GPU capabilities. You will see that your shader compatibility will increase. The #version directive will sometimes cause a shader to fail even though the GPU in that machine can execute all of the shader code when its not given a version number.
精彩评论