PDA

View Full Version : Return single integer from fragment shader.



Trionet
08-04-2015, 05:25 PM
Hi I'm using opengl 3.3 and I think I have figured out a way of knowing what triangle I hower with the mouse trough the fragment shader and some stuff in c++. However for this too work I need to return an integer with only the gl_VertexID of the one fragments vertex whose gl_FragCoord casted to int equals the mouse position while rendering the scene. However I'm not sure how to do that or if it is even possible...

I guess I'll have to use a framebuffer with a 1D (or 2D) texture, size 1x1, containing GL_INT:s. Which I guess always gets interpolated to that single pixel. Which I then can get out on like color channel 1??

I guess then we will always have an output value for color channel 1 even if we don't want to set it to anything. So can I get the current value on a specific framebuffer pixel and just use that as output if mouse don't hower the fragment?

Also another thing that is important is that there is some kind of depth buffer so that the closest fragment is the one which index is returned. Maybe that is sorted out by itself if I render normal with the depth buffer since fragments under won't be rendered and override the return value to something that Ain't directly howered?

Also how can I set the value in the 1x1 renderbuffer texture I use in c++ before rendering to like -1 so if that is the value after rendering, nothing was howered?

I really want this to work since it seems like the ultimate way of being able to click stuff.

//Thanks in regards!

GClements
08-04-2015, 06:04 PM
Hi I'm using opengl 3.3 and I think I have figured out a way of knowing what triangle I hower with the mouse trough the fragment shader and some stuff in c++. However for this too work I need to return an integer with only the gl_VertexID of the one fragments vertex whose gl_FragCoord casted to int equals the mouse position while rendering the scene. However I'm not sure how to do that or if it is even possible...
Rather than checking gl_FragCoord, you'd normally just use a 1x1 framebuffer and set the projection matrix to match a single pixel in the default framebuffer.

Or you can render the entire scene into a full-sized framebuffer using IDs rather than colours and just have the client query the specific pixel under the mouse. This may be more efficient if the scene is static and you want to implement mouse-over (rather than mouse-click) picking, as you don't have to re-render whenever the mouse moves. If you're normally rendering into an FBO rather than the default framebuffer, you can write the IDs along with the colour, avoiding the need for a separate pass.

Also, you probably want to be writing gl_PrimitiveID rather than gl_VertexID. When using element arrays, multiple primitives can share vertices, so a vertex ID doesn't uniquely identify the primitive. Also, gl_PrimitiveID is available in the fragment shader, whereas gl_VertexID would have to be propagated explicitly from the vertex shader to the fragment shader (and if you wanted to control which of the primitive's vertices was used, you'd need a geometry shader).



I guess then we will always have an output value for color channel 1 even if we don't want to set it to anything. So can I get the current value on a specific framebuffer pixel and just use that as output if mouse don't hower the fragment?

If no primitives cover the fragment, the framebuffer won't be updated. If the fragment shader is invoked, you can always use a discard statement if you want to avoid writing anything to the framebuffer.



Also how can I set the value in the 1x1 renderbuffer texture I use in c++ before rendering to like -1 so if that is the value after rendering, nothing was howered?

Use glClearBuffer() to clear a buffer to a specific value. This is roughly equivalent to calling glClearColor() then glClear() but is more flexible (i.e. you can clear an integer buffer to a specific value; glClearColor() clamps the values to the 0-1 range).

Trionet
08-05-2015, 05:54 AM
Rather than checking gl_FragCoord, you'd normally just use a 1x1 framebuffer and set the projection matrix to match a single pixel in the default framebuffer.

I didn't quite understand how this would be done.


Or you can render the entire scene into a full-sized framebuffer using IDs rather than colours and just have the client query the specific pixel under the mouse. This may be more efficient if the scene is static and you want to implement mouse-over (rather than mouse-click) picking, as you don't have to re-render whenever the mouse moves. If you're normally rendering into an FBO rather than the default framebuffer, you can write the IDs along with the colour, avoiding the need for a separate pass.

I don't have a static scene. It updates along with a certain framrate at the moment. Having a full sized framebuffer would in this case only be a waste of memory.



Also, you probably want to be writing gl_PrimitiveID rather than gl_VertexID. When using element arrays, multiple primitives can share vertices, so a vertex ID doesn't uniquely identify the primitive. Also, gl_PrimitiveID is available in the fragment shader, whereas gl_VertexID would have to be propagated explicitly from the vertex shader to the fragment shader (and if you wanted to control which of the primitive's vertices was used, you'd need a geometry shader).

I have shaders using both element arrays and vertex arrays. So depending on which i will use gl_PrimitiveID or gl_VertexID and handle it directly after the specific draw calls. Also which of the primitive's vertices was used won't be neccessary as long as I know which triangle the vertex belonged to.

Trionet
08-05-2015, 06:16 AM
What I've tried so far which appears to not work on several levels is the following.

C++
I create the frame buffer as followed in the beginning of the application and use it for the rest of the application.
The purpose is also to write to this one through color channel 1 not 0.



glGenFramebuffers(1, &m_vertex_observer_index_framebuffer_ID);
glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_observer_index_framebuffer_ID);

glGenTextures(1, &m_vertex_observer_index_texture_ID);


glBindTexture(GL_TEXTURE_2D, m_vertex_observer_index_texture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 1,1, 0, GL_COLOR_INDEX, GL_INT, 0);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

//This would be the depth buffer.
//glGenRenderbuffers(1, &m_vertex_observer_index_depthbuffer_ID);
//glBindRenderbuffer(GL_RENDERBUFFER, m_vertex_observer_index_depthbuffer_ID);
//glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1, 1);
//glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_vertex_observer_index_depthbuffer_ID);

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_vertex_observer_index_texture_ID, 1); //I'm very unsure about this.

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
perror("Something went wrong creating the vertex index return value");
return;
}

glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_observer_index_framebuffer_ID);



Note that I try to use GL_DEPTH_ATTACHMENT instead of GL_COLOR_ATTACHMENT. Since depth only has one value, instead of color which I think of like a vec3 or something and I only need one value. Does this even matter or can/should it be done by color?

glCheckFramebufferStatus() doesn't return complete so this apparently doesn't work at all and I don't have much of a clue of what's wrong...

PS of course I delete everything later and clean up.

Vertex Shader


in int gl_VertexID;
out flat int VertexID;
//maybe inout int gl_VertexID would that work?

void main()
{
VertexID = gl_VertexID;
//And of cource all the other stuff with MVP and so on.
}


Fragment Shader


in flat int VertexID;
out vec3 color;
out int index; //this is supposed to be the frame buffer output.

layout (std140) uniform Window // this is a global uniform for window information and works
{
vec2 res; //0
vec2 size; //8
ivec2 curs; //16
};

main{
//Color stuff, lightning etc.

if(int(gl_FragCoord.x) == curs.x || int(gl_FragCoord.y) == curs.y) // this works
index = VertexID; //So if not this, the frame buffer won't be given anything
}


However both vertex and fragment shader gives "error C7538: OpenGL does not allow 'flat' after 'inout'". And I don't know what to do about it sinc if I don't have flat It gives me another error which flat is required.

So some help would be appreciated :)

GClements
08-05-2015, 07:26 AM
I create the frame buffer as followed in the beginning of the application and use it for the rest of the application.

The index buffer should be a colour buffer (i.e. GL_COLOR_ATTACHMENT0). The depth buffer should be a separate texture or renderbuffer.



glCheckFramebufferStatus() doesn't return complete so this apparently doesn't work at all and I don't have much of a clue of what's wrong..

glCheckFramebufferStatus() returns a code which indicates the reason for the framebuffer being incomplete.

One possibility is that the implementation doesn't support GL_DEPTH_COMPONENT32. That isn't a required format. GL_DEPTH_COMPONENT24 and GL_DEPTH24_STENCIL8 are the widest required formats.





in int gl_VertexID;
out flat int VertexID;
//maybe inout int gl_VertexID would that work?


No. "inout" is only valid for function parameters, not global variables (inputs, outputs, uniforms, etc).

gl_VertexID is intrinsically defined; it doesn't need an explicit declaration.





if(int(gl_FragCoord.x) == curs.x || int(gl_FragCoord.y) == curs.y) // this works
index = VertexID; //So if not this, the frame buffer won't be given anything
}


If the fragment shader is invoked for a particular fragment and doesn't execute a "discard" statement, the value of index will be written to the framebuffer for that fragment. If you don't assign index, the value written will be undefined, but something will be written.



However both vertex and fragment shader gives "error C7538: OpenGL does not allow 'flat' after 'inout'". And I don't know what to do about it sinc if I don't have flat It gives me another error which flat is required.

Don't use "inout", use "out" for VertexID and don't declare gl_VertexID.

Trionet
08-05-2015, 12:32 PM
The index buffer should be a colour buffer (i.e. GL_COLOR_ATTACHMENT0). The depth buffer should be a separate texture or renderbuffer.

Okay about texture and renderbuffer what is the practical differens between them?



If the fragment shader is invoked for a particular fragment and doesn't execute a "discard" statement, the value of index will be written to the framebuffer for that fragment. If you don't assign index, the value written will be undefined, but something will be written.

Okay but then I would need to be able to only discard the index and not color since otherwise nothing except the howered fragment will be rendered. How do I do that?


I considered all your tips and it helped and I learned alot. Thank you!

Now it compiles and renders but I don't get any respons from the framebuffer, in form of changed values ion the texture.

Currently the code looks like followed.

C++


m_vertex_index_value = -1; //-1 for no vertex howered.
glGenFramebuffers(1, &m_vertex_index_framebuffer_ID);
glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_index_framebuffer_ID);

glGenTextures(1, &m_vertex_index_texture_ID);
glBindTexture(GL_TEXTURE_2D, m_vertex_index_texture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 1, 1, 0, GL_RED_INTEGER, GL_INT, &m_vertex_index_value); //I use the int m_vertex_index_value as the data for the whole 1x1 texture.
//That way I will have access to the index easy. Is that correct?
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // This had to do with how depth rendering is handled right?
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); //I've seen these online but don't understand what they do. Not render fragments outside window?
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, m_vertex_index_texture_ID, 0); //This binds the texture to output "layout(location = 1)out int index;" in the frag shader right?


Vertex Shader


flat out int VertexID;
//other outs
void main(){
VertexID = gl_VertexID;
//MVP stuff.
}


Fragment Shader


layout(location = 0)out vec3 color; //normal color output
layout(location = 1)out int index; //m_vertex_index_value should be altered through this.

//lots of ins
void main(){
//color stuff.

if(int(gl_FragCoord.x) == curs.x && int(gl_FragCoord.y) == curs.y){
index = VertexID;
}
else
;// here it should discard. But only index not color. How do I do that?
}


If I cout the m_vertex_index_value every update. It always stays -1 and doesn't change when howering somehting. It should change to the vertex index from the fragment I hower. This is the problem.

I thought that it may be dependent on the 1x1 texture and that it doesn't stretch over the whole window, but only when it gets interpolated over the pixel 0,0. But that doesn't seem to be the case after testing.

Alfonse Reinheart
08-05-2015, 02:27 PM
Okay but then I would need to be able to only discard the index and not color since otherwise nothing except the howered fragment will be rendered. How do I do that?

If a fragment shader output is piped to a framebuffer-attached image (https://www.opengl.org/wiki/Framebuffer#Draw_color_buffers) (which is something you set up well before issuing the rendering command), then unless the fragment is discarded (https://www.opengl.org/wiki/Fragment#Fragment_discard), something will be written to that image by that fragment (and if the fragment is discarded, none of them are written).

The only operations that can prevent writing for a specific output are blending (https://www.opengl.org/wiki/Blending), logical operations (https://www.opengl.org/wiki/Logical_Operation), or write masking (https://www.opengl.org/wiki/Write_Mask). Write masking is static; nothing the FS can do will affect masking state, so either all writes to that buffer will be masked or none of them will be. Logical operations only work for integers framebuffers (normalized or not), but if all you need is a single bitmask, it's possible to use them. Blending would be problematic, as non-normalized integer formats can't use blending.

So generally speaking, you can't.

GClements
08-05-2015, 02:43 PM
Okay about texture and renderbuffer what is the practical differens between them
Both can be attached to a framebuffer, but a texture can also be used as a texture while a renderbuffer can't.

Using a texture is useful for multi-pass processing where one pass renders into a texture then subsequent passes read from it.

For this purpose, either will work. A renderbuffer may be more efficient because it doesn't have to also function as a texture.



Okay but then I would need to be able to only discard the index and not color since otherwise nothing except the howered fragment will be rendered. How do I do that?

Why would you need to do that? If you're doing this while rendering the frame, you'd just write the index for every fragment then read only the desired fragment from the framebuffer afterwards.

If you're rendering to a 1x1 framebuffer, you'd be rendering the portion of the scene corresponding to the fragment which is under the mouse pointer in the full framebuffer.



Now it compiles and renders but I don't get any respons from the framebuffer, in form of changed values ion the texture.


glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 1, 1, 0, GL_RED_INTEGER, GL_INT, &m_vertex_index_value); //I use the int m_vertex_index_value as the data for the whole 1x1 texture.
//That way I will have access to the index easy. Is that correct?

If I cout the m_vertex_index_value every update. It always stays -1 and doesn't change when howering somehting. It should change to the vertex index from the fragment I hower. This is the problem.

The texture has its own memory. The value of m_vertex_index_value is copied into the texture when it's created, but changes to the texture won't be written back to the variable. You need to use glReadPixels() or glGetTexImage() to read the data out of the texture.





if(int(gl_FragCoord.x) == curs.x && int(gl_FragCoord.y) == curs.y){
index = VertexID;


For a 1x1 framebuffer, gl_FragCoord will always be (0.5, 0.5), i.e. the centre of the top-left (and only) pixel.

To render the portion of the scene corresponding to a specific pixel from a larger framebuffer, you would pre-multiply the projection matrix with another matrix to "zoom in" on that pixel. If you were using legacy OpenGL, gluPickMatrix() can be used (and exists for this purpose). If you're using GLM, glm::pickMatrix() can be used. Or you can construct the matrix yourself as:


[ w 0 0 w+2*x-2*sx-1 ]
[ ]
[ 0 h 0 h+2*y-2*sy-1 ]
[ ]
[ 0 0 1 0 ]
[ ]
[ 0 0 0 1 ]

where x,y,w,h are the viewport parameters and sx,sy is the pixel coordinates relative to the lower-left corner of the window.

Trionet
08-05-2015, 02:51 PM
If a fragment shader output is piped to a framebuffer-attached image (https://www.opengl.org/wiki/Framebuffer#Draw_color_buffers) (which is something you set up well before issuing the rendering command), then unless the fragment is discarded (https://www.opengl.org/wiki/Fragment#Fragment_discard), something will be written to that image by that fragment (and if the fragment is discarded, none of them are written).

The only operations that can prevent writing for a specific output are blending (https://www.opengl.org/wiki/Blending), logical operations (https://www.opengl.org/wiki/Logical_Operation), or write masking (https://www.opengl.org/wiki/Write_Mask). Write masking is static; nothing the FS can do will affect masking state, so either all writes to that buffer will be masked or none of them will be. Logical operations only work for integers framebuffers (normalized or not), but if all you need is a single bitmask, it's possible to use them. Blending would be problematic, as non-normalized integer formats can't use blending.

So generally speaking, you can't.

But you still you said logical operations was possible right? It says I can't have blending then :O that is very important! :(

Well so that's sad... Then can I somehow get a value from the frambuffer from the fragment shader or vertex shader? Then I can just ovveride the value with the same as it is!

Trionet
08-05-2015, 03:58 PM
glReadPixels doesn't work very well for me..

If I do the following shouldn't vertexIndex equal -1 then?



glGenFramebuffers(1, &m_vertex_index_framebuffer_ID);
glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_index_framebuffer_ID);

glGenTextures(1, &m_vertex_index_texture_ID);
glBindTexture(GL_TEXTURE_2D, m_vertex_index_texture_ID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, 1, 1, 0, GL_RED_INTEGER, GL_INT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, m_vertex_index_texture_ID, 0);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
perror("Something went wrong creating the vertex index return value");
return;
}

glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_index_framebuffer_ID);



//Lets say lots of other stuff happens like texture value changes etc..
glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_index_framebuffer_ID); //this is importand right?
glBindTexture(GL_TEXTURE_2D, m_vertex_index_texture_ID); //I asume the glDrawPixels and glReadPixels are dependent on binding the right framebuffer. And texture?
int drawValue = -1;
glDrawPixels(1, 1, GL_RED, GL_INT, &drawValue); //I'm unsure about GL_RED though
int vertexIndex;
glReadPixels(0,0,1,1, GL_RED, GL_INT, &vertexIndex);
//vertexIndex should be -1. But it's not, just something random. So what am I doing wrong?






Also it appears that when I'm doing this and do glBindFramebuffer(GL_FRAMEBUFFER, m_vertex_index_framebuffer_ID) every update, the screen turns black. I don't know if I made myself understood but I want to use a framebuffer, along side with the normal render to window with the help of glfw, without breaking the rendering and only render too the framebuffer. Is this possible or will I have to render everything 2 times?? :O Since that isn't very efficient.

GClements
08-05-2015, 05:51 PM
If I do the following shouldn't vertexIndex equal -1 then?



glDrawPixels(1, 1, GL_RED, GL_INT, &drawValue); //I'm unsure about GL_RED though


glDrawPixels() is deprecated, and it can't write integer data.

If you want a test case, upload the value to the texture with glTexSubImage2D() before attaching it to the framebuffer.



I want to use a framebuffer, along side with the normal render to window with the help of glfw, without breaking the rendering and only render too the framebuffer. Is this possible or will I have to render everything 2 times??
You could render into a framebuffer with two "colour" attachments (one for the actual colour, one for the index) then copy the image from the colour buffer to the default framebuffer (i.e. the window).

Bear in mind that if you "render" the index as a separate pass, you're only rendering to a 1x1 pixel framebuffer with a very narrow view cone, so the overhead would be much less than rendering the full view.

But another option is to forget about framebuffers and use a buffer variable (OpenGL 4.3+) or an image (OpenGL 4.2+) to hold the index. In this case, you'd render normally, and if gl_FragCoord.xy matches the pointer position, you'd store the index to the buffer variable or image.

For this to work, you need to specifically enable early fragment tests (with layout(early_fragment_tests) in the shader) so that the shader isn't executed for fragments which fail the depth test. Otherwise, the depth test is performed after the shader has executed, meaning that the index would still be written if the depth test fails. However, enabling early fragment tests means that you can't set gl_FragDepth in the shader, and "discard"ed fragments will cause the stencil buffer to be updated as if the fragment was generated.

Probably the main drawback of using a buffer variable or image is that it requires a relatively recent OpenGL version (at least 4.2), which may be excessive if you don't otherwise require that.

Trionet
08-08-2015, 05:44 AM
You could render into a framebuffer with two "colour" attachments (one for the actual colour, one for the index) then copy the image from the colour buffer to the default framebuffer (i.e. the window).

That was my guess.





But another option is to forget about framebuffers and use a buffer variable (OpenGL 4.3+) or an image (OpenGL 4.2+) to hold the index. In this case, you'd render normally, and if gl_FragCoord.xy matches the pointer position, you'd store the index to the buffer variable or image.

For this to work, you need to specifically enable early fragment tests (with layout(early_fragment_tests) in the shader) so that the shader isn't executed for fragments which fail the depth test. Otherwise, the depth test is performed after the shader has executed, meaning that the index would still be written if the depth test fails. However, enabling early fragment tests means that you can't set gl_FragDepth in the shader, and "discard"ed fragments will cause the stencil buffer to be updated as if the fragment was generated.

Probably the main drawback of using a buffer variable or image is that it requires a relatively recent OpenGL version (at least 4.2), which may be excessive if you don't otherwise require that.


This seems much easier! Also can't come up with any reason for me to set gl_FragDepth. I'll go for this I've always been interested in other opengl 4.x stuff so guess I'll get there soon anyway.

Read about buffer variables at the opengl wiki. It's a single variable stored in a SSBO. An SSBO can be initiated as a Buffer Backed Interface Block, using the buffer​ keyword. Or as a buffer variable however there was no example of how to do it that way. I looked around and couldn't find any. So I guess that's what I need help with now :/ How do I declare a buffer variable?

GClements
08-08-2015, 05:56 AM
How do I declare a buffer variable?
With the "buffer" qualifier on an interface block.

Trionet
08-08-2015, 10:50 AM
Okay I really feel like this post is getting too long :(

But any way tried the SSBO buffer variable. I'm obviously doing something wrong. Here's the code and I just want some respons the see that I get something back from the shader. However I don't. So this is the code.

C++



#define GLOBAL_VERTEX_INDEX_SSBO_INDEX 0;

//Creates the SSBO n the beginning of the program
m_vertex_index = -1;
glGenBuffers(1, &m_vertex_index_SSBO_ID);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), &m_vertex_index, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GLOBAL_VERTEX_INDEX_SSBO_INDEX, m_vertex_index_SSBO_ID);





//This is sopposed to get the value written in the fragment shader and then set it to -1 again.
int retrieveVertexIndexData()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
GLvoid* p = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY); //This is a pointer to the memory of the SSBO?
memcpy(p, &m_vertex_index, sizeof(GLint)); //Data too m_vertex_index.
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLint vertexIndex = m_vertex_index;
m_vertex_index = -1;
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), &m_vertex_index, GL_DYNAMIC_DRAW); //buffer -1 to SSBO again. This seems to work atleast
return vertexIndex;
}




//This is done for the shader program I use.
glShaderStorageBlockBinding(m_program_ID, glGetUniformBlockIndex(m_program_ID, "CursorVertex"), GLOBAL_VERTEX_INDEX_SSBO_INDEX);


Fragment Shader


//Stuff

layout (std430, binding = 0) buffer CursorVertex
{
int index;
};
void main(){
//fragment stuff
index = 2;
}


So I want retrieveVertexIndexData to return 2 just to see that it's working. However It is always -1;

I also noticed that setting index internally works so the change appears between the fragment. Though I can't get the value back too c++ again.

Alfonse Reinheart
08-08-2015, 11:01 AM
Your problem is that SSBO accesses are not like normal writing/reading of buffers. Just because an FS writes to the value does not (by itself) mean that a later FS can read it, nor does it mean that the CPU can read it.

You have to make such writes visible to later processes (https://www.opengl.org/wiki/Memory_Model#Incoherent_memory_access). Normally, OpenGL handles this for you (https://www.opengl.org/wiki/Memory_Model), but SSBOs and Image Load/Store don't do that for performance reasons.

GClements
08-08-2015, 11:07 AM
glShaderStorageBlockBinding(m_program_ID, glGetUniformBlockIndex(m_program_ID, "CursorVertex"), GLOBAL_VERTEX_INDEX_SSBO_INDEX);



The block index should be retrieved using glGetProgramResourceIndex() with a programInterface parameter of GL_SHADER_STORAGE_BLOCK.

Trionet
08-08-2015, 04:16 PM
Still not working. Same problem as before..........................

Code:
C++
Beginning of program


glGenBuffers(1, &m_vertex_index_SSBO_ID);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), &m_vertex_index, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GLOBAL_VERTEX_INDEX_SSBO_INDEX, m_vertex_index_SSBO_ID);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); //is this right with the visibility?

Retrieve and reset value function
PS. this is done right after draw call and disabling glDisableVertexAttribArrays


int retrieveVertexIndexData()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
GLvoid* p = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY);
memcpy(p, &m_vertex_index, sizeof(GLint));
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
GLint vertexIndex = m_vertex_index;
m_vertex_index = -1;
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), &m_vertex_index, GL_DYNAMIC_DRAW);
return vertexIndex;
}


Does for every shader program


glShaderStorageBlockBinding(m_program_ID, glGetProgramResourceIndex(m_program_ID, GL_SHADER_STORAGE_BLOCK, "CursorVertex"), GLOBAL_VERTEX_INDEX_SSBO_INDEX);



Fragment Shader


//STUFF
layout (std430, binding = 0) buffer CursorVertex
{
int index;
};
void main(){
//FRAGMENT STUFF
index = 2;
}



retrieveVertexIndexData() only returns -1

I've also tried putting glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT) like every where

GClements
08-09-2015, 05:32 AM
Retrieve and reset value function

This doesn't retrieve anything.

First it copies m_vertex_index into the buffer, then it replaces the buffer's data store with one initialised to contain m_vertex_index.

I think you want e.g.:


int retrieveVertexIndexData()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
GLvoid* p = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_WRITE);
GLint vertexIndex = *(GLint*)p;
*(GLint*)p = -1;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
return vertexIndex;
}

[/QUOTE]

Trionet
08-09-2015, 07:34 AM
This doesn't retrieve anything.

First it copies m_vertex_index into the buffer, then it replaces the buffer's data store with one initialised to contain m_vertex_index.

I think you want e.g.:


int retrieveVertexIndexData()
{
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_vertex_index_SSBO_ID);
GLvoid* p = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_READ_WRITE);
GLint vertexIndex = *(GLint*)p;
*(GLint*)p = -1;
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
return vertexIndex;
}

[/QUOTE]

Holy shit this actually works :D Thank U! <333333

Guess this ends the thread :)