OpenGL ES 如何使用 AHardwareBuffer 进行渲染

GraphicBuffer 是Android设计的一种高性能 buffer,其具备一些比较优越的特性,如:

  • 可以在多个进程中传递
  • 可以在多个硬件设备中共享使用,如 CPU、GPU、HWC
  • 可以生成EglImage然后绑定到 Texture 或者 renderBuffer 上

这几个特性可以实现的功能有:

  • 跨进程传递渲染结果
  • 在使用GraphicBuffer绑定纹理时,可以减少CPU和GPU间的数据拷贝

但在GraphicBuffer在使用时存在一个严重的限制,需要在Android源码环境下使用。 


从Android7之后,限制了对GraphicBuffer使用,NDK中不能直接使用GraphicBuffer。

那么是否存在方法通过NDK来间接使用GraphicBuffer?

答案是肯定的,而且存在两种方案:

  • 通过NDK的libnativewindow.so的AHardwareBuffer_allocate方法创建一个AHardwareBuffer
  • 通过EGL的eglCreateNativeClientBufferANDROID扩展来创建一个EGLClientBuffer

下边分别介绍下两种方法

1. 通过 NDK AHardwareBuffer_allocate 创建AHardwareBuffer

首先需要了解下 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;

具体实现代码如下:

#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. 通过 EGL eglCreateNativeClientBufferANDROID 扩展创建EGLClientBuffer

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. 两种实现的优点

  • AHardwareBuffer_allocate不依赖EGL环境
  • eglCreateNativeClientBufferANDROID需要依赖EGL环境

来源:https://blog.csdn.net/m0_54238665/article/details/117136089

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论