Cómo usar GraphicBuffer indirectamente a través de Android NDK

GraphicBuffer es un búfer de alto rendimiento diseñado por Android. Tiene algunas características superiores, como:

  1. Puede pasarse en múltiples procesos
  2. Se puede compartir entre varios dispositivos de hardware, como CPU, GPU, HWC
  3. EglImage se puede generar y luego enlazar a Texture o renderBuffer

Las funciones que pueden lograr estas características son:

  1. Transmitir resultados de renderizado a través de procesos
  2. Al usar GraphicBuffer para unir texturas, puede reducir la copia de datos entre la CPU y la GPU

Sin embargo, existe una seria limitación al usar GraphicBuffer, y debe usarse en el entorno de código fuente de Android.
Después de Android7, el uso de GraphicBuffer está restringido y GraphicBuffer no se puede usar directamente en NDK.

Entonces, ¿hay alguna manera de usar GraphicBuffer indirectamente a través del NDK?

La respuesta es sí y hay dos opciones:

  1. Cree un AHardwareBuffer a través del método AHardwareBuffer_allocate de libnativewindow.so del NDK
  2. Cree un EGLClientBuffer a través de la extensión eglCreateNativeClientBufferANDROID de EGL

Los dos métodos siguientes se presentan por separado

1. Cree AHardwareBuffer a través de NDK AHardwareBuffer_allocate

Primero, debe comprender la estructura AHardwareBuffer_Desc

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;

El código de implementación específico es el siguiente:


#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. Cree EGLClientBuffer mediante la extensión EGL eglCreateNativeClientBufferANDROID

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. Las ventajas de ambas implementaciones

  1. AHardwareBuffer_allocate no depende del entorno EGL
  2. eglCreateNativeClientBufferANDROID necesita depender del entorno EGL

Supongo que te gusta

Origin blog.csdn.net/u010116586/article/details/108111632
Recomendado
Clasificación