I have the following uniform buffer:
layout(std140) uniform Light
{
vec4 AmbientLight;
vec4 LightIntensity;
vec3 LightPosition;
float LightAttenuation;
};
I have some issues when buffering the data and the padding I need to add. I have read the http://ptgmedia.pearsoncmg.com/images/9780321552624/downloads/0321552628_AppL.pdf which says I have to add an extra 4 bytes at the end of the vec3 for padding - so I will upload a total of 13 bytes for 'Light'. When I do that however, 'LightAttenuation' gets the value I padded on 'LightPosition', rather than one byte ahead, so I get the correct values in the shader when I do NOT pad. Why is this?
See section 7.6.2.2 of the OpenGL spec for the details, but basically, std140 layout says that each variable will be laid out immediately after the previous variable with enough padding added for the alignment required for the variable's type. vec3 and vec4 both require 16-byte alignment and are 12 and 16 bytes respectively. float requires 4 byte alignment and has 4 byte size. So with std140 layout, LightPosition will get 16 byte alignment so will always end at an address that is 12 mod 16. Since this is 4-byte aligned, no extra padding will be inserted before LightAttenuation.
Usually yes, openGL will treat a vec3 as an vec4. But AFAIK in this case it appends the float LightAttenuation to the vec3 LightPosition - forming an overall vec4 (its some kind of optimization, done by the glsl compiler).
The whole structure will be of size 3x vec4.
Try out using a vec3 or vec4 for LightAttenuation.
Related
I am experiencing the following error in GLSL. Here is the fragment shader:
#version 450 core
#define DIFFUSE_TEX_UNIT 0
#define INDEX_UNIFORM_LOC 0
layout(binding = DIFFUSE_TEX_UNIT) uniform sampler2D colorTex;
#ifdef SOME_SPECIAL_CASE
layout (location = INDEX_UNIFORM_LOC) uniform uint u_blendMode;
//...more code here related to the case
#endif
//... rest of the code(not important)
Now,when I compile this shader into program without declaring SOME_SPECIAL_CASE,and still set u_blendMode uniform during runtime,I am getting the following error from driver:
GL_INVALID_OPERATION error generated. value is
invalid; expected GL_INT or GL_UNSIGNED_INT64_NV.
But I would expect to get an error like this:
GL_INVALID_OPERATION error generated. ' location ' is invalid.
Because there is no location with such an index (0) if I don't set SOME_SPECIAL_CASE preprocessor flag. Then I decided to check what uniform I have got, which requires GL_INT or GL_UNSIGNED_INT64_NV,so I queried uniform name based on its location (zero):
char buff[20];
GLsizei len = 0;
glGetActiveUniformName(prog.progHandle, 0, 20, &len, buff);
And got the name 'colorTex',which is the name of sampler2D uniform that has binding index DIFFUSE_TEX_UNIT ,that is also zero.
Untill now,I believed uniform location and binding points do not use same indices and I still believe they don't,because otherwise this shader,when compiled with SOME_SPECIAL_CASE active would fail,as well as many other shaders I have written thru my work history.Hence it looks utterly weird why that sampler2D uniform binding index is affected when I am setting non-existing uniform location,and I also use specific type (GLSL - uint)
glProgramUniform1ui(prog, location, (GLuint)value);
Which also doesn't match the type of sampler2D (so the error is kinda right at least about type mismatch).
Is it a driver bug?
One more thing,I tried to check in docs if binding and location indices really overlap and found this statement:
It is illegal to assign the same uniform location to two uniforms in
the same shader or the same program. Even if those two uniforms have
the same name and type, and are defined in different shader stages, it
is not legal to explicitly assign them the same uniform location; a
linker error will occur.
This is just absolutely wrong! I have been doing this for years. And tried that again after reading those lines. Having same uniform,with same location in both vertex and fragment shader compiles and works fine.
My setup:
NVIDIA Quadro P2000, driver 419.17
OpenGL 4.5
Windows 10 64bit
Regarding the ability to use same uniform on same location,at least on NVIDIA GPU the following compiles and runs fine:
Vertex shader
#version 450 core
#define MVP_UNIFORM_LOC 2
layout(location = 0) in vec2 v_Position;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth out vec2 texCoord;
void main()
{
texCoord = v_Position;
gl_Position = u_MVP * vec4(v_Position,0.0,1.0);
}
Fragment shader:
#version 450 core
#define MVP_UNIFORM_LOC 2
#define TEX_MAP_UNIT 5
layout(binding = TEX_MAP_UNIT ) uniform sampler2D texMap;
layout(location = MVP_UNIFORM_LOC) uniform mat4 u_MVP;
smooth in vec2 texCoord;
out vec4 OUTPUT;
void main()
{
vec4 tex = texture(texMap, texCoord);
OUTPUT = u_MVP * tex;
}
Is it a driver bug?
No. glGetActiveUniformName takes uniform indices, not uniform locations. Indices cannot be set from the shader; they're just all of the uniform variables, from 0 to the number of active uniforms. Indices are only used for introspecting properties of uniforms.
There's no way to take a uniform location and ask for the uniform index (or name) of the uniform variable.
But I would expect to get an error like this:
...
Because there is no location with such an index (0) if I don't set SOME_SPECIAL_CASE preprocessor flag.
Sure there is. Uniform variables which do not use explicit locations will never have the same location as a uniform variable that does have an explicit location. However, that's not what's happening here.
If SOME_SPECIAL_CASE is not defined, then the declaration of u_blendMode does not exist. Since location 0 was never used by an explicit uniform variable, it is now available for implicit location assignment.
So the implementation can assign the location of colorTex to zero (note that this is different from assigning the binding to zero).
If you want to reserve location 0 always, then the declaration of u_blendMode must always be visible, even if you never use it. The specification allows implementations to still optimize away such declarations, but the explicit location itself is not optimized away. So if you use location = 0 for a uniform that goes unused, then location 0 may or may not be a valid location. But if it is valid, it will always refer to u_blendMode.
Regarding the ability to use same uniform on same location,at least on NVIDIA GPU the following compiles and runs fine:
The GLSL specification has worked this out, and it is now OK to have two explicit uniform locations that are the same, so long as the two declarations are themselves identical. So cross-shader-stage uniform locations are supposed to work.
My GLSL fragment shader skips the "if" statement. The shader itself is very short.
I send some data via a uniform buffer object and use it further in the shader. However, the thing skips the assignment attached to the "if" statement for whatever reason.
I checked the values of the buffer object using glGetBufferSubData (tested with specific non zero values). Everything is where it needs to be. So I'm really kinda lost here. Must be some GLSL weirdness I'm not aware of.
Currently the
#version 420
layout(std140, binding = 2) uniform textureVarBuffer
{
vec3 colorArray; // 16 bytes
int textureEnable; // 20 bytes
int normalMapEnable; // 24 bytes
int reflectionMapEnable; // 28 bytes
};
out vec4 frag_colour;
void main() {
frag_colour = vec4(1.0, 1.0, 1.0, 0.5);
if (textureEnable == 0) {
frag_colour = vec4(colorArray, 0.5);
}
}
You are confusing the base alignment rules with the offsets. The spec states:
The base offset of the first
member of a structure is taken from the aligned offset of the structure itself. The
base offset of all other structure members is derived by taking the offset of the
last basic machine unit consumed by the previous member and adding one. Each
structure member is stored in memory at its aligned offset. The members of a toplevel
uniform block are laid out in buffer storage by treating the uniform block as
a structure with a base offset of zero.
It is true that a vec3 requires a base alignment of 16 bytes, but it only consumes 12 bytes. As a result, the next element after the vec3 will begin 12 bytes after the aligned offset of the vec3 itself. Since the alignment rules for int are just 4 bytes, there will be no padding at all.
I suppose this is a kind-of cross between a pure C++ question and an OpenGL question. I have a uniform buffer and am allocating space in it of sizeof(ShaderData) bytes. I'm using std140 layout on the GPU side in the shader.
According to std140 rules, I need to add padding in various places in my structure to make sure things like vectors are aligned correctly. The structure below is an example (for my light):
struct ShaderData {
float Light_Intensity;
float _pad1[3]; // align following vec3 on 4N boundary
Math::Vec3f Light_Position;
float _pad2; // align following vec4 on 4N boundary
Math::Colour4f Light_Ambient;
Math::Colour4f Light_Diffuse;
Math::Colour4f Light_Specular;
float Light_AttenuationMin;
float Light_AttenuationMax;
} MyShaderData;
Is this the way people generally do things in C++, or are there special keywords or pragmas for aligning individual elements of a structure CPU side that are a little tidier?
No, in this way you just waste space. You have to find the optimized layout according to std140 rules.
a float needs 4 bytes and it's 4 bytes aligned
a vec3 needs 12 bytes and it's 16 bytes aligned
a vec4 needs 16 bytes and it's 16 bytes aligned
This means that you can find a better layout for your struct:
float Light_Intensity; X
float _pad1[3]; XXX
Math::Vec3f Light_Position; XXX
float _pad2; X
As you can see you are wasting 4 bytes and what's worse is the fact that you can just do something like:
Math::Vec3f Light_Position XXX
float Light_Intensity; X
To have it aligned and without the need to waste a byte. This works because vec3 will be aligned to 16 bytes boundaries while the float will be still aligned to 4 bytes boundaries.
My vertex shader is ,
uniform Block1{ vec4 offset_x1; vec4 offset_x2;}block1;
out float value;
in vec4 position;
void main()
{
value = block1.offset_x1.x + block1.offset_x2.x;
gl_Position = position;
}
The code I am using to pass values is :
GLfloat color_values[8];// contains valid values
glGenBuffers(1,&buffer_object);
glBindBuffer(GL_UNIFORM_BUFFER,buffer_object);
glBufferData(GL_UNIFORM_BUFFER,sizeof(color_values),color_values,GL_STATIC_DRAW);
glUniformBlockBinding(psId,blockIndex,0);
glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,0,16);
glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,16,16);
Here what I am expecting is, to pass 16 bytes for each vec4 uniform. I get GL_INVALID_VALUE error for offset=16 , size = 16.
I am confused with offset value. Spec says it is corresponding to "buffer_object".
There is an alignment restriction for UBOs when binding. Any glBindBufferRange/Base's offset must be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. This alignment could be anything, so you have to query it before building your array of uniform buffers. That means you can't do it directly in compile-time C++ logic; it has to be runtime logic.
Speaking of querying things at runtime, your code is horribly broken in many other ways. You did not define a layout qualifier for your uniform block; therefore, the default is used: shared. And you cannot use `shared* layout without querying the layout of each block's members from OpenGL. Ever.
If you had done a query, you would have quickly discovered that your uniform block is at least 32 bytes in size, not 16. And since you only provided 16 bytes in your range, undefined behavior (which includes the possibility of program termination) results.
If you want to be able to define C/C++ objects that map exactly to the uniform block definition, you need to use std140 layout and follow the rules of std140's layout in your C/C++ object.
So we have in C:
auto if break int case long char register
continue return default short do sizeof
double static else struct entry switch extern
typedef float union for unsigned
goto while enum void const signed volatile
What new keywords OpenGL (ES) Shader Language provide to us?
I am new to GLSL and I want to create some highlight editing util for ease of use.
Math words included into GLSL will count as keywords..?
New ones (excluding the ones you listed above) according to the latest spec document:
attribute uniform varying
layout
centroid flat smooth noperspective
patch sample
subroutine
in out inout
invariant
discard
mat2 mat3 mat4 dmat2 dmat3 dmat4
mat2x2 mat2x3 mat2x4 dmat2x2 dmat2x3 dmat2x4
mat3x2 mat3x3 mat3x4 dmat3x2 dmat3x3 dmat3x4
mat4x2 mat4x3 mat4x4 dmat4x2 dmat4x3 dmat4x4
vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 dvec2 dvec3 dvec4
uvec2 uvec3 uvec4
lowp mediump highp precision
sampler1D sampler2D sampler3D samplerCube
sampler1DShadow sampler2DShadow samplerCubeShadow
sampler1DArray sampler2DArray
sampler1DArrayShadow sampler2DArrayShadow
isampler1D isampler2D isampler3D isamplerCube
isampler1DArray isampler2DArray
usampler1D usampler2D usampler3D usamplerCube
usampler1DArray usampler2DArray
sampler2DRect sampler2DRectShadow isampler2DRect usampler2DRect
samplerBuffer isamplerBuffer usamplerBuffer
sampler2DMS isampler2DMS usampler2DMS
sampler2DMSArray isampler2DMSArray usampler2DMSArray
samplerCubeArray samplerCubeArrayShadow isamplerCubeArray usamplerCubeArray
Reserved for future use (will cause error at the moment):
common partition active
asm
class union enum typedef template this packed
goto
inline noinline volatile public static extern external interface
long short half fixed unsigned superp
input output
hvec2 hvec3 hvec4 fvec2 fvec3 fvec4
sampler3DRect
filter
image1D image2D image3D imageCube
iimage1D iimage2D iimage3D iimageCube
uimage1D uimage2D uimage3D uimageCube
image1DArray image2DArray
iimage1DArray iimage2DArray uimage1DArray uimage2DArray
image1DShadow image2DShadow
image1DArrayShadow image2DArrayShadow
imageBuffer iimageBuffer uimageBuffer
sizeof cast
namespace using
row_major
You probably want to get the OpenGL ES GLSL language specification. §3.6 lists the keywords (plus a number of reserved words that aren't keywords, but you're not supposed to use anyway, so they probably merit some sort of color coding as well).
Edit: Oops, I grabbed the wrong link there. My apologies. The current specs are:
OpenGL 4.1 GLSL
OpenGL ES 2.0 GLSL
Besides the above answers, there are also reserved identifiers, eg. in GLSL ES 3.0 spec:
Identifiers starting with gl_ are reserved for use by OpenGL ES, and may not be declared in a shader as either a variable or a function. It is an error to redeclare a variable, including those starting “gl_”.
And other things beyond these are reserved:
In addition, all identifiers containing two consecutive underscores (__) are reserved for use by underlying software layers. Defining such a name in a shader does not itself result in an error, but may result in unintended behaviors that stem from having multiple definitions of the same name.
It is relevant for syntax coloring and correctness checking.
Similarly, macros starting with GL_, and a bunch of things with __.