I'm trying to use the GPU for solving an algorithm and I'm using shaders to do so (not compute shaders, just vertex and fragment shaders). For this purpose I need in my fragment shader two output variable for extracting data, I have no problem with input data (that works perfectly) but so far I wasnt able to make it run with two output variable because just one of them is actually working or something weird happens between both of them.
I would also like this question to be like a reference for this practice (several outputs in fragment shader for GPGPU) since what i have seen so far is just specific cases. First I have two textures that I load just once like this:
First Texture
glBindTexture(GL_TEXTURE_2D, texture[4]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, width, height,
0, GL_RED_INTEGER, GL_INT, 0);
Second Texture
glBindTexture(GL_TEXTURE_2D, texture[5]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, width, height,
0, GL_RED_INTEGER, GL_INT, 0);
These two textures are supposed to store my output data (each texture should be a variable out) In both cases I'm using the red component for storing the data as an intenger.
Now I create a framebuffer and bind these two textures to the framebuffer, each texture in a color_attachment.
glGenFramebuffers(1, &resultFBO); // frame buffer id
glBindFramebuffer(GL_FRAMEBUFFER, resultFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture[4], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, texture[5], 0);
Now, as for the fragment shader I set up the location of output variables like this:
layout(location = 0) out int resultFlow;
layout(location = 1) out int resultAccumFlow;
Finally I just call DrawArrays() (in the render loop) after I bind this same framebuffer:
glBindFramebuffer(GL_FRAMEBUFFER, resultFBO);
// Render
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
I am pretty sure that this last step is the one which is not "working" but maybe I need something else. I have tried to look it up but I didnt find any documentation, anyway if there is actually some paper related with this, it would be really helpful.
... but so far I wasnt able to make it run with two output variable because just one of them is actually working ...
When you want to write to multiple target in the fragment shader, then the final step, which you missed, is to specifies a list of color buffers to be drawn into.
This can be done by glDrawBuffers
:
glBindFramebuffer(GL_FRAMEBUFFER, resultFBO);
GLenum drawBuffers[]={GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, drawBuffers);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Hint: You can use glClearBuffer
to clear individual buffers of a framebuffer
See OpenGL 4.6 API Core Profile Specification; 17.4.1 Selecting Buffers for Writing; page 513:
17.4.1 Selecting Buffers for Writing
.....
The set of buffers of a framebuffer object to which all fragment colors are written is controlled with the commands
void DrawBuffers( sizei n, const enum *bufs ); void NamedFramebufferDrawBuffers( uint framebuffer, sizei n, const enum *bufs );
.....
For framebuffer objects, in the initial state the draw buffer for fragment color zero is COLOR_ATTACHMENT0. For both the default framebuffer and framebuffer objects, the initial state of draw buffers for fragment colors other then zero is NONE.