glsl conditionally assigning out_color - glsl

I'm trying to achieve blending by using a shader to conditionally assign the fragment color.
Full shader code...
#version 450
#pragma shader_stage(fragment)
layout(binding = 1) uniform sampler2D texture_sampler;
layout(location = 0) in vec2 tex_coord;
layout(location = 1) in vec4 _rgba;
layout(location = 0) out vec4 out_color;
void main() {
vec4 oc = textureLod(texture_sampler, tex_coord, 0);
if (oc.r > _rgba.r)
oc.r = _rgba.r;
if (oc.g > _rgba.g)
oc.g = _rgba.g;
if (oc.b > _rgba.b)
oc.b = _rgba.b;
if (oc.a > _rgba.a)
oc.a = _rgba.a;
float threshhold = .5;
if (oc.a > threshhold)
out_color = oc;
}
(this flickers at run time btw...)
changing the last bit of code to...
float threshhold = .5;
//if (oc.a > threshhold)
out_color = oc;
does this...
If I remove the assignment completely, the text just dissappears. It seems that having the assignment there makes the driver expect it to always be assigned. Does anyone know why this is happening? Why can't I conditionally leave the pixel unmodified? Is there something I have to change in my Vulkan code for the pipeline?

This declaration in a shader
layout(location = 0) out vec4 out_color;
is basically telling the pipeline that whatever value out_color ends up with at the end of execution is what should go in the framebuffer. You're not allowed to just not assign a value. If you fail to write the value it's the same as having an uninitialized variable in C. The contents will be random based on whatever happened to be in that memory address at the start of execution.
From the GL wiki (but still applicable to GLSL shaders for Vulkan)
The shader must set all output variables at some point in its execution
The only two exceptions this. The first is if the output variable isn't being read by subsequent stages. In this case, there are no subsequent stages, and the variable is the output going to the framebuffer, so that's not applicable.
The second is in fragment shaders where you use the discard keyword. You're not using discard in your shader, but most likely that would fix your problem. Try changing your code to
if (oc.a > threshhold)
out_color = oc;
else
discard;
However, bear in mind that discard as a keyword can impact performance of the entire pipeline because it can no longer assume that every evaluation of the shader will produce output. See this other question

Related

Why does GLSL Warning tell me varying isn't written to, when it clearly is?

I have never had any problems passing variables from vertex shader to fragment shader. But today, I added a new "out" variable in the vs, and a corresponding "in" variable in the fs. GLSL says the following:
Shader Program: The fragment shader uses varying tbn, but previous shader does not write to it.
Just to confirm, here's the relevant part of the VS:
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 uv;
// plus other layout & uniform inputs here
out DATA
{
vec2 uv;
vec3 tangentViewDir;
mat3 tbn;
} vs_out;
void main()
{
vs_out.uv = uv;
vs_out.tangentViewDir = vec3(1.0);
vs_out.tbn = mat3(1.0);
gl_Position = sys_ProjectionViewMatrix * sys_ModelMatrix * position;
}
And in the FS, it is declared as:
in DATA
{
vec2 uv;
vec3 tangentViewDir;
mat3 tbn;
} fs_in;
Interestingly, all other varyings, like "uv" and all, work. They are declared the same way.
Also interesting: Even though GLSL says the variable isn't written to - it still recognizes the changes when I write to it, and displays those changes.
So is it just a false warning or bug? Even though it tells me otherwise, the value seems to be passed correctly. Why do I receive this warning?
HolvBlackCat pointed me in the right direction - it was indeed a shader mismatch!
I had 2 shader programs, same FS in both, but different VSs, and I forgot to update the outputs of the 2nd VS to match the output layout of the first, so that they both work with the same FS!
Ouch, I guess now that I've run into this error, lesson learnt.
Thank you HolvBlackCat!

c++/OpenGL/GLSL, textures with "random" artifacts

Would like to know if someone has experienced this and knows the reason. I'm getting these strange artifacts after using "texture arrays"
http://i.imgur.com/ZfLYmQB.png
(My gpu is AMD R9 270)
ninja edit deleted the rest of the post for readability since it was just showing code where the problem could have been, since the project is open source now I only show the source of the problem(fragment shader)
Frag:
#version 330 core
layout (location = 0) out vec4 color;
uniform vec4 colour;
uniform vec2 light;
in DATA{
vec4 position;
vec2 uv;
float tid;
vec4 color;
}fs_in;
uniform sampler2D textures[32];
void main()
{
float intensity = 1.0 / length(fs_in.position.xy - light);
vec4 texColor = fs_in.color;
if(fs_in.tid > 0.0){
int tid = int(fs_in.tid - 0.5);
texColor = texture(textures[tid], fs_in.uv);
}
color = texColor; // * intensity;
}
Edit: github repos (sorry if It is missing some libs, having trouble linking them to github) https://github.com/PedDavid/NubDevEngineCpp
Edit: Credits to derhass for pointing out I was doing something with undefined results (accessing the array without a constant ([tid])). I have it now working with
switch(tid){
case 0: textureColor = texture(textures[0], fs_in.uv); break;
...
case 31: textureColor = texture(textures[31], fs_in.uv); break;
}
Not the prettiest, but fine for now!
I'm getting these strange artifacts after using "texture arrays"
You are not using "texture arrays". You use arrays of texture samplers. From your fragment shader:
#version 330 core
// ...
in DATA{
// ...
float tid;
}fs_in;
//...
if(fs_in.tid > 0.0){
int tid = int(fs_in.tid - 0.5);
texColor = texture(textures[tid], fs_in.uv);
}
What you try to do here is not allowed as per the GLSL 3.30 specification which states
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”).
Your tid is not a constant, so this will not work.
In GL 4, this constraint has been somewhat relaxed to (quote is from GLSL 4.50 spec):
When aggregated into arrays within a shader, samplers can only be
indexed with a dynamically uniform integral expression, otherwise
results are undefined.
Your now your input also isn't dynamically uniform either, so you will get undefined results too.
I don't know what you are trying to achieve, but maybe you can get it dobe by using array textures, which will represent a complete set of images as a single GL texture object and will not impose such constraints at accessing them.
That looks like the shader is rendering whatever random data it finds in memory.
Have you tried checking that glBindTexture(...) is called at the right time (before render) and that the value used (as returned by glGenTextures(...)) is valid?

Opengl error 1282 (invalid operation) when using texture()

I have the following fragment shader:
#version 330 core
layout (location = 0) out vec4 color;
uniform vec4 colour;
uniform vec2 light_pos;
in DATA
{
vec4 position;
vec2 texCoord;
float tid;
vec4 color;
} fs_in;
uniform sampler2D textures[32];
void main()
{
float intensity = 1.0 / length(fs_in.position.xy - light_pos);
vec4 texColor = fs_in.color;
if (fs_in.tid > 0.0)
{
int tid = int(fs_in.tid + 0.5);
texColor = texture(textures[tid], fs_in.texCoord);
}
color = texColor * intensity;
}
If I run my program, I get opengl error 1282, which is invalid operation. If I don't use the texture(), so I write texCoord = vec4(...) it works perfectly. I'm always passing in tid (texture ID) as 0 (no texture) so that part shouldn't even run. I've set the textures uniform to some placeholder, but as far as I know this shouldn't even matter. What could cause the invalid operation then?
Your shader compilation has most likely failed. Make sure that you always check the compile status after trying to compile the shader, using:
GLint val = GL_FALSE;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &val);
if (val != GL_TRUE)
{
// compilation failed
}
In your case, the shader is illegal because you're trying to access an array of samplers with a variable index:
texColor = texture(textures[tid], fs_in.texCoord);
This is not supported in GLSL 3.30. From the spec (emphasis added):
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”).
This restriction is relaxed in later OpenGL versions. For example, from the GLSL 4.50 spec:
When aggregated into arrays within a shader, samplers can only be indexed with a dynamically uniform integral expression, otherwise results are undefined.
This change was introduced in GLSL 4.00. But it would still not be sufficient for your case, since you're trying to use an in variable as the index, which is not dynamically uniform.
If your textures are all the same size, you may want to consider using an array texture instead. That will allow you to sample one of the layers in the array texture based on a dynamically calculated index.
I know this solution is late, but if it helps anybody..
As per Cherno's video, this should work. He however uses the attribute 'fs_in.tid' as a 'GL_BYTE' in the gl_VertexAttribPointer fo the texture index, for some reason regarding casting 1.0f always got converted to 0.0f and hence did not work.
Changing GL_BYTE to GL_FLOAT resolved this issue for me.
Regarding the 'opengl error 1282', its a very common mistake I faced. I used to forget to call glUseProgram(ShaderID) before setting any of the uniforms. Because of this the uniforms even though not being used/set at the time can cause an error, namely '1282'. This could be one of the solutions, this solved it for me.

OpenGL shader not passing variable from vertex to fragment shader

I'm encountering something really really strange.
I have a very simple program that renders a simple full-screen billboard using the following shader pipeline:
VERTEX SHADER:
#version 430
layout(location = 0) in vec2 pos;
out vec2 tex;
void main()
{
gl_Position = vec4(pos, 0, 1);
tex = (pos + 1) / 2;
}
FRAGMENT SHADER:
#version 430
in vec2 tex;
out vec3 frag_color;
void main()
{
frag_color = vec3(tex.x, tex.y, 1);
}
The program always renders the quad in the correct positions (so I've ruled out the VAO as culprit), but for some reason ignores whatever values I set for tex and always set it to vec2(0,0), rendering a blue box.
Is there something I'm missing here? I've done many opengl apps before, and I've never encountered this. :/
I've seen implementations of OpenGL 2.0 having problems at compile time when adding floats and not explicitly casted integers.
Even if it is not a problem I would think possible on a 4.3 implementation, maybe you should just add dots and suffixes to your "integer" constants.
The last line of you're vertex shader seems to be the only one that could be a problem (I believe values are always casted in constructors :p ) so you would have something like this instead:
tex = (pos + 1.0f) / 2.0f;
Remember that you're shaders can compile on thousands of different implementations so it's a good habit to always be explicit!!!

GLSL Atomic Image Access

My other post intends to collect general information on the kinds of GLSL spinlocks, but unfortunately nothing has come of it, nor has it solved my problem. Therefore, a specific question. I reduced my problem down to a minimal example, presented below:
The trivial problem makes a screen-sized texture of locks and texture of color. In pass one, the colors are all set to zero (shader 1). In pass two, two triangles are drawn, which the geometry shader quadruples and slightly offsets (shader 2). The fragment shader atomically increments the texture's color. In pass three, the color is visualized (shader 3).
Shader 1:
//Vertex
#version 440
uniform mat4 mat_P;
in vec4 _vec_vert_a;
void main(void) {
gl_Position = mat_P*_vec_vert_a;
}
//Fragment
#version 440
layout(rgba32f) coherent uniform image2D img0;
void main(void) {
imageStore(img0,ivec2(gl_FragCoord.xy),vec4(0.0,0.0,0.0,1.0));
discard;
}
Shader 2:
//Vertex
#version 440
in vec4 _vec_vert_a;
out vec4 vert_vg;
void main(void) {
vert_vg = _vec_vert_a;
}
//Geometry
#version 440
#define REPS 4
layout(triangles) in;
layout(triangle_strip,max_vertices=3*REPS) out;
uniform mat4 mat_P;
in vec4 vert_vg[3];
void main(void) {
for (int rep=0;rep<REPS;++rep) {
for (int i=0;i<3;++i) {
vec4 vert = vert_vg[i];
vert.xy += vec2(5.0*rep);
gl_Position = mat_P*vert; EmitVertex();
}
EndPrimitive();
}
}
//Fragment
#version 440
layout(rgba32f) coherent uniform image2D img0;
layout(r32ui) coherent uniform uimage2D img1;
void main(void) {
ivec2 coord = ivec2(gl_FragCoord.xy);
bool have_written = false;
do {
bool can_write = (imageAtomicExchange(img1,coord,1u)!=1u);
if (can_write) {
vec4 data = imageLoad(img0,coord);
data.xyz += vec3(1.0,0.0,0.0);
imageStore(img0,coord,data);
memoryBarrier();
imageAtomicExchange(img1,coord,0);
have_written = true;
}
} while (!have_written);
discard;
}
Shader 3:
//Vertex
#version 440
uniform mat4 mat_P;
in vec4 _vec_vert_a;
void main(void) {
gl_Position = mat_P*_vec_vert_a;
}
#version 440
layout(rgba32f) coherent uniform image2D img0;
void main(void) {
vec4 data = imageLoad(img0,ivec2(gl_FragCoord.xy));
gl_FragData[0] = vec4(data.rgb/4.0, 1.0); //tonemap
}
Main Loop:
Enable Shader 1
render fullscreen quad
glMemoryBarrier(GL_ALL_BARRIER_BITS);
Enable Shader 2
Render two small triangles
glMemoryBarrier(GL_ALL_BARRIER_BITS);
Enable Shader 3
render fullscreen quad
Note that in steps 3 and 6 I [think I ]could have used GL_SHADER_IMAGE_ACCESS_BARRIER_BIT. Just in case, I'm being conservative.
The visualized colors jitter with time, and are mostly fairly small. This shows that atomicity is not happening. Can someone sanity check this procedure? Am I missing anything?
EDIT: From this page, I found that using discard can make image load/store undefined in the fragment. I removed discards, but the problem still occurs. I also found layout(early_fragment_tests) in;, which forces early fragment tests (it didn't help either).
Another related link:
https://www.opengl.org/discussion_boards/showthread.php/182715-Image-load-store-mutex-problem?p=1255935#post1255935
Some spin lock code that worked last time I tested it (granted a few years ago):
http://blog.icare3d.org/2010/07/opengl-40-abuffer-v20-linked-lists-of.html
Another implementation of the same application:
https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2020%20Efficient%20Layered%20Fragment%20Buffer%20Techniques/lfbPages.glsl
In the above links, a canary is used which definitely was important and possibly still is. coherent is important but you have that. A few years ago memoryBarrier() simply wasn't implemented and did nothing. I hope this isn't the case, however it may be the spin lock works just fine and the writes to img0 don't happen in order with following reads.
GLSL compilers can be a bit buggy some times. Here's a few examples to show just how strange GLSL coding can get. Point is, trying lots of different ways of writing the same code can help. I've seen issues with functions as conditionals inside while loops simply failing.
For all I know do..while compiles vastly differently to a typical while.
Combining as many conditions into the loop condition can sometimes help too.
Sometimes else break doesn't behave as expected or allow the compiler to unroll certain loops and you have to use the following:
for (...)
{
if (...)
{
...
continue;
}
break;
}