How to use GraphicBuffer indirectly through Android NDK

GraphicBuffer is a high-performance buffer designed by Android. It has some superior features, such as:

  1. Can be passed in multiple processes
  2. Can be shared among multiple hardware devices, such as CPU, GPU, HWC
  3. EglImage can be generated and then bound to Texture or renderBuffer

The functions that these features can achieve are:

  1. Pass rendering results across processes
  2. When using GraphicBuffer to bind textures, you can reduce the data copy between CPU and GPU

However, there is a serious limitation when using GraphicBuffer, and it needs to be used in the Android source code environment.
After Android7, the use of GraphicBuffer is restricted, and GraphicBuffer cannot be used directly in NDK.

So is there a way to use GraphicBuffer indirectly through NDK?

The answer is yes, and there are two options:

  1. Create an AHardwareBuffer through the AHardwareBuffer_allocate method of NDK's libnativewindow.so
  2. Create an EGLClientBuffer through EGL's eglCreateNativeClientBufferANDROID extension

The following two methods are introduced separately

1. Create AHardwareBuffer through NDK AHardwareBuffer_allocate

First, you need to understand the AHardwareBuffer_Desc structure

typedef struct AHardwareBuffer_Desc {
    
    
    uint32_t    width;      // width in pixels
    uint32_t    height;     // height in pixels
    uint32_t    layers;     // number of images
    uint32_t    format;     // One of AHARDWAREBUFFER_FORMAT_*
    uint64_t    usage;      // Combination of AHARDWAREBUFFER_USAGE_*
    uint32_t    stride;     // Stride in pixels, ignored for AHardwareBuffer_allocate()
    uint32_t    rfu0;       // Initialize to zero, reserved for future use
    uint64_t    rfu1;       // Initialize to zero, reserved for future use
} AHardwareBuffer_Desc;

The specific implementation code is as follows:


#define LOAD_PROC(NAME, TYPE)                                           \
    NAME = reinterpret_cast<TYPE>(eglGetProcAddress(# NAME))
    // First, load entry points provided by extensions.
    LOAD_PROC(glEGLImageTargetTexture2DOES,
              PFNGLEGLIMAGETARGETTEXTURE2DOESPROC);

    LOAD_PROC(eglGetNativeClientBufferANDROID,
              PFNEGLGETNATIVECLIENTBUFFERANDROID);

    LOAD_PROC(eglCreateImageKHR, PFNEGLCREATEIMAGEKHRPROC);

    LOAD_PROC(glFramebufferTextureMultiviewOVR,
              PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC);

    LOAD_PROC(glFramebufferTextureMultisampleMultiviewOVR,
              PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC);

    // Try creating a 32x32 AHardwareBuffer and attaching it to a multiview
    // framebuffer, with various formats and depths.
    AHardwareBuffer_Desc desc = {
    
    };
    desc.width = 32;
    desc.height = 32;
    desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
                 AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
    const int layers[] = {
    
    2, 4};
    const int formats[] = {
    
    
      AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
      AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
      // Do not test AHARDWAREBUFFER_FORMAT_BLOB, it isn't color-renderable.
    };
    const int samples[] = {
    
    1, 2, 4};
    for (int nsamples : samples) {
    
    
      for (auto nlayers : layers) {
    
    
        for (auto format : formats) {
    
    
          desc.layers = nlayers;
          desc.format = format;
          testEglImageArray(env, desc, nsamples);
        }
      }
    }
}
static void testEglImageArray(JNIEnv* env, AHardwareBuffer_Desc desc,
                              int nsamples) {
    
    

    AHardwareBuffer* hwbuffer = nullptr;
    int error = AHardwareBuffer_allocate(&desc, &hwbuffer);

    // Create EGLClientBuffer from the AHardwareBuffer.
    EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer);

    // Create EGLImage from EGLClientBuffer.
    EGLint attrs[] = {
    
    EGL_NONE};
    EGLImageKHR image =
        eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
                          EGL_NATIVE_BUFFER_ANDROID, native_buffer, attrs);

    // Create OpenGL texture from the EGLImage.
    GLuint texid;
    glGenTextures(1, &texid);
    glBindTexture(GL_TEXTURE_2D_ARRAY, texid);
    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D_ARRAY, image);

    // Create FBO and add multiview attachment.
    GLuint fboid;
    glGenFramebuffers(1, &fboid);
    glBindFramebuffer(GL_FRAMEBUFFER, fboid);
    const GLint miplevel = 0;
    const GLint base_view = 0;
    const GLint num_views = desc.layers;
    if (nsamples == 1) {
    
    
        glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                         texid, miplevel, base_view, num_views);
    } else {
    
    
        glFramebufferTextureMultisampleMultiviewOVR(
            GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texid, miplevel, nsamples,
            base_view, num_views);
    }

    glCheckFramebufferStatus(GL_FRAMEBUFFER);
    //do some render
    
    glDeleteTextures(1, &texid);
    glDeleteFramebuffers(1, &fboid);
    AHardwareBuffer_release(hwbuffer);
}

2. Create EGLClientBuffer through the EGL eglCreateNativeClientBufferANDROID extension

EGLint attrs[] = {
    
    
	EGL_WIDTH, 10,
	EGL_HEIGHT,10,
	EGL_RED_SIZE,8,
	EGL_GREEN_SIZE,8,
	EGL_BLUE_SIZE 8,
	EGL_ALPHA_SIZE,8,
	EGL_NATIVE_BUFFER_USAGE_ANDROID,EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID,
	EGL_NONE };
  
EGLClientBuffer native_buffer = eglCreateNativeClientBufferANDROID(attrs);

// Create EGLImage from EGLClientBuffer.
EGLint attrs[] = {
    
    EGL_NONE};
EGLImageKHR image =
	eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT,
	                 EGL_NATIVE_BUFFER_ANDROID, native_buffer, attrs);

// Create OpenGL texture from the EGLImage.
GLuint texid;
glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_2D_ARRAY, texid);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D_ARRAY, image);

3. The advantages of both implementations

  1. AHardwareBuffer_allocate does not depend on the EGL environment
  2. eglCreateNativeClientBufferANDROID needs to rely on the EGL environment

Guess you like

Origin blog.csdn.net/u010116586/article/details/108111632