Using a PBO glTexSubImage2D with GL_PIXEL_UNPACK_BUFFER gives GL_INVALID_OPERATION

Currently I am attempting to use PBOs to get video data to textures.

I file the buffer with glMapBuffer():

 for (int iBuffer = 0; iBuffer < N_MAX_BUFFERS; ++iBuffer)
  {
    // bind pixel-buffer object
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[iBuffer]);

    // create buffer's data container
    glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, NULL, GL_STREAM_DRAW);

    void * pPixelsPBO = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);//GL_WRITE_ONLY
    // copy original image into the buffer
    if(pPixelsPBO)
    {
      //pPixelsPBO = new unsigned char[imageGL.width() * imageGL.height() * 3];
      memcpy(pPixelsPBO, imageGL.bits(), DATA_SIZE);//memcpy
    }
    // unbind pixel-buffer object
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  }

And I display the buffer into the texture with glTexSubImage2D:

    glBindTexture(GL_TEXTURE_2D, texture);

    // bind PBO to update pixel values
    // GL_PIXEL_PACK_BUFFER to transfer pixel data to a PBO
    //GL_PIXEL_UNPACK_BUFFER to transfer pixel data from PBO.
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[nextIndex]);// for nextIndex
    MyLgGetError("glBindBuffer");

    displayeInfo();
    MyLgGetError("displayeInfo");

    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageGL.width(), imageGL.height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);
    MyLgGetError("glTexSubImage2D");

        
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);

this is a correct way to use PBO ?

Going through the list of reasons the error could be generated, this is what I know:
•texture array has been defined
•not executed between glBegin/glEnd

This one I’m not sure about:
•error is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the data would be unpacked from the buffer object such that the memory reads required would exceed the data store size.

This one seems like it could be an issue, but I’d have no idea how else to handle this:
•error is generated if a non-zero buffer object name is bound to the GL_PIXEL_UNPACK_BUFFER target and the buffer object’s data store is currently mapped.

You should call glUnmapBuffer after the memcpy. Unbinding the buffer doesn’t unmap it.

Yes of course sorry I didn’t show you the entire code.

 for (int iBuffer = 0; iBuffer < N_MAX_BUFFERS; ++iBuffer)
  {
    // bind pixel-buffer object
    // GL_PIXEL_PACK_BUFFER to transfer pixel data to a PBO
    //GL_PIXEL_UNPACK_BUFFER to transfer pixel data from PBO.
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[iBuffer]);
    // create buffer's data container
    glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, NULL, GL_STREAM_DRAW);

    void * pPixelsPBO = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);//GL_WRITE_ONLY
    // copy original image into the buffer
    if(pPixelsPBO)
    {
      //pPixelsPBO = new unsigned char[imageGL.width() * imageGL.height() * 3];
      memcpy(pPixelsPBO, imageGL.bits(), DATA_SIZE);//memcpy
    }
    else
    {
      qDebug() << "pPixelsPBO NULL";
    }
    if (!glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER))
    {
      qDebug() << "Couldn't unmap pixel buffer. Exiting";
    }
    // unbind pixel-buffer object
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

Well, that just leaves the size. Is DATA_SIZE equal to (or greater than) imageGL.width() * imageGL.height() * 4?

You don’t actually say what error is being generated by what call; from the context, I’m assuming that glTexSubImage2D is generating GL_INVALID_OPERATION.

when I multiply by 4 my program crach so I put *3 because my image is RGB format but I not sure about format.

I’ll write all about format in my code:

image.load(name)
imageGL = QGLWidget::convertToGLFormat(image);
imageGL = (image.convertToFormat(QImage::Format_RGB888));
...
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8,imageGL.width(), imageGL.height(), 0, GL_RGB, GL_UNSIGNED_BYTE,imageGL.bits() );
...
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageGL.width(), imageGL.height(), GL_RGB, GL_UNSIGNED_BYTE, 0);

Do you know what is the better format from QT to OpenGL when I do image.convertToFormat(…) ?

Well, the original version of your code used:

And GL_BGRA uses 4 bytes per pixel.

If the buffer contains 3 bytes per pixel, use GL_RGB or GL_BGR. But unless the image width is a multiple of 4 (or the image data is padded so that each row is a multiple of 4 bytes), you also need to call

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

before the glTexImage2D or glTexSubImage2D calls. The default unpack alignment is 4, meaning that each row is assumed to be aligned to a multiple of 4 bytes.

Ok so that work with 4 bits in any case interresting but I’m completely lost beacause why my programme crach when I multiply by 4 so ?

So I change many things about format for my image:

imageGL = QGLWidget::convertToGLFormat(image);
imageGL = (image.convertToFormat(QImage::Format_ARGB32));

  glBindTexture(GL_TEXTURE_2D, texture); // Set as the current texture

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_NEAREST  GL_LINEAR
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexImage2D(GL_TEXTURE_2D, 0, **GL_BGRA**,imageGL.width(), imageGL.height(), 0, **GL_BGRA**, GL_UNSIGNED_BYTE,imageGL.bits() 
  glBindTexture(GL_TEXTURE_2D, 0);

  // Now create the corresponding PBOs
  for (int iBuffer = 0; iBuffer < N_MAX_BUFFERS; ++iBuffer)
  {
// bind pixel-buffer object
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[iBuffer]);
// create buffer's data container
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, NULL, GL_STREAM_DRAW);

void * pPixelsPBO = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
// copy original image into the buffer
if(pPixelsPBO)
{
  memcpy(pPixelsPBO, imageGL.bits(), DATA_SIZE);//memcpy
}
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  }

    glClear(GL_COLOR_BUFFER_BIT);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[Index]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageGL.width(), imageGL.height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);

    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    glPushMatrix();

      glBindTexture(GL_TEXTURE_2D, texture);
      glColor4f(1, 1, 1, 1);

      glBegin(GL_QUADS);  
      glTexCoord2i(0,0); glVertex2i(0,imageGL.height());
      glTexCoord2i(0,1); glVertex2i(0,0);
      glTexCoord2i(1,1); glVertex2i(imageGL.width(),0);
      glTexCoord2i(1,0); glVertex2i(imageGL.width(),imageGL.height());
      glEnd();

      glBindTexture(GL_TEXTURE_2D, 0);
      glDisable(GL_TEXTURE_2D);
      glPopMatrix();
      glutSwapBuffers();

Ok this is almost my entire main loop in order to display my image.
I change all the format into GL_BGRA for the fonction glTexImage2D() and glTexSubImage2D() and convert my Qimage into Format_ARGB32, it’s seems the best but I don’t know.

GL_BGRA is not a valid internal format. It is only usable as a pixel-transfer format. You should have gotten an OpenGL error when you did that.

Exact ! I did’nt saw that !
So I change into :

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,imageGL.width(), imageGL.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE,imageGL.bits() );

But now I still have my error on glTexSubImage2D() INVALID_OPERATION.

Thanks for your help ! I’m on it since so many times that I becom completly lost about that !