Getting a ANativeWindowBuffer from ANativeWindow_Buffer
Getting a ANativeWindowBuffer from ANativeWindow_Buffer
要在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_Buffer
与eglCreateImageKHR()
一起使用,或者如何从ANativeWindow_Buffer
或ANativeWindow*
获得ANativeWindowBuffer
。
从我在这条路上发现的情况来看,ANativeWindow_Buffer
和ANativeWindowBuffer
是完全不同的类型。嗯,它们有些相似,但绝对如此不同,以至于它们不能互换使用。
如果要比较,以下是定义:
-
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
您会注意到它们有几个共同的字段(width
、height
、stride
、format
(。最大的区别在于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
-
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"
和实现:
-
图形缓冲区.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; }
引用:
- 如何"buffer" UNIX 信号
- 什么是 Direct3D 12.0 上的"Map Default Buffer"?
- VC++ wcscpy_s随机断言"Buffer is too small"
- 将uint8_t*buffer和size_tbufferlen从C++传递到C中的API函数的最佳方式是什么
- boost::asio::buffer 如何遍历字节
- 在 boost::<double>asio::buffer 中使用像 std::vector<std::complex> 这样的参数
- Cppcheck 静态代码分析器实际上可以检测到不太常见的警告(如 "Relative Path Traversal (CWE-23)" 或"Buffer Under-read(CWE-127)")吗
- tf2_ros::Buffer::canTransform() 为现有转换返回 False
- OpenCL/C++ - 返回一个 cl::Buffer 对象
- 如何在方法参数中使用boost :: asio :: buffer
- 尝试运行 NVIDIA FleX 时"buffer overflow detected"
- C++: buffer the cin istream
- 如何将 std::array 转换为 boost::asio::buffer
- 如何从节点本机插件正确创建Buffer对象
- Buffer.BlockCopy Array 2d c++ to C# 共享内存
- opencv imencode() buffer exception
- boost::asio::buffer与矢量结构
- 在类中声明tf2_ros::Buffer时生成错误
- Buffer上次收到Zeromq消息作为类成员
- "no match for ‘operator>>’ in ‘inputFile >> buffer"错误?