从ANativeWindow_Buffer获取ANativeWindowBuffer

8
为了在Android NDK上快速获得OpenGL ES 2.0纹理像素访问,我想使用eglCreateImageKHR()扩展。根据EGL_NATIVE_BUFFER_ANDROID docs的说明:

此扩展使Android窗口缓冲区(struct ANativeWindowBuffer)可用作EGLImage源。

ANativeWindowBuffer是由本机框架类(如GraphicBuffer)使用的内部struct。不幸的是,由于我正在使用NDK,因此无法直接访问这些类。
NDK的native_window接口允许我将Java Surface对象传递到NDK。然后,我可以使用ANativeWindow_fromSurface()获取一个不透明的ANativeWindow*句柄。有了这个指针,我可以调用ANativeWindow_lock()来填充一个类型为ANativeWindow_Buffer的结构体(注意_)。
如果我尝试使用这个&ANativeWindow_Buffer对象与eglCreateImageKHR()一起使用,它会失败并显示EGL_BAD_NATIVE_WINDOW
我的问题是:如何将ANativeWindow_BuffereglCreateImageKHR()一起使用,或者如何从ANativeWindow_BufferANativeWindow*中获取ANativeWindowBuffer
2个回答

6
从我在这个过程中了解到的内容来看,ANativeWindow_BufferANativeWindowBuffer是完全不同的类型。虽然它们有些相似,但它们确实如此不同,以至于它们不能互换使用。
如果您想进行比较,以下是定义: 您会注意到它们有一些共同的字段(widthheightstrideformat)。最大的区别是ANativeWindow_Buffer包含指向实际数据的指针,而ANativeWindowBuffer包含一个类型为buffer_handle_t的不透明句柄。
因此,如果您已经找到了如何获取ANativeWindow_Buffer,并希望您已经在通往ANativeWindowBuffer的道路上,那么您可能不是这样。至少这是我的结论。我认为非常相似的名称只是一个诱惑。
我没有找到在NDK代码中创建ANativeWindowBuffer的方法。至少只使用支持的API,我认为这是不可能的。我的研究是基于KitKat的。

2
确实,ANativeWindow_Buffer 结构体只在公共 API 中使用,用于封装需要在此返回的字段,并由调用方分配,因此结构体地址本身并不说明其背后的真实对象。关于它们如何相互关联的示例,请查看 https://android.googlesource.com/platform/frameworks/native/+/033f7e8e/libs/gui/Surface.cpp 中的 Surface::lock 方法(特别是 876-880 行)。 - mstorsjo
经过一些黑客技巧,唯一的获取方式是与gr_alloc打交道,它们就在那么深处。 - Luiz Felipe

2
我发现这个问题,我认为用更新的信息和进展来回答它可能会有用,因为我不得不再次查找如何做到这一点,而这是谷歌上ImageKHR的第一个答案之一。
这是如何获取本机缓冲区以与ImageKHR一起使用。您必须“礼貌地”向gralloc请求一个缓冲区,为此,您只需打开代表binder和gralloc之间IPC的linux_kernel文件,它深入内部。
下面演示的技术将使用dlopen获取指向执行此操作的“.so”之一的指针,但由于它是系统内部的,并且使用JNI反射,如果您尝试发布它,则应用程序验证器可能不喜欢它。 您可以通过进一步实施gralloc本身所做的内容来绕过它,它只是编写并读取文件块设备,如果只是fopen调用,则应用程序验证器无法立即检查从实际libui.so或您的代码之间的调用差异,它只进行简单的静态分析。 要执行此操作,您可以只需复制GrAlloc的源代码或按照github项目中所述将libui.so链接到不同的名称。
仅出于完整性考虑,虽然我使用此技术,但在失败的情况下,我使用PBO进行从GPU到CPU的数据传输的回退,但在大多数情况下,PBO具有可接受的性能。 所需的最低限度 我用作参考的完整库 FramebufferNativeWindow.cpp
  1. GraphicBuffer.h

    #pragma once
    
    #include <exception>
    #include <cstdint>
    #include <cerrno>
    
    class DynamicLibrary
    {
    public:
        DynamicLibrary(const char *fileName);
        ~DynamicLibrary();
    
        void *getFunctionPtr(const char *name) const;
    
        DynamicLibrary(const DynamicLibrary &) = delete;
        DynamicLibrary & operator = (const DynamicLibrary &other) = delete;
    
    private:
        void *libHandle;
    };
    
    struct ANativeWindowBuffer;
    
    namespace android
    {
        class GraphicBuffer;
    
        // include/system/window.h
        struct android_native_base_t
        {
            uint32_t magic;
            uint32_t version;
            void* reserved[4];
            void (*incRef)(struct android_native_base_t* base);
            void (*decRef)(struct android_native_base_t* base);
        };
    
        // include/ui/android_native_buffer.h
        struct android_native_buffer_t
        {
            struct android_native_base_t common;
            int32_t width;
            int32_t height;
            int32_t stride;
            int32_t format;
            int32_t usage;
            // ...
        };
    }
    
    // utils/Errors.h
    enum status_t
    { /*ommited, look at the gist */        };
    
    // ui/PixelFormat.h, system/graphics.h
    enum PixelFormat
    { /*ommited, look at the gist */        };
    
    // ui/GraphicBuffer.h
    { /*ommited, look at the gist */        };
    
    class GraphicBuffer
    {
    public:
        // ui/GraphicBuffer.h, hardware/gralloc.h
    
        GraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage);
        ~GraphicBuffer();
    
        status_t lock(uint32_t usage, void** vaddr);
        status_t unlock();
        ANativeWindowBuffer *getNativeBuffer() const;
        uint32_t getStride() const;
    
    private:
        DynamicLibrary library;
        GraphicBufferFunctions functions;
        android::GraphicBuffer *impl = nullptr;
    };
    #include "GraphicBuffer.h"
    

实现方式如下:

  1. GraphicBuffer.cpp

    #include <string>
    #include <cstdlib>
    #include <iostream>
    #include <iostream>
    #include <dlfcn.h>
    
    const int GRAPHICBUFFER_SIZE = 1024;
    
    using std::string;
    
    DynamicLibrary::DynamicLibrary(const char *fileName)
    {
        libHandle = dlopen(fileName, RTLD_LAZY);
        if (!libHandle) throw OpenLibFailedException();
    }
    
    DynamicLibrary::~DynamicLibrary()
    {
        if (libHandle) dlclose(libHandle);
    }
    
    void *DynamicLibrary::getFunctionPtr(const char *name) const
    {
        auto ret = (void *)dlsym(libHandle, name);
        if (ret == nullptr) {
            std::cerr << "Failed to get function " << name << std::endl;
        }
        return ret;
    }
    
    template<typename Func>
    void setFuncPtr(Func *&funcPtr, const DynamicLibrary &lib, const string &symname) {
        funcPtr = reinterpret_cast<Func *>(lib.getFunctionPtr(symname.c_str()));
    }
    
    #if defined(__aarch64__)
    #   define CPU_ARM_64
    #elif defined(__arm__) || defined(__ARM__) || defined(__ARM_NEON__) || defined(ARM_BUILD)
    #   define CPU_ARM
    #elif defined(_M_X64) || defined(__x86_64__) || defined(__amd64__)
    #   define CPU_X86_64
    #elif defined(__i386__) || defined(_M_X86) || defined(_M_IX86) || defined(X86_BUILD)
    #   define CPU_X86
    #else
    #   warning "target CPU does not support ABI"
    #endif
    
    template<typename RT, typename T1, typename T2, typename T3, typename T4>
    RT *callConstructor4(void (*fptr)(), void *memory, T1 param1, T2 param2, T3 param3, T4 param4) {
    #if defined(CPU_ARM)
        // C1 constructors return pointer
        typedef RT* (*ABIFptr)(void*, T1, T2, T3, T4);
        (void)((ABIFptr)fptr)(memory, param1, param2, param3, param4);
        return reinterpret_cast<RT*>(memory);
    #elif defined(CPU_ARM_64)
        // C1 constructors return void
        typedef void (*ABIFptr)(void*, T1, T2, T3, T4);
        ((ABIFptr)fptr)(memory, param1, param2, param3, param4);
        return reinterpret_cast<RT*>(memory);
    #elif defined(CPU_X86) || defined(CPU_X86_64)
        // ctor returns void
        typedef void (*ABIFptr)(void *, T1, T2, T3, T4);
        ((ABIFptr) fptr)(memory, param1, param2, param3, param4);
        return reinterpret_cast<RT *>(memory);
    #else
        return nullptr;
    #endif
    }
    
    template<typename T>
    void callDestructor(void (*fptr)(), T *obj) {
    #if defined(CPU_ARM)
        // D1 destructor returns ptr
        typedef void* (*ABIFptr)(T* obj);
        (void)((ABIFptr)fptr)(obj);
    #elif defined(CPU_ARM_64)
        // D1 destructor returns void
        typedef void (*ABIFptr)(T* obj);
        ((ABIFptr)fptr)(obj);
    #elif defined(CPU_X86) || defined(CPU_X86_64)
        // dtor returns void
        typedef void (*ABIFptr)(T *obj);
        ((ABIFptr) fptr)(obj);
    #endif
    }
    
    template<typename T1, typename T2>
    T1 *pointerToOffset(T2 *ptr, size_t bytes) {
        return reinterpret_cast<T1 *>((uint8_t *) ptr + bytes);
    }
    
    static android::android_native_base_t *getAndroidNativeBase(android::GraphicBuffer *gb) {
        return pointerToOffset<android::android_native_base_t>(gb, 2 * sizeof(void *));
    }
    
    GraphicBuffer::GraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t usage) :
            library("libui.so") {
        setFuncPtr(functions.constructor, library, "_ZN7android13GraphicBufferC1Ejjij");
        setFuncPtr(functions.destructor, library, "_ZN7android13GraphicBufferD1Ev");
        setFuncPtr(functions.getNativeBuffer, library,
                "_ZNK7android13GraphicBuffer15getNativeBufferEv");
        setFuncPtr(functions.lock, library, "_ZN7android13GraphicBuffer4lockEjPPv");
        setFuncPtr(functions.unlock, library, "_ZN7android13GraphicBuffer6unlockEv");
        setFuncPtr(functions.initCheck, library, "_ZNK7android13GraphicBuffer9initCheckEv");
    
        // allocate memory for GraphicBuffer object
        void *const memory = malloc(GRAPHICBUFFER_SIZE);
        if (memory == nullptr) {
            std::cerr << "Could not alloc for GraphicBuffer" << std::endl;
            return;
        }
    
        try {
            android::GraphicBuffer *const gb =
                    callConstructor4<android::GraphicBuffer, uint32_t, uint32_t, PixelFormat, uint32_t>(
                            functions.constructor,
                            memory,
                            width,
                            height,
                            format,
                            usage
                    );
            android::android_native_base_t *const base = getAndroidNativeBase(gb);
            status_t ctorStatus = functions.initCheck(gb);
    
            if (ctorStatus) {
                // ctor failed
                callDestructor<android::GraphicBuffer>(functions.destructor, gb);
                std::cerr << "GraphicBuffer ctor failed, initCheck returned " << ctorStatus <<
                std::endl;
            }
    
            // check object layout
            if (base->magic != 0x5f626672u) // "_bfr"
                std::cerr << "GraphicBuffer layout unexpected" << std::endl;
    
            // check object version
            const uint32_t expectedVersion = sizeof(void *) == 4 ? 96 : 168;
            if (base->version != expectedVersion)
                std::cerr << "GraphicBuffer version unexpected" << std::endl;
    
            base->incRef(base);
            impl = gb;
        } catch (...) {
            free(memory);
            throw;
        }
    }
    
    GraphicBuffer::~GraphicBuffer() {
        if (impl) {
            android::android_native_base_t *const base = getAndroidNativeBase(impl);
            base->decRef(base);
            //no need to call it, decRef will do
            //callDestructor<android::GraphicBuffer>(functions.destructor, impl);
        }
    }
    
    status_t GraphicBuffer::lock(uint32_t usage, void **vaddr) {
        return functions.lock(impl, usage, vaddr);
    }
    
    status_t GraphicBuffer::unlock() {
        return functions.unlock(impl);
    }
    
    /// Here it is, the windowbuffer !!!
    ANativeWindowBuffer *GraphicBuffer::getNativeBuffer() const {
        return functions.getNativeBuffer(impl);
    }
    
    uint32_t GraphicBuffer::getStride() const {
        return ((android::android_native_buffer_t *) getNativeBuffer())->stride;
    }
    

参考文献:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接