# Using a PBO glTexSubImage2D with GL_PIXEL_UNPACK_BUFFER gives GL_INVALID_OPERATION

I plan to develop a tool for realtime video manipulation using C++, QT 4.7.4 and OpenGL and i'm on visual studio 2008. I check many web site but my code doesn't work since I try with PBO. At the moment I imagine a following sequence of steps: 1.load image file into QTimage 2.copy data into PBO with glmapBuffer 3.transfert into a texture with glTextSubImage2D

Is correct ?

And after succes with several image then I'll begin with video.

To see if I din't miss somthing a explaine my code: INIT I use glut so I initialised with :

glutInit(&iArgc, cppArgv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE  | GLUT_ALPHA);
glutInitWindowSize(1000, 1000);
glutInitWindowPosition(500, 10);
glutCreateWindow("Texture");

glEnable(GL_TEXTURE_2D);


In my MAIN:

glGenTextures(1,&texture)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture); // Set as the current texture
// Poor filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);//GL_NEAREST  GL_LINEAR
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//GL_LINEAR_MIPMAP_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

//glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, imageGL.width(), imageGL.height());

glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8,imageGL.width(), imageGL.height(), 0, GL_RGB, GL_UNSIGNED_BYTE,0 );//PIXEL_FORMAT  imageGL.bits()  (GLvoid*)imageGL.bits()   GL_SRGB8_ALPHA8
glBindTexture(GL_TEXTURE_2D, 0);

GLuint pboIds[2];
glGenBuffers(N_MAX_BUFFERS, pboIds);
//for two buffers
glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[iBuffer]);
glBufferData(GL_PIXEL_PACK_BUFFER, DATA_SIZE, NULL, GL_STREAM_DRAW);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);


In a fonction loadImage I do the step 1 and 2:

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

for (int iBuffer = 0; iBuffer < N_MAX_BUFFERS; ++iBuffer)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, pboIds[iBuffer]);
glBufferData(GL_PIXEL_PACK_BUFFER_EXT, DATA_SIZE, NULL, GL_STREAM_DRAW);

void * pPixelsPBO = glMapBuffer(GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY);
// copy original image into the buffer

//(Step 2)
if(pPixelsPBO)
{
memcpy(pPixelsPBO, imageGL.bits(), imageGL.width() * imageGL.height() * 3);// with 4 the program crach
}
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_EXT
glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, 0);


And finally in the glutDisplayFunc():

//step 3
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[Index]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageGL.width(), imageGL.height(), GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 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);

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

//to load the next data from image
// I do the step 1 et 2 at the end


I get only an error on glTexSubImage2D() INVALID_OPERATION means generally format problem but I check many different format.

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.

Some correction:

For the format I change the into GL_BGRA excepte for the internal format of glTexImage2D() I change into GL_RGBA.

so now I have:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,imageGL.width(), imageGL.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE,0 );//PIXEL_FORMAT  imageGL.bits()  (GLvoid*)imageGL.bits()   GL_SRGB8_ALPHA8
...
imageGL = QGLWidget::convertToGLFormat(image);
imageGL = (image.convertToFormat(QImage::Format_ARGB32));
...
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageGL.width(), imageGL.height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);

• Your texture is incomplete; you have a mipmapping TexParameter set but only one mip level defined. Also, if your objective in using a PBO is to speed up the upload, you'll fail miserably if you use GL_RGB source data, because generally the driver will need to do a software emulated format conversion. You'll get much better performance by using GL_BGRA source data and you probably won't need a PBO at all. – Maximus Minimus Jul 17 '19 at 14:58
• I don't understand why I need more than one level. You speak about that ? 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); I'm wandering if I need to do this each time or juste in my main. – sacha legrand Jul 18 '19 at 15:52
• In the code you posted you're using GL_LINEAR_MIPMAP_LINEAR so you need to specify a full mipmap chain. – Maximus Minimus Jul 19 '19 at 0:56