PDA

View Full Version : Clamped float values in PBO ...



djedge@ogl
06-11-2008, 08:22 AM
Hello,

I think PBO doesn't like me :) (see my other topic named "PBO and Texture Float")

I try (yet!) to upload floating textures using PBO. The transfer works good but I have a problem with clamped values.

My texture internal format is GL_RGB16F_ARB. It means that texture values can be outside [0...1]. Without PBO, I have no problem to read real values either (< 0) or (> 1). With PBO, when I read texture values from fragment shader, all values are in [0...1]. In other words, texture values are clamped to [0...1] when PBO uploading is used.

I use the following arguments for PBO :

glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, pboid[0]);
glBufferData(GL_PIXEL_UNPACK_BUFFER_EXT, DATA_SIZE*sizeof(float), 0, GL_STREAM_DRAW);
GLvoid* ptr1 = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
copy(ptr1,myTexFloat,DATA_SIZE)
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT,0,0,0,z,w, h,1,GL_RGB,GL_FLOAT,BUFFER_OFFSET(0));

But I don't how to specify internal format for PBO. I haven't found any thread or doc talking about PBO internal format ... It seems to be GLbyte, but I think that the problem comes from the transfert CPU to GPU made by OpenGL driver.

Any ideas to make PBO values unclamped ?

Thanks a lot.

djedge@ogl
06-11-2008, 01:57 PM
I found the extension : ARB_color_buffer_float

http://developer.download.nvidia.com/opengl/specs/GL_ARB_color_buffer_float.txt

I don't have my computer to try it (my laptop is too old ;))! It seems to be what I need. If you have experience with this extension ...

Thank you.

Zengar
06-11-2008, 02:36 PM
There is no such thing as PBO internal format. Loading a texture from a PBO (a region of server-managed memory) is conceptually no different then loading it from client memory. No idea why it is clamped, maybe you messed up the internal format of your texture...

djedge@ogl
06-11-2008, 02:49 PM
I don't think so ... texture values are unclamped when I don't use PBO (so internal format is good I guess). I agree with you, I see no difference conceptually between PBO and client-side way ! But, with PBO, the data transfert is up to OpenGL driver and I have no idea of what it is done during this stage ... probably a clamp somewhere !

PBO are strongly correlated with VBO. AFAIK, vertex positions in VBO are not clamped !!! This is why I hope that a solution can be find with PBO :)

Zengar
06-11-2008, 03:11 PM
Well, PBO and VBO are basically the same... the difference is the binding point for the buffer. No data transformation should take place when transferring to server-side memory. Still, I have no clue what can be your problem, sorry :(

djedge@ogl
06-11-2008, 04:00 PM
I have tried a minimal program with GL_TEXTURE_2D and ATI video card and it works with unclamped values ...

I can't try now with NVidia video card and GL_TEXTURE_2D_ARRAY_EXT (as previously defined) but as soon as can, I will tell you where my bug is : NVidia driver or GL_TEXTURE_2D_ARRAY_EXT (or me :)).

Thanks for your help.

cass
06-11-2008, 06:24 PM
What is the glTexImage*() call you make on this object? That's the command that defines the internal format of the texture.

// This will convert your 3-component float data into whatever the
// internal format of the texture is when it's allocated.
glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT,0,0,0,z,w, h,1,GL_RGB,GL_FLOAT,BUFFER_OFFSET(0));

Zengar
06-11-2008, 11:18 PM
Wow cass, you surely are active lately :)

-NiCo-
06-12-2008, 12:21 AM
I have tried a minimal program with GL_TEXTURE_2D and ATI video card and it works with unclamped values

If it's Linux-compatible code I'd be happy to test it for you.

djedge@ogl
06-12-2008, 02:35 AM
What is the glTexImage*() call you make on this object? That's the command that defines the internal format of the texture.

// This will convert your 3-component float data into whatever the
// internal format of the texture is when it's allocated.
glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT,0,0,0,z,w, h,1,GL_RGB,GL_FLOAT,BUFFER_OFFSET(0));


As I said, I use GL_RGB16F_ARB as internal format. My glTexImage3D declaration looks like :

glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGB16F_ARB, WIDTH, HEIGHT, DEPTH, 0, GL_RGB, GL_FLOAT, 0);

djedge@ogl
06-12-2008, 03:01 AM
If it's Linux-compatible code I'd be happy to test it for you.

You have it in PM.

-NiCo-
06-12-2008, 03:59 AM
It looks like you were on the right track. The problem is the conversion step from external type to internal type. If the external type and format exactly matches the internal type and format, there is no special interpretation for the values and they will be sent 'as is' to the GPU. Therefore, the values will be unclamped if you send

1. GL_RGBA + GL_FLOAT -> GL_RGBA32F
2. GL_RGBA + GL_HALF_FLOAT -> GL_RGBA16F
3. ...

but they will be clamped if you send:

1. GL_RGB + GL_FLOAT -> GL_RGBA32F
2. ...

As far as I can tell, this behavior is not consistent with the spec. Anyway, you were right that the GL_ARB_color_buffer_float extension can help. Just put in
glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE);

djedge@ogl
06-12-2008, 04:26 AM
I don't know the behavior of : GL_RGB + GL_FLOAT -> GL_RGBA32F

I think that an error can appears, something like INVALID_ENUM. However, I use GL_RGB{16|32}F with [ GL_RGB, GL_FLOAT ] so the values should be unclamped.

I'm not sure about GL_ARB_color_buffer_float extension ... It seems to be for frame buffer (or COLOR_BUFFER) and not for texture values. I will try it as soon as I can.

-NiCo-
06-12-2008, 04:39 AM
Trust me, it works with the GL_ARB_color_buffer_float extension extension. I've updated your code, there were a few errors in it like creating the shader as a local variable instead of assigning it to the global variable, forgetting to bind the texture to the shader and uncompilable shader code ;) . Anyway, here it is:



#define BUFFER_OFFSET(i) ((char *)NULL + (i))

#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include <GL/gl.h>

#include <iostream>

using namespace std;

static int width = 800;
static int height = 600;

static GLuint shader;
static GLuint texid;
static GLuint pboid[8];

const char* vertSource = "void main() { \n" \
" gl_Position = ftransform(); \n" \
" gl_TexCoord[0] = gl_MultiTexCoord0; \n" \
"}\n";


const char* fragSource = " uniform sampler2D tex; \n" \
"void main() { \n" \
" vec3 value = texture2D(tex,gl_TexCoord[0].st).rgb; \n" \
" if ( value.x == 2.0 &amp;&amp; value.y == 2.0 &amp;&amp; value.z == 2.0 ) \n" \
" gl_FragColor = vec4(0.0,1.0,0.0,1.0); \n" \
" else \n" \
" gl_FragColor = vec4(1.0,0.0,0.0,1.0); \n" \
"}\n";

void
idle ()
{
glutPostRedisplay ();
}


void
display ()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBindTexture(GL_TEXTURE_2D,texid);

glUseProgramObjectARB(shader);
GLint texloc1 = glGetUniformLocationARB(shader,"tex");
glUniform1iARB(texloc1,0);




glNormal3f(0.f,0.f,1.f);
glColor3f(1.f,1.f,1.f);

glBegin(GL_TRIANGLES);
glTexCoord2f(0.f,1.f); glVertex3f(-1.f,-1.f,-1.f);
glTexCoord2f(1.f,1.f); glVertex3f(1.f,-1.f,-1.f);
glTexCoord2f(0.f,0.f); glVertex3f(-1.f,1.f,-1.f);
glEnd();

glBegin(GL_TRIANGLES);
glTexCoord2f(1.f,1.f); glVertex3f(1.f,-1.f,-1.f);
glTexCoord2f(1.f,0.f); glVertex3f(1.f,1.f,-1.f);
glTexCoord2f(0.f,0.f); glVertex3f(-1.f,1.f,-1.f);
glEnd();

glUseProgramObjectARB(0);
glutSwapBuffers ();
}


void
initGL ()
{
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
cerr << "[PBO] Ready for OpenGL 2.0" << endl;
else {
cerr << "[PBO] OpenGL 2.0 not supported" << endl;
exit(1);
}

glCullFace( GL_BACK );
glEnable( GL_DEPTH_TEST );
glEnable( GL_CULL_FACE );
glEnable( GL_TEXTURE_2D );
glDisable( GL_LIGHTING );
}

void
initTextureAndShader ()
{

//glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE);

const int w = 256;
const int h = 256;

float* gputex = new float[3*w*h];
for ( int i = 0; i < 3*w*h; ++i )
gputex[i] = 2.f;

cerr << "Texture Init OK" << endl;

glGenTextures(1,&amp;texid);
glBindTexture(GL_TEXTURE_2D,texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D,0,GL_RGB16F_ARB,w,h,0,G L_RGB,GL_FLOAT,0);

cerr << "Texture Allocation OK" << endl;

// create PBO ...
glGenBuffers(1,pboid);

cerr << " PBO created ..." << endl;

glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pboid[0]);
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, 3*w*h*sizeof(float), 0,
GL_STREAM_DRAW);

GLvoid* ptr1 = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);

GLfloat* tmp = (GLfloat*) ptr1;
for ( int i = 0; i < 3*w*h; ++i )
tmp[i] = gputex[i];

glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);

glTexSubImage2D( GL_TEXTURE_2D,0,0,0,w,h,GL_RGB,GL_FLOAT,BUFFER_OFF SET(0));

glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

glDeleteBuffers(1,pboid);
delete [] gputex;

cerr << "Texture PBO upload OK" << endl;

GLuint v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
GLuint f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
glShaderSourceARB(v, 1, &amp;vertSource,NULL);
glShaderSourceARB(f, 1, &amp;fragSource,NULL);
glCompileShaderARB(v);
glCompileShaderARB(f);
shader = glCreateProgramObjectARB();
glAttachObjectARB(shader,f);
glAttachObjectARB(shader,v);
glLinkProgramARB(shader);

cerr << "shader OK" << endl;

}


int
main ( int argc, char** argv )
{
glutInit (&amp;argc, argv);
glutInitDisplayMode (GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize (width,height);
glutCreateWindow ("PBO");

glutIdleFunc (idle);
glutDisplayFunc (display);

initGL();
initTextureAndShader();

glutMainLoop ();

return EXIT_SUCCESS;
}



Just uncomment
//glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE);
to make it work.

djedge@ogl
06-12-2008, 04:54 AM
I have edited the code to repair errors just after sending it ;)

But the proper code works without glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE) on my laptop with ATI card. I will try soon on NVidia ... on my computer where the error originally occurs.

see you.

-NiCo-
06-12-2008, 04:57 AM
Aha, even better. On my NVidia Quadro 1600M uncommenting that line definitely makes a difference...

djedge@ogl
06-12-2008, 05:50 AM
You are rightn this is a problem of NVidia drivers !!!!

When I try the minimal code on my GF8800 with lastest linux driver, I have to use : glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE);

but not on ATI graphic card. I think NVidia PBO driver implementation doesn't look the texture internal format before streaming textures and by default, clamp values between 0 and 1.

I'm not crazy there is a real BUG :)

Thanks a lot for your help.

If someone knows how to submit bug to nvidia ... I found 2 bugs in 2 days with PBO !!!

cass
06-12-2008, 06:19 AM
You are rightn this is a problem of NVidia drivers !!!!

When I try the minimal code on my GF8800 with lastest linux driver, I have to use : glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB,GL_FAL SE);

but not on ATI graphic card. I think NVidia PBO driver implementation doesn't look the texture internal format before streaming textures and by default, clamp values between 0 and 1.

I'm not crazy there is a real BUG :)

Thanks a lot for your help.

If someone knows how to submit bug to nvidia ... I found 2 bugs in 2 days with PBO !!!



Glad you found a workaround. I agree it sounds like a driver bug.

Registered developers can file bugs directly into NVIDIA's bugs system, but if you have the email address of an NVIDIA person, that usually works fine too.

Probably Evan Hart (ehart@nvidia.com) would be a good first shot.

Evan and others do watch these forums though.

djedge@ogl
06-12-2008, 03:28 PM
Bug submitted to NVidia (id 436120)