Android NDKを介して間接的にGraphicBufferを使用する方法

GraphicBufferは、Androidによって設計された高性能バッファで、次のような優れた機能を備えています。

  1. 複数のプロセスで渡すことができます
  2. CPU、GPU、HWCなどの複数のハードウェアデバイス間で共有可能
  3. EglImageを生成して、TextureまたはrenderBufferにバインドできます

これらの機能で実現できる機能は次のとおりです。

  1. プロセス間でレンダリング結果を渡す
  2. GraphicBufferを使用してテクスチャをバインドする場合、CPUとGPU間のデータコピーを減らすことができます

ただし、GraphicBufferを使用する場合は重大な制限があり、Androidソースコード環境で使用する必要があります。
Android7以降、GraphicBufferの使用は制限され、GraphicBufferをNDKで直接使用することはできません。

NDKを介して間接的にGraphicBufferを使用する方法はありますか?

答えは「はい」で、2つのオプションがあります。

  1. NDKのlibnativewindow.soのAHardwareBuffer_allocateメソッドを使用してAHardwareBufferを作成します。
  2. EGLのeglCreateNativeClientBufferANDROID拡張機能を使用してEGLClientBufferを作成します

次の2つの方法は別々に導入されます

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.両方の実装の利点

  1. AHardwareBuffer_allocateはEGL環境に依存しません
  2. eglCreateNativeClientBufferANDROIDはEGL環境に依存する必要があります

おすすめ

転載: blog.csdn.net/u010116586/article/details/108111632