AnsweredAssumed Answered

Using PBO is very slow (imx8mqevk)

Question asked by wooyeol Jun on Nov 29, 2018
Latest reply on Dec 4, 2018 by Bio_TICFSL

Hi community

 

I tried to test PBO in imx8mqevk(linux 4.9.51, wayland).

 

Test code is very simple.

 

* Test1: Load Image -> glTexImage2D -> Rendering  : 52fps

* Test2: Load Image -> PBO bind (2PBO) -> glTexSubImage2D -> Rendering :6~7fps

 

The image size is 5120x960

 

I know that in opnegles2.0 I can use gl-extensions for direct mapping. But I have to use GLES3.0 can't use gl-extesnions.

I heard that By using PBO, OpenGL can perform asynchronous DMA transfer between a PBO and a texture object. (OpenGL Pixel Buffer Object (PBO) )

But In my test, using PBO is slower.

 

Below is my code about PBO.  Thank you.

 


glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0, PIX_FORMAT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);


glGenBuffers(2, pboIds);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[0]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[1]);
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);


Timer fpsTimer;
fpsTimer.reset();
cout <<"loop start"<<endl;
int index =0;
int nextIndex = 0;
/// Infinite loop
for (unsigned int i = 0;; i++) {
/// Clear screen
float fFPS = fpsTimer.getFPS();
if(fpsTimer.isTimePassed(1.0f))
{
printf("FPS:\t%.1f\n", fFPS);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

index= (index + 1) % 2;
nextIndex = (index + 1) % 2;

#if 1 // do not use PBO
//glBindTexture(GL_TEXTURE_2D, textureId);
//glTexImage2D(GL_TEXTURE_2D, 0, 0, 0, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, test[index].data);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0, PIX_FORMAT, GL_UNSIGNED_BYTE, test[index].data);
#else // use PBO


glBindTexture(GL_TEXTURE_2D, textureId);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);

// copy pixels from PBO to texture object
// Use offset instead of ponter.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, PIX_FORMAT, GL_UNSIGNED_BYTE, 0);
// bind PBO to update texture source
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[nextIndex]);

// Note that glMapBuffer() causes sync issue.
// If GPU is working with this buffer, glMapBuffer() will wait(stall)
// until GPU to finish its job. To avoid waiting (idle), you can call
// first glBufferData() with NULL pointer before glMapBuffer().
// If you do that, the previous data in PBO will be discarded and
// glMapBuffer() returns a new allocated pointer immediately
// even if GPU is still working with the previous data.
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
// map the buffer object into client's memory
GLubyte* ptr = (GLubyte*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,DATA_SIZE, GL_MAP_WRITE_BIT);
if(ptr)
{
// update data directly on the mapped buffer
// updatePixels(ptr, DATA_SIZE);
// cout <<"here"<<endl;
// camImage.data = ptr;
// cap >> camImage; // capture displayImage from camera
//cout <<"memcpy"<<endl;
memcpy (ptr, test[index].data, DATA_SIZE);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // release the mapped buffer
}

// it is good idea to release PBOs with ID 0 after use.
// Once bound with 0, all pixel operations are back to normal ways.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

#endif

//glBindTexture(GL_TEXTURE_2D, textureId);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, test.data);

render(1280,720);
/// Swap EGL buffer
eglBufferSwap();

glBindTexture(GL_TEXTURE_2D, 0);
}

Outcomes