Max & Min in shader

Started by
12 comments, last by Bucky32 18 years, 4 months ago
Are there any efficient methods for retrieving the max and min values being rendered to the framebuffer in a shader? From discussions here on the forums reading all values from the framebuffer doesn't seem so efficient. The values are going to be used for color-normalization.
Advertisement
ARB_imaging provides min and max and also a histogram.
We've looked into that, and glGetMinmax seems to only check pixels being drawn with glDrawPixels. If we're going to do that we need to do a framebuffer readback, and that's exactly what we don't want to do.
Never used gl minmax but you can found more here: http://www.gamedev.net/community/forums/topic.asp?topic_id=293968

Well since shaders are per vertex or per pixel based then you have no other option than reading back some value. However you can read async (ARB_pixel_buffer_object) to speed up.
Yep, we found that thread too, but it didn't return any pixelvalues if we're not using glDrawPixels.

Using a traditional framebuffer readback kills our fps with 50% so the async read looks interesting =)

This is what our code looks like now, however, it doesn't work at all. We get a null-pointer exception:

----

GLuint imageBuffers[2];
glGenBuffers(2, imageBuffers);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[0]);
glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 512 / 2 * sizeof(float), NULL, GL_STREAM_READ);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[1]);
glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 512 / 2 * sizeof(float), NULL, GL_STREAM_READ);

drawSomething();

//Yep, we're using fbo's
glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[0]);
glReadPixels(0, 0, 512, 512/2, GL_BGRA, GL_FLOAT, BUFFER_OFFSET(0));

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[1]);
glReadPixels(0, 512/2, 512, 512/2, GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));

float *pixels1 = new float[512*512*2];
float *pixels2 = new float[512*512*2];

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[0]);
pixels1 = (float*)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
findMinMax(pixels1);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[1]);
pixels2 = (float*)glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
findMinMax(pixels2);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[0]);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[1]);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);

delete[] pixels2;
delete[] pixels1;

-------

As you can see we're rendering to a fbo, is that compatible with this technique?
No one has an idea?

We've tried texture readbacks, but that is also soooo slow. Isn't there some efficient way of keeping track of what's beeing written to the framebuffer? It would be really great if ARB_IMAGING would work for rasterized fragments too...
The pointer that glMapBuffer returns to you is a pointer directly into video memory.

You do not need to allocate space for it (remove the "new float[512*512*2];") and attempting to free that pointer is also a Very Bad Idea(tm) (remove the deletes).

Once you call glUnmapBuffer, the pointer is simply no longer mapped. There is no other cleanup required.
It runs, but we only seem to access 256 values, and they don't contain any info. The buffer we're trying to read from is 512x512.
Instead of calling glReadPixels, why not just render into the FBO directly? It seems like you're trying to do an overly large amount of work for something rather simple. :)
Quote:Original post by Bucky32
It runs, but we only seem to access 256 values, and they don't contain any info. The buffer we're trying to read from is 512x512.
One thing I notice that's odd is you are reading back half the FBO as floats and the other half as unsigned bytes.

Another problem is you are creating the two buffers with enough room for only 256 floats.
Quote:glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[0]);
glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 512 / 2 * sizeof(float), NULL, GL_STREAM_READ);

glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, imageBuffers[1]);
glBufferData(GL_PIXEL_PACK_BUFFER_ARB, 512 / 2 * sizeof(float), NULL, GL_STREAM_READ);
You need 512 * (512/2) * 4 floats if you are reading back as BGRA in floats. And unless you are rendering to a floating-point FBO it's probably a better idea to read the data as unsigned bytes (and allocate enough space in unsigned bytes instead of floats when you create the buffers).

This topic is closed to new replies.

Advertisement