Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using only part of a varying variable

Tags:

opengl

glsl

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.

like image 392
Christian Rau Avatar asked Apr 29 '17 16:04

Christian Rau


People also ask

What is a varying variable?

varying variables contain data shared from a vertex shader to a fragment shader. The variable must be written in the vertex shader and the read-only value in the fragment shader is then interpolated from the vertices which make up the fragment.

What is the difference between a uniform variable and a varying variable?

uniform are per-primitive parameters (constant during an entire draw call) ; attribute are per-vertex parameters (typically : positions, normals, colors, UVs, ...) ; varying are per-fragment (or per-pixel) parameters : they vary from pixels to pixels.

What is gl_PointCoord?

gl_PointCoord is a fragment language input variable that contains the two-dimensional coordinates indicating where within a point primitive the current fragment is located. If the current primitive is not a point, then values read from gl_PointCoord are undefined.

What is gl_FragCoord?

Available only in the fragment language, gl_FragCoord is an input variable that contains the window relative coordinate (x, y, z, 1/w) values for the fragment. If multi-sampling, this value can be for any location within the pixel, or one of the fragment samples.


1 Answers

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.

like image 53
derhass Avatar answered Sep 28 '22 00:09

derhass