Clamped float values in PBO ...

Hello,

I think PBO doesn’t like me :slight_smile: (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_SIZEsizeof(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.

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.

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…

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 :slight_smile:

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 :frowning:

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.

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

Wow cass, you surely are active lately :slight_smile:

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

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

You have it in PM.

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

but they will be clamped if you send:

  1. GL_RGB + GL_FLOAT -> GL_RGBA32F

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_FALSE);

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.

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 :wink: . 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() {                               
" \
        "  gl_Position = ftransform(); 
" \
        "  gl_TexCoord[0] = gl_MultiTexCoord0; 
" \
        "}
";


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

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_FALSE);

  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,&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,GL_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_OFFSET(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, &vertSource,NULL);
  glShaderSourceARB(f, 1, &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 (&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_FALSE);
to make it work.

I have edited the code to repair errors just after sending it :wink:

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

see you.

Aha, even better. On my NVidia Quadro 1600M uncommenting that line definitely makes a difference…

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_FALSE);

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 :slight_smile:

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.

Bug submitted to NVidia (id 436120)