I've just read through this answer and its comments and have some related questions:
Does this rule apply to uniform variables too?
Can I call glUniform3fv for vec4 uniform and expect the W component to be 1.0, etc.?
Where does the OpenGL spec mention about this topic?
The specs in (7.6. UNIFORMVARIABLES) say that the Uniform* would result in INVALID_OPERATION error if:
the size indicated in the name of the Uniform* command used does not match the size of the uniform declared in the shader,
or
the component type and count indicated in the name of the Uniform* command used does not match the type of the uniform declared in the shader, where a boolean uniform component type is considered to match any of the Uniform*i{v}, Uniform*ui{v}, or Uniform*f{v} commands.
And testing to call glUniform3f for a vec4 uniform will indeed result in a INVALID_OPERATION error.
No, these rules do not apply to uniforms. Consequently, you are not allowed to call glUniform3fv on a vec4.
The Spec states in Section 7.6.1:
For all [...] uniform types loadable with Uniform* commands, the command
used must match the size and type of the uniform, as declared in the shader, and
no type conversions are done.
Related
The OpenGL specification lies (or is this a bug?)... Referring to the layout for std140, with shared uniform buffers, it states:
"The set of rules shown in Tabl e L-1 are used by the GLSL compiler to
layout members in a std140-qualified uniform block. The offsets of
members in the block are accumulated based on the sizes of the
previous members in the block (those declared before the variable in
question), and the starting offset. The starting offset of the first
member is always zero.
Scalar variable type (bool, int, uint, float) - Size of the scalar in
basic machine types"
(http://www.opengl-redbook.com/appendices/AppL.pdf)
So, armed with this information, I setup a uniform block in my shader that looks something like this:
// Spotlight.
layout (std140) uniform Spotlight
{
float Light_Intensity;
vec4 Light_Ambient;
vec3 Light_Position;
};
... only to discover it doesn't work with the subsequent std140 layout I setup on the CPU side. That is the first 4 bytes are a float (size of the machine scalar type for GLfloat), the next 16 bytes are a vec4 and the following 12 bytes are a vec3 (with 4 bytes left over on the end to take account of the rule that a vec3 is really a vec4).
When I change the CPU side to specify a float as being the same size as a vec4, i.e. 16 bytes, and do my offsets and buffer size making this assumption, the shader works as intended.
So, either the spec is wrong or I've misunderstood the meaning of "scalar" in this context, or ATI have a driver bug. Can anyone shed any light on this mystery?
That PDF you linked to is not the OpenGL specification. I don't know where you got it from, but that is certainly not the full list of rules. Always check your sources; the spec is not as unreadable as many claim it to be.
Yes, the size of variables of basic types is the same size as the basic machine type (ie: 4 bytes). But size alone does not determine the position of the variable.
Each type has a base alignment, and no matter where that type is found in a uniform block, it's overall byte offset must fit that alignment. The base alignment of a vec4 is 4 * the alignment of its basic type (ie: float). So the base alignment of a vec4 is 16.
Because Light_Intensity ends after 4 bytes, the compiler must insert 12 bytes of padding, because Light_Ambient cannot be on a 4-byte boundary. It must be on a 16-byte boundary, so the compiler uses 12 bytes of empty space.
ATI does have a few driver bugs around std140 layout, but this isn't one of them.
As a general rule, I like to explicitly put padding into my structures, and I avoid vec3 (because it has 16 byte alignment). Doing these generally cuts down on compiler bugs as well as accidental misunderstanding about where things go and how much room they actually take.
I have been trying to get a 16bit float (half-floating point) as an attribute into my GLSL vertex shader. It won't let me compile saying:
error C7506: OpenGL does not define the global type half
but my #version is 410 and so it should support half? Am I missing something obvious?
OpenGL and OpenGL ES define two concurrent types of precision.
Storage precision in buffers
Minimum computational precision used in shaders.
Storage precision is defined by your vertex attribute upload, such as GL_FLOAT or GL_HALF_FLOAT. This will be the precision used to store the data in memory.
Usage precision is defined in the shader as highp (at least 32-bit), mediump (at least 16-bit), and lowp (at least 9-bit). These are minimum precisions; it is perfectly legal for a shader to specify a variable as mediump and for the shader compiler to generate fp32 data types. Desktop GPUs tend to only support fp32 computation, so the use of highp, mediump and lowp all map to fp32 data types (the precision qualifiers are only included to keep compatibility with OpenGL ES shaders, and can legally be ignored by the compiler). Mobile GPUs implementing OpenGL ES tend to map highp to fp32, and mediump and lowp to fp16.
Detailed information can be found in the GLSL ES 3.0 Specification, Section 4.5.1
When binding a vertex attribute in memory to an input shader variable the storage and usage precisions are not required to match; the API will include transparent attribute precision conversion. It is perfectly legal for a user to upload e.g. a GL_FLOAT and then use it in a shader as a mediump fp16 variable, although it would be a waste of memory bandwidth to do so.
In the absence of a MCVE demonstrating otherwise I assume you tried something like:
half float aHalfFloat;
However, "half" is a reserved keyword in #version 410:
OpenGL Shading Language 4.10 Specification, page 15 (emphasis mine):
The following are the keywords reserved for future use. Using them
will result in an error:
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 In addition, all
identifiers
Let's say I have a varying variable between any two GLSL shader stages (e.g. the vertex and fragment stage) declared as a vec4:
in/out/varying vec4 texCoord;
What happens if I only use part of that variable (say, through swizzling) in both shaders, i.e. I only write to a part of it in the vertex shader and only read from that same part in the fragment shader?
// vertex shader
texCoord.st = ...
// fragment shader
... = texture2D(..., texCoord.st);
Is that guartanteed (i.e. by specification) to always produce sane results? It seems reasonable that it does, however I'm not too well-versed in the intricacies of GLSL language-lawyering and don't know if that varying variable is interpreted as somehow "incomplete" by the compiler/linker because it isn't fully written to in the preceding stage. I'm sure the values of texCoord.pq will be undefined anyway, but does that affect the validity of texCoord.st too or does the whole varying system operate on a pure component level?
I haven't found anything to that effect in the GLSL specification on first glance and I would prefer answers based either on the actual specification or any other "official" guarantees, rather than statements that it should work on reasonable hardware (unless of course this case simply is unspecified or implementation-defined). I would also be interested in any possible changes of that throughout GLSL history, including all the way back to its appliance to deprecated builtin varying variables like gl_TexCoord[] in good old GLSL 1.10.
I'm trying to argue that your code will be fine, as per the specification. However, I'm not sure if you will find my reasoning 100% convincing, because I think that the spec seems somewhat imprecise about this. I'm going to refer to the OpenGL 4.5 Core Profile Specification and the OpenGL Shading language 4.50 specification.
Concerning input and output variables, the GLSL spec established the following in section 4.3.4
Shader input variables are declared with the storage qualifier in. They form the input interface between
previous stages of the OpenGL pipeline and the declaring shader. [...] Values from the previous pipeline stage are copied into input variables at the beginning of
shader execution.
and 4.3.6, respectively:
Shader output variables are declared with a storage qualifier using the storage qualifier out. They form
the output interface between the declaring shader and the subsequent stages of the OpenGL pipeline. [...]
During shader execution they will behave as normal
unqualified global variables. Their values are copied out to the subsequent pipeline stage on shader exit.
Only output variables that are read by the subsequent pipeline stage need to be written; it is allowed to
have superfluous declarations of output variables.
Section 5.8 "Assignments" establishes that
Reading a variable before writing (or initializing) it is legal, however the value is undefined.
Since the assignment of the .st vector will write to the sub-vector, we can establish that this variable will contain two intialized and two un-initialized components at the end of the shader invocation, and the whole vector will be copied to the output.
Section 11.1.2.1 of the GL spec states:
If the output variables are passed directly to the vertex processing
stages leading to rasterization, the values of all outputs are
expected to be interpolated across the primitive being rendered,
unless flatshaded. Otherwise the values of all outputs are collected
by the primitive assembly stage and passed on to the subsequent
pipeline stage once enough data for one primitive has been collected.
"The values of all outputs" are determined by the shader, and although some components have undefined values, they still have values, and there is no undefined or implementation-defined behavior here. The interpolation formulas for the line and polygon primitives (sections 14.5.1 and 14.6.1) also never mix between the components, so any defined component value will result in a defined value in the interpolated datum.
Section 11.1.2.1 also contains this statement about the vertex shader outputs:
When a program is linked, all components of any outputs written by a
vertex shader will count against this limit. A program whose vertex
shader writes more than the value of MAX_VERTEX_OUTPUT_COMPONENTS
components worth of outputs may fail to link, unless device-dependent
optimizations are able to make the program fit within available
hardware resources.
Note that this language implies that the full 4 components of a vec4 are counted against the limit as soon as a single component is written to.
On output variables, the specification says:
Their values are copied out to the subsequent pipeline stage on shader exit.
So the question boils down to two things:
What is the value of such an output variable?
That is easily answered. The section on swizzling makes it clear that writing to a swizzle mask will not modify the components that are not part of the swizzle mask. Since you did not write to those components, their values are undefined. So undefined values will be copied out to the subsequent pipeline stage.
Will interpolation of undefined values affect the interpolation of defined values?
No. Interpolation is a component-wise operation. The result of one component's interpolation cannot affect another's.
So this is fine.
I'm using OpenGL 3.3 GLSL 1.5 compatibility. I'm getting a strange problem with my vertex data. I'm trying to pass an index value to the fragment shader, but the value seems to change based on my camera position.
This should be simple : I pass a GLfloat through the vertex shader to the fragment shader. I then convert this value to an unsigned integer. The value is correct the majority of the time, except for the edges of the fragment. No matter what I do the same distortion appears. Why is does my camera position change this value? Even in the ridiculous example below, tI erratically equals something other than 1.0;
uint i;
if (tI == 1.0) i = 1;
else i = 0;
vec4 color = texture2D(tex[i], t) ;
If I send integer data instead of float data I get the exact same problem. It does not seem to matter what I enter as vertex Data. The value I enter into the data is not consistent across the fragment. The distortion even looks the exact same each time.
What you are doing here is invalid in OpenGL/GLSL 3.30.
Let me quote the GLSL 3.30 specification, section 4.1.7 "Samplers" (emphasis mine):
Samplers aggregated into arrays within a shader (using square brackets
[ ]) can only be indexed with integral constant expressions (see
section 4.3.3 “Constant Expressions”).
Using a varying as index to a texture does not represent a constant expression as defined by the spec.
Beginning with GL 4.0, this was somewhat relaxed. The GLSL 4.00 specification states now the following (still my emphasis):
Samplers aggregated into arrays within a shader (using square brackets
[ ]) can only be indexed with a dynamically uniform integral
expression, otherwise results are undefined.
With dynamically uniform being defined as follows:
A fragment-shader expression is dynamically uniform if all fragments
evaluating it get the same resulting value. When loops are involved,
this refers to the expression's value for the same loop iteration.
When functions are involved, this refers to calls from the same call
point.
So now this is a bit tricky. If all fragment shader invocations actaully get the same value for that varying, it would be allowed, I guess. But it is unclear that your code guarantees that. You should also take into account that the fragment might be even sampled outside of the primitive.
However, you should never check floats for equality. There will be numerical issues. I don't know what exactly you are trying to achieve here, but you might use some simple rounding behavior, or use an integer varying. You also should disable the interpolation of the value in any case using the flat qualifier (which is required for the integer case anyway), which should greatly improve the changes of that construct to become dynamically uniform.
float texture(gsampler2DArrayShadow sampler, vec4 P, [float bias]);
Look at this function in OpenGL ES (shader lang). I do not understand the difference between gsampler2DArrayShadow and sampler2DArrayShadow. Can you explain this? I read that 'g' can mean nothing or i or u. But what then is this type?
Also, Does '[float bias]' mean that we have 2 functions: with this parameter and without?
Anytime you see a variable type in GLSL prefixed with g in a function prototype, that is a shorthand convention that means there is an overload for every type of data. A function that accepts gvec, for instance, means it has an overload for ivec, uvec, vec, dvec, bvec and so on.
Desktop GLSL has support for integer samplers in addition to fixed-/floating-point so you will see a lot of functions defined using gsampler... instead of sampler..., that means the function has isampler... and usampler... overloads in addition to the more traditional variety.
As for [float bias], that is used to control mipmap LOD bias. When you do not supply a value to that parameter, GL computes the bias itself.
Interestingly because of the way mipmap LODs are computed, only the fragment shader variety of the texture lookups support automatic mipmap selection (it has to do with the per-fragment derivative calculation). To use mipmapping in the vertex shader, you have to explicitly select the LOD with textureLod (...) or supply your own partial derivative using textureGrad (...).