GLSL Atomic Image Access - opengl

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;
}

Related

gl_PointCoord compiles and links, but crashes at runtime

I successfully wrote a standard basic transform feedback particle system with point-sprites. No flickering, the particles update from one buffer into the next, which is then rendered, then output buffer becomes input buffer on next iteration. All GPU-side, standard transform feedback.
Wonderful! ONE BIG PROBLEM: It only works if I don't use gl_PointCoord. Using a flat color for my point sprites works fine. But I need gl_PointCoord to do anything meaningful. All my shaders, whether or not they use gl_PointCoord, compile and link just fine. However, at runtime, if the shader uses gl_PointCoord (whether or not gl_PointCoord is actually in the execution path), the program crashes. I explicitly glEnable(GL_POINT_SPRITE). This doesn't have any effect. Omitting gl_PointCoord, and setting glPointSize(100.0f), and using vec4(1.0,1.0,1.0,1.) the particle system renders just fine as large white blocky squares (as expected). But using gl_PointCoord in any way (as standard texture lookup coord or procedural color or anything else) will crash my shaders at runtime, after successfully compiling and linking. I simply don't understand why. It passed glShaderSource, glCompileShader,glAttachShader, glLinkProgram. I'm compiling my shaders as #version 430, and 440, and I even tried 300 es. All compile, link, and I checked the status of the compile and link. All good. I'm using a high-end microsoft surface book pro, visual studio 2015. NVIDIA GeForce GPU. I also made sure all my drivers are up to date. Unfortunately, with point sprites, I don't have billboard vertices from the vertex shader to use to interpolate into the fragment shader as texture coordinates. gl_FragCoord doesn't work either (as I would expect for point sprites). Does anyone know how to solve this or use another technique for texture coordinates for point sprites?
glBeginTransformFeedback(GL_POINTS);//if my fragment shader uses gl_PointCoord, it hard crashes here.
When replying, please understand I'm very experienced in writing shaders, Vertex Shaders, Pixel Shaders, Tessellation control, tessellation evaluation, and geometry shaders, in GLSL and HLSL. But I don't claim to know everything. I could have forgotten something simple; I just have no idea what that could be. I'm figuring it could be a state I don't have enabled. As far as transform feedback goes, I also set up the varying attribs correctly via glTransformFeedbackVaryings.
C++ :
void Render(void* pData)
{
auto pOwner = static_cast<CPointSpriteSystem*>(pData);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_POINT_SPRITE);
glEnable(GL_POINT_SMOOTH);
//glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
m_Shader.Activate();
auto num_particles = pOwner->m_NumPointSprites;
FeedbackIndex = 0;
while (true)
{
m_Shader.SetSubroutine(GL_VERTEX_SHADER, "RenderPass",
vssubroutines[FeedbackIndex],
vsprevSubLoc[FeedbackIndex],
vsupdateSub[FeedbackIndex]);
m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
pssubroutines[0],
psprevSubLoc[0],
psrenderSub[0]);
if (!FeedbackIndex)
{
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(m_vao[bufferIndex]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_Feedback[bufferIndex]);
glBeginTransformFeedback(GL_POINTS);//if feedback fragment shader uses gl_PointCoord, will always hard-crash here
glDrawArrays(GL_POINTS, 0, num_particles);
glEndTransformFeedback();
glFlush();
}
else
{
m_Shader.SetSubroutine(GL_FRAGMENT_SHADER, "RenderPixelPass",
pssubroutines[(int)pOwner->m_ParticleType],
psprevSubLoc[(int)pOwner->m_ParticleType],
psrenderSub[(int)pOwner->m_ParticleType]);
glPointSize(100.0f);
glDisable(GL_RASTERIZER_DISCARD);
glDrawTransformFeedback(GL_POINTS, m_Feedback[bufferIndex]);
bufferIndex = 1 - bufferIndex;
break;
}
FeedbackIndex = 1 - FeedbackIndex;
}
}
VS feedback:
#version 310 es
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
layout(location=0) in vec3 VertexPosition;
layout(location=1) in vec3 VertexVelocity;
layout(location=2) in float VertexStartTime;
layout(location=3) in vec3 VertexInitialVelocity;
out vec3 Position;
out vec3 Velocity;
out float StartTime;
out float Transp;
uniform float g_fCurSeconds;
uniform float g_fElapsedSeconds;
uniform float Time;
uniform float H;
uniform vec3 Accel;
#ifdef USE_VIEW_BLOCK
layout(std140) uniform view_block{
mat4 g_mView,
g_mInvView,
g_mPrevView,
g_mPrevInvView,
g_mProj,
g_mInvProj;
};
uniform mat4 g_mWorld;
#endif
subroutine(RenderPassType) void UpdateSphere(){
Position=VertexPosition+VertexVelocity*g_fElapsedSeconds;
Velocity=VertexVelocity;
StartTime=VertexStartTime;
}
subroutine(RenderPassType) void Render(){
gl_Position=g_mProj*g_mInvView*vec4(VertexPosition,1.0);
}
void main(){
RenderPass();"
}
PS feedback:
#version 310 es //version 430 and 440 same results
subroutine void RenderPixelType();
subroutine uniform RenderPixelType RenderPixelPass;
uniform sampler2D tex0;
layout(location=0) out vec4 g_FragColor;
subroutine(RenderPixelType) void Basic(){
g_FragColor=vec4(1.0,1.0,1.0,1.0);
}
subroutine(RenderPixelType) void ProceduralSphere(){
#if 1
vec2 coord=gl_PointCoord;//at runtime: BOOM!
coord=coord*2.0-1.0;
float len=length(coord);
if(len>1.0) discard;
g_FragColor=vec4(1.0-len,1.0-len,1.0-len,1.0);
#else
g_FragColor=vec4(1.0,1.0,1.0,1.0);//always works
#endif
}
subroutine(RenderPixelType) void StandardImage(){
g_FragColor=texture2D(tex0,gl_PointCoord); //boom!!
g_FragColor=vec4(1.0,1.0,1.0,1.0);
}
void main(){
RenderPixelPass();
}
I solved the problem! The problem was actually that I didn't write a value to Transp (declared out float Transp;//in vs). I casually thought I didn't have to do this. But I started to trim some fat, and as soon as I wrote out a generic float (not actually being used by later shader stages: Transp=0.0f), and then compiled as #version 430, it all started to work as originally expected: little white spheres

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 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!!!

Error with a Simple vertex shader

I'm having a problem following this tutorial The First Triangle. I actually managed to get the First part working, but when it comes to the vertex shader it doesn't work.
Here is my Vertex Shader Code:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
It's just a copy of the Tutorial, but it gives me this error: must write to gl_Position.`
Just don't know what to do now.
EDIT: I'm using a GeForce 9500GT with 319.32 Drivers
EDIT2: I actually got the same thing in an older version, but it has the same error.
Here is the code:
#version 120
// Input vertex data, different for all executions of this shader.
attribute vec3 vertexPosition_modelspace;
void main(){
gl_Position = vec4(vertexPosition_modelspace, 1.0);
}
EDIT3: I'm using SFML as my default library.
I came to realize that what I were doing was kind of wrong thanks to you that helped me.
If anyone has this kind of problem the best option is to try the libraries (SFML) native functions.
That's what I'm doing now using this tutorial.
if your shader files have more than one newline [0D0A] at a time in succession, or if they consist of only 0D or 0A, you will have a bad day.
GOOD ->
#version 330 core
in vec3 ourColor;
out vec4 color;
void main()
{
color = vec4(ourColor, 1.0f);
}
BAD ->
#version 330 core
in vec3 ourColor;
out vec4 color;
void main()
{
color = vec4(ourColor, 1.0f);
}
at least that is what worked for me...

GLSL 1.5 - rendering to different layers of texture array

I have GL_TEXTURE_2D_ARRAY and I do this:
1. Render everything I want to FBO to texture array
2. Sample that array in the "main stage" of rendering
To achieve the first goal I've added a little geometry shader with gl_Layer calls to each primitive. Also, I've implemented some, let me say, "translation" thing similar to this Nvidia tutorial in my shaders that I use for the second stage of rendering.
So, what's my problem :
Condition: same vertices, same FBO, same shaders, same texture array
1) Rebinding rendering target multiply times in my FBO with glFramebufferTextureLayer calls works fine.
2) Saving texture array as glFramebufferTexture and only changing gl_Layer value leads to unexpected behaviour (first layer (0 in the code) is correct, every layer I try render next is invalid).
3) I don't want to 1) , I want to do 2) . How do I do that?
My shaders I use when rendering the FBO.
//vertex shader
#version 150 core
uniform mat4 orthoView;
in vec4 in_Position;
void main(void) {
gl_Position = orthoView * in_Position;
}
//geometry
#version 150 core
uniform int lr;
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
out int gl_Layer;
void main(void){
//pass-thru!
for(int i=0; i<3; i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
gl_Layer = lr;
EndPrimitive();
}
//fragment is empty
EDIT:
Thanks to everyone for help! My problem is solved now, here is my geometry shader:
#version 150 core
uniform int lr;
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
void main(void){
//pass-thru!
for(int i=0; i<3; i++)
{
gl_Layer = lr;
gl_Position = gl_in[i].gl_Position;
EmitVertex();
}
EndPrimitive();
}
gl_Layer, like all geometry shader outputs is a per-vertex output. Which vertex controls the layer for a particular primitive is implementation-defined. In your case, there's no reason not to set it in your loop, before the EmitVertex call.
I haven't actually used gl_Layer before, but looking at the documentation, it sounds like it is a per-vertex attribute (which is odd...).
The actual layer used will come from one of the vertices in the primitive being shaded
So try to set the value inside the for loop, before the EmitVertex, maybe?