This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Usage of android GraphicBuffer instead of glReadPixels on SGS3 with Mali 400 MP4

Hello,

My application needs to retrieve a lot of data from GPU. So, as once recommended on ARM dev forums, I use android GraphicBuffer for this purpose as glReadPixels slows down the process quite heavily (by approx. 10 ms per frame, which is disastrous at 30 fps). But, when I render something into it and then try to read it via GraphicBuffer, the memory pointed at the address I get with buffer->lock() contains only partially updated image data (e.g. some of the pixels contain the data from the last draw call, and another pixels contain the data which was in that texture before I made the draw call).

So, here is what I do:

1) Create android graphics buffer

  int format = PIXEL_FORMAT_RGBA_8888;
  int usage = GraphicBuffer::USAGE_HW_TEXTURE |
  GRALLOC_USAGE_SW_READ_OFTEN |
  GRALLOC_USAGE_SW_WRITE_RARELY;
  EGLClientBuffer clientBuffer = nullptr;
  buffer = new android::GraphicBuffer(width, height, format, usage);
  clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();

2) Create EglKHR image with this buffer attached to it

EGLint eglImgAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE};
  img = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
  EGL_NATIVE_BUFFER_ANDROID,
  (EGLClientBuffer) clientBuffer,
  eglImgAttrs);

3) Attach Egl KHR image to texture

glGenTextures(1, &androidTextureId);

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, androidTextureId);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

  // Attach the EGLImage to whatever texture is bound to GL_TEXTURE_2D
  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img);
  glBindTexture(GL_TEXTURE_2D, 0);

4) Then, I get frames from camera which are rendered into external texture, which I render into framebuffer to which graphicsBuffer-backed texture is attached

  glBindFramebuffer(GL_FRAMEBUFFER, framebufferId);
  glViewport(0, 0, width, height);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, androidTextureId, 0);
  //render here, I've skipped it

  glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 );
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

5) Then, I call glFinish(), lock the graphicsBuffer for reading and load it's data into another texture I'll write on the screen later, just to check that everything is ok.

  glFinish();
  void *memPtr;
  buffer->lock(mode, &memPtr);
  glActiveTexture(GL_TEXTURE0);
  glPixelStorei(GL_PACK_ALIGNMENT, 1);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glBindTexture(GL_TEXTURE_2D, textureToRenderId);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, buffer->stride, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, memPtr);
  unlockGraphicsBuffer();

  //render here, I've skipped it
  glBindTexture(GL_TEXTURE_2D, 0);
  glUseProgram(0);

6) Then, I write zeros to graphicBuffer-backed texture (by writing into it's graphicBuffer counterpart) so I'll clearly see the artifacts. If I skip this step, the artifacts are still present but harder to notice, because two sequential camera frames look similar unless you move the device quite quickly.

This code works absolutely fine on many another devices of different vendors, with one of the problematic devices being Samsung S3 mentioned above.

There was a similar problem on lenovo vibe x2 with PowerVR G6400 gpu (which occured because PowerVR ignores glFinish on newer models completely), and was fixed by addition of fence sync objects before locking the buffer.

For devices which don't support opengl es 3.0, I call only glFinish(), and for SGS3 this doesn't work for some reason

Could anyone please tell what can be wrong with this code?

I can email you the sample project with this problem or provide any other additional info.

Thank you.

Parents
  • Hi sfairat,

    I have the same problem. In my case libMali.so does not contain a string "REVISION", so I am unable to tell you the driver version, but it is a Mali-450 MP4.

    In conjunction with frank.lei's advice, where glFinish is substituted with EGL synchronization primitive, when locking the GraphicBuffer, I use

    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN
    

    In my usecase I only need GRALLOC_USAGE_SW_READ_OFTEN, since there is only reading going on. For whatever reason, locking also with GRALLOC_USAGE_SW_WRITE_OFTEN, seem to solve the problem. To be honest, I am not sure if this is related at all, because in my case the artifacts appear rarely. It may be just a coincidence, that the extra bit of work introduced removes the concurrency issue.

    In your post it is unclear with what usage mode you are locking the buffer, but I would assume it is GRALLOC_USAGE_SW_WRITE_RARELY.

Reply
  • Hi sfairat,

    I have the same problem. In my case libMali.so does not contain a string "REVISION", so I am unable to tell you the driver version, but it is a Mali-450 MP4.

    In conjunction with frank.lei's advice, where glFinish is substituted with EGL synchronization primitive, when locking the GraphicBuffer, I use

    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN
    

    In my usecase I only need GRALLOC_USAGE_SW_READ_OFTEN, since there is only reading going on. For whatever reason, locking also with GRALLOC_USAGE_SW_WRITE_OFTEN, seem to solve the problem. To be honest, I am not sure if this is related at all, because in my case the artifacts appear rarely. It may be just a coincidence, that the extra bit of work introduced removes the concurrency issue.

    In your post it is unclear with what usage mode you are locking the buffer, but I would assume it is GRALLOC_USAGE_SW_WRITE_RARELY.

Children
No data