Getting a ANativeWindowBuffer from ANativeWindow_Buffer

Getting a ANativeWindowBuffer from ANativeWindow_Buffer

本文关键字:Buffer ANativeWindow from ANativeWindowBuffer Getting      更新时间:2023-10-16

要在Android NDK上快速访问OpenGL ES 2.0纹理像素,我想使用eglCreateImageKHR()扩展。

根据EGL_NATIVE_BUFFER_ANDROID文档:

此扩展允许使用 Android 窗口缓冲区 (结构 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

从我在这条路上发现的情况来看,ANativeWindow_BufferANativeWindowBuffer是完全不同的类型。嗯,它们有些相似,但绝对如此不同,以至于它们不能互换使用。

如果要比较,以下是定义:

  • ANativeWindow_Buffer : http://androidxref.com/4.4.4_r1/xref/prebuilts/ndk/current/platforms/android-18/arch-arm/usr/include/android/native_window.h
  • ANativeWindowBuffer : http://androidxref.com/4.4.4_r1/xref/system/core/include/system/window.h

您会注意到它们有几个共同的字段(widthheightstrideformat(。最大的区别在于ANativeWindow_Buffer包含指向实际数据的指针,而ANativeWindowBuffer包含类型 buffer_handle_t 的不透明句柄。

因此,如果您发现了如何获得ANativeWindow_Buffer,并希望您顺利前往ANativeWindowBuffer,那么您将......应该不会。至少这是我的结论。我认为非常相似的名字只是一种戏弄。

我没有找到从 NDK 代码创建ANativeWindowBuffer的方法。至少在仅使用支持的 API 的情况下,我认为这是不可能的。我的研究是与KitKat合作的。

我发现了这个问题,我认为用更新的信息和发展来回答它可能会很有用,因为我不得不再次查找如何做到这一点,这是谷歌上的第一个答案之一ImageKHR.

这就是获取本机缓冲区以与 ImageKHR 一起使用的方式。您必须"礼貌地"向 gralloc 索要一个,因为您只需打开代表粘合剂和 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. 图形缓冲区.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;
    }
    

引用: