Selectively drawing to some outputs in shaders - opengl

I have a framebuffer object with 2 outputs:
layout(location = 0) out vec4 color;
layout(location = 1) out uint object_id;
In my shader I also receive a boolean value, which tells me if I should write to the second output or not.
color = some_color;
if (condition) {
object_id = value;
}
Is this possible to achieve?
I thought I could do it with glBlendEquation(1, GL_MAX) and just write 0 in the else part of the if, but that doesn't seem to work with r32ui textures.

In my shader I also receive a boolean value, which tells me if I should write to the second output or not.
What is condition? A uniform? Something the shader calculates?
It comes as vertex shader input.
If you don't write to one of the user-defined fragment shader output variables, then this is an undefined behavior and the result which is stored to the framebuffer is undefined.
See OpenGL 4.6 API Core Profile Specification; 17.4. WHOLE FRAMEBUFFER OPERATIONS; page 516
If a fragment shader writes to no user-defined output variables, the values of the fragment colors following shader execution are undefined, and may differ for each fragment color. If some, but not all user-defined output variables are written, the values of fragment colors corresponding to unwritten variables are similarly undefined.
See OpenGL 4.6 API Core Profile Specification; 15.2. SHADER EXECUTION; page 492
When a fragment shader terminates, the value of each active user-defined output variable is written to components of the fragment color output to which it is bound.
I thought I could do it with glBlendEquation(1, GL_MAX) and just write 0 in the else part of the if, but that doesn't seem to work with r32ui textures.
That is not possible, because blending is not applied to integer format buffers.
OpenGL 4.6 API Core Profile Specification; 17.3.6 Blending; page 502:
Blending applies only if the color buffer has a fixed-point or floating-point
format. If the color buffer has an integer format, proceed to the next operation.
What you can do is to use a fixed point format for the framebuffer data store, like GL_R16. GL_R16 has 16 bits to store the values from 0.0 to 1.0 and blending is provided. Further GL_R16 is provided for both, textures and renderbuffers. The corresponding data type is float.
You can store a unsigned integer to it by "normalizing" the value by dividing it by 2^16-1:
layout(location = 1) out vec4 object_id;
object_id.r = float(value) / (exp2(16.0)-1.0);

Related

Does dual-source blending require larger color buffer?

In OpenGL, we can turn on dual-source blending through following code in fragment shader:
layout(location = 0, index = 0) out vec4 color1;
layout(location = 0, index = 1) out vec4 color2;
And through token XX_SRC1_XX get color2 in blending functions. I have questions that:
If I want to do off-screen rendering, do I need to double the texture's storage's size as there are two colors output.
Is it that once I turn on dual-source blending then I can only output two colors to one buffer? And it means that I cannot bind more than one color buffers through attaching them to GL_COLOR_ATTACHMENTi tokens.
Is the qualifier 'index' here only used for dual-source blending purpose?
Dual-source blending means blending involving two color outputs from the FS. That has nothing to do with the nature of the images being written to (only the number). Location 0 still refers to the 0th index in the glDrawBuffers array, and the attachment works just as it did previously.
You are outputting two colors. But only one value (the result of the blend operation) gets written.
And it means that I cannot bind more than one color buffers through attaching them to GL_COLOR_ATTACHMENTi tokens.
Well, that depends on the number of attached images allowed when doing dual-source blending, as specified by your implementation. Granted, all known implementations set this to 1. Even Vulkan implementations all use 1 (or 0 if they don't support dual-source blending); the only ones that don't seem to be either early, broken implementations or software renderers,

Using 'discard' in GLSL 4.1 fragment shader with multisampling

I'm attempting depth peeling with multisampling enabled, and having some issues with incorrect data ending up in my transparent layers. I use the following to check if a sample (originally a fragment) is valid for this pass:
float depth = texelFetch(depthMinima, ivec2(gl_FragCoord.xy), gl_SampleID).r;
if (gl_FragCoord.z <= depth)
{
discard;
}
Where depthMinima is defined as
uniform sampler2DMS depthMinima;
I have enabled GL_SAMPLE_SHADING which, if I understand correctly, should result in the fragment shader being called on a per-sample basis. If this isn't the case, is there a way I can get this to happen?
The result is that the first layer or two look right, but beneath that (and I'm doing 8 layers) I start getting junk values - mostly plain blue, sometimes values from previous layers.
This works fine for single-sampled buffers, but not for multi-sampled buffers. Does the discard keyword still discard the entire fragment?
I have enabled GL_SAMPLE_SHADING which, if I understand correctly, should result in the fragment shader being called on a per-sample basis.
It's not enough to only enable GL_SAMPLE_SHADING. You also need to set:
glMinSampleShading(1.0f)
A value of 1.0 indicates that each sample in the framebuffer should be indpendently shaded. A value of 0.0 effectively allows the GL to ignore sample rate shading. Any value between 0.0 and 1.0 allows the GL to shade only a subset of the total samples within each covered fragment. Which samples are shaded and the algorithm used to select that subset of the fragment's samples is implementation dependent.
– glMinSampleShading
In other words 1.0 tells it to shade all samples. 0.5 tells it to shade at least half the samples.
// Check the current value
GLfloat value;
glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE, &value);
If either GL_MULTISAMPLE or GL_SAMPLE_SHADING is disabled then sample shading has no effect.
There'll be multiple fragment shader invocations for each fragment, to which each sample is a subset of the fragment. In other words. Sample shading specifies the minimum number of samples to process for each fragment.
If GL_MIN_SAMPLE_SHADING_VALUE is set to 1.0 then there'll be issued a fragment shader invocation for each sample (within the primitive).
If its set to 0.5 then there'll be a shader invocation for every second sample.
max(ceil(MIN_SAMPLE_SHADING_VALUE * SAMPLES), 1)
Each being evaluated at their sample location (gl_SamplePosition).
With gl_SampleID being the index of the sample that is currently being processed.
Should discard work on a per-sample basis, or does it still only work per-fragment?
With or without sample shading discard still only terminate a single invocation of the shader.
Resources:
ARB_sample_shading
Fragment Shader
Per-Sample Processing
I faced a similar problem when using depth_peeling on a multi-sample buffer.
Some artifacts appears due to the depth_test error when using a multi_sample depth texture from the previous peel and the current fragment depth.
vec4 previous_peel_depth_tex = texelFetch(previous_peel_depth, coord, 0);
the third argument is the sample you want to use for your comparison which will give a different value from the fragment center. Like the author said you can use gl_SampleID
vec4 previous_peel_depth_tex = texelFetch(previous_peel_depth, ivec2(gl_FragCoord.xy), gl_SampleID);
This solved my problem but with a huge performance drop, if you have 4 samples you will run your fragment shader 4 times, if 4 have peels it means 4x4 calls. You don't need to set the opengl flags if atleast glEnable(GL_MULTISAMPLE); is on
Any static use of [gl_SampleID] in a fragment shader causes the entire
shader to be evaluated per-sample
I decided to use a different approach and to add a bias when doing the depth comparison
float previous_linearized = linearize_depth(previous_peel_depth_tex.r, near, far);
float current_linearized = linearize_depth(gl_FragCoord.z, near, far);
float bias_meter = 0.05;
bool belong_to_previous_peel = delta_depth < bias_meter;
This solve my problem but some artifacts might still appears and you need to adjust your bias in your eye_space units (meter, cm, ...)

Writing primtive ID per primitive in Geometry shader

I am a bit confused with the description of gl_PrimitiveID.Here is said that
The meaning for this value is whatever you want it to be. However, if
you want to match the standard OpenGL meaning (ie: what the Fragment
Shader would get if no GS were used), just do this for each vertex
before emitting it.: gl_PrimitiveID = gl_PrimitiveIDIn;
Does it mean that if I output a quad from geometry shader the fragment shader will get 0,1,2,3? What I need is to output gl_PrimitiveID once per primitive and not per vertex or triangle.Will this suffice?
gl_PrimitiveID = gl_PrimitiveIDIn
If I write it only once before EndPrimitive(); ?

Why gl_Color is not a built-in variable for the fragment shader?

The vertex shader is expected to output vertices positions in clip space:
Vertex shaders, as the name implies, operate on vertices.
Specifically, each invocation of a vertex shader operates on a single
vertex. These shaders must output, among any other user-defined
outputs, a clip-space position for that vertex. (source: Learning Modern 3D Graphics Programming, by Jason L. McKesson)
It has a built-in variable named gl_Position for that.
Similarly, the fragment shader is expected to output colors:
A fragment shader is used to compute the output color(s) of a
fragment. [...] After the fragment shader executes, the fragment
output color is written to the output image. (source: Learning
Modern 3D Graphics Programming, by Jason L. McKesson)
but there is no gl_Color built-in variable defined for that as stated here: opengl44-quick-reference-card.pdf
Why that (apparent) inconsistency in the OpenGL API?
That is because the OpenGL pipeline uses gl_Position for several tasks. The manual says: "The value written to gl_Position will be used by primitive assembly, clipping, culling and other fixed functionality operations, if present, that operate on primitives after vertex processing has occurred."
In contrast, the pipeline logic does not depend on the final pixel color.
The accepted answer does not adequately explain the real situation:
gl_Color was already used once-upon-a-time, but it was always defined as an input value.
In compatibility GLSL, gl_Color is the color vertex pointer in vertex shaders and it takes on the value of gl_FrontColor or gl_BackColor depending on which side of the polygon you are shading in a fragment shader.
However, none of this behavior exists in newer versions of GLSL. You must supply your own vertex attributes, your own varyings and you pick between colors using the value of gl_FrontFacing. I actually explained this in more detail in a different question related to OpenGL ES 2.0, but the basic principle is the same.
In fact, since gl_Color was already used as an input variable this is why the output of a fragment shader is called gl_FragColor instead. You cannot have a variable serve both as an input and an output in the same stage. The existence of an inout storage qualifier may lead you to believe otherwise, but that is for function parameters only.

GLSL fragment shader output type

Suppose I'm having a problem like this: now I have a framebuffer and a texture only contains one color component(for example, GL_RED) has already binded to it. What will fragment shader looks like? I guess the answer is:
...
out float ex_color;
ex_color = ...;
Here comes my question : will the shader automatically detect the format of framebuffer and write values to it? What if fragment shader outputs float values but framebuffer format is GL_RGBA?
By the way, what is the correct approach to create a texture only has one component? I read examples from g-truc which has a sample like this:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED,GLsizei(Texture.dimensions().x), GLsizei(Texture.dimensions().y), 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
What's the meaning of assign GL_RGB as pixel data format?
Just like vertex shader inputs don't have to match the exact size of the data specified by glVertexAttribPointer, fragment shader outputs don't have to match the exact size of the image they're being written to. If the output provides more components than the destination image format, then the extra components are ignored. If it provides fewer, then the other components have undefined values (unlike vertex inputs, where unspecified values have well-defined values).
What's the meaning of assign GL_RGB as pixel data format?
That's the pixel transfer format. That describes the format of pixels you're providing to OpenGL, not the format that OpenGL will store them as.
You should always use sized internal formats, not unsized ones like GL_RED.
For a decent explanation of the internal format and format, see:
http://opengl.org/wiki/Image_Format and http://opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml.
You basically want GL_RED for format and likely want GL_R8 (unsigned normalized 8-bit fixed-point) for the internal format.
A long time ago, luminance textures were the norm for single-channel, but that is a deprecated format in modern GL and red is now the logical "drawable" texture format for single-channels, just as red/green is the most logical format for two-channel.
As for your shader, there are rules for component expansion defined by the core specification. If you have a texture with 1 channel as an input, but sample it as a vec4, it will be equivalent to: vec4 (RED, 0.0, 0.0, 1.0).
Writing to the texture is a little bit different.
From the OpenGL 4.4 Spec, section 15.2 (Shader Execution), pp. 441 -- http://www.opengl.org/registry/doc/glspec44.core.pdf
When a fragment shader terminates, the value of each active user-defined output variable is written to components of the fragment color output to which it is bound. The set of fragment color components written is determined according to the variable’s data type and component index binding, using the mappings in table 11.1 [pp. 341].
By default, if your fragment shader's output is a float, it is going to write to the x (red) component of your texture. You could use a layout qualifier (e.g. layout (component=1) out float color;) to specify that it should write to y (green), z (blue) or w (alpha) (assuming you have an RGBA texture).