{"id":16799881,"url":"https://github.com/fuyufjh/graphicbuffer","last_synced_at":"2025-07-02T23:33:05.103Z","repository":{"id":53464389,"uuid":"61100482","full_name":"fuyufjh/GraphicBuffer","owner":"fuyufjh","description":"Use GraphicBuffer class from Android native code","archived":false,"fork":false,"pushed_at":"2021-03-30T02:48:41.000Z","size":26,"stargazers_count":202,"open_issues_count":3,"forks_count":52,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-09T01:46:23.096Z","etag":null,"topics":["android"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fuyufjh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-14T07:13:46.000Z","updated_at":"2025-03-28T08:06:06.000Z","dependencies_parsed_at":"2022-08-26T13:30:29.863Z","dependency_job_id":null,"html_url":"https://github.com/fuyufjh/GraphicBuffer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fuyufjh/GraphicBuffer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fuyufjh%2FGraphicBuffer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fuyufjh%2FGraphicBuffer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fuyufjh%2FGraphicBuffer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fuyufjh%2FGraphicBuffer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fuyufjh","download_url":"https://codeload.github.com/fuyufjh/GraphicBuffer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fuyufjh%2FGraphicBuffer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263233244,"owners_count":23434824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android"],"created_at":"2024-10-13T09:30:01.696Z","updated_at":"2025-07-02T23:33:05.014Z","avatar_url":"https://github.com/fuyufjh.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphicBuffer\n\nUse GraphicBuffer class in Android native code in your project, without compiling with Android source code.\n\nThis repository is for APIs 23-27. API 23 is supported without additional tricks, APIs 24-25 need making your application a system application.\n\nAPIs 26 and 27 do not need code from this repository since a more convenient alternative is available: `HardwareBuffer`.\n\nMoreover, this README provides an example of usage of the buffer to obtain a rendered texture image using simple and fast `memcpy()` calls, both for `GraphicBuffer` (API \u003c= 23) and `HardwareBuffer` (API \u003e= 26).\n\nInspired by [tcuAndroidInternals.cpp](https://android.googlesource.com/platform/external/deqp/+/master/framework/platform/android/tcuAndroidInternals.cpp)\n\n# How to use\n\nThe usage is exactly the same with `android::GraphicBuffer` on API \u003c= 25 or `HardwareBuffer` on API \u003e= 26.\nThe example below shows a pseudo-code which renders something to a texture attached to a framebuffer and get the result using simple `memcpy()` calls.\nExamples for both API \u003e= 26 (HardwareBuffer) and API \u003c 26 (GraphicBuffer) are provided.\nIf something doesn't work, it's worth checking if pointers are valid, if `eglGetError()` shows no issues, if there are any errors from Android system and also checking return codes with `glGetError()` if drawing issues occur.\n\nAn example for API \u003c= 25 using this repository, GraphicBuffer:\n```c++\n// for EGL calls\n#define EGL_EGLEXT_PROTOTYPES\n#include \"EGL/egl.h\"\n#include \"EGL/eglext.h\"\n#include \"GLES/gl.h\"\n#define GL_GLEXT_PROTOTYPES\n#include \"GLES/glext.h\"\n\n// Use code from this repository. Note that define __ANDROID_API__ must be set properly for it to work\n// Also add -lEGL at link stage\n#include \"GraphicBuffer.h\" \n\n// bind FBO (create FBO my_handle first!)\nglBindFramebuffer(GL_FRAMEBUFFER, my_handle);\n\n// attach texture to FBO (create texture my_texture first!)\nglFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, my_texture, 0);\n\n// usage for the GraphicBuffer\nint usage = GraphicBuffer::USAGE_HW_RENDER | GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_NEVER;\n\n// create GraphicBuffer\nGraphicBuffer* graphicBuf = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, usage);\n\n// get the native buffer\nauto clientBuf = (EGLClientBuffer) graphicBuf-\u003egetNativeBuffer();\n\n// obtaining the EGL display\nEGLDisplay disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n\n// specifying the image attributes\nEGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};\n\n// creating an EGL image\nEGLImageKHR imageEGL = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf, eglImageAttributes);\n\n// Doing some OpenGL rendering like glDrawArrays\n// Shaders also work, need `#extension GL_OES_EGL_image_external : require`\n// Now the result is inside the FBO my_handle\n\n// binding the OUTPUT texture\nglBindTexture(GL_TEXTURE_2D, my_texture);\n\n// attaching an EGLImage to OUTPUT texture\nglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, imageEGL);\n\n// Obtaining the content image:\n\n// pointer for reading and writing texture data\nvoid *readPtr, *writePtr;\n\n// locking the buffer\ngraphicBuf-\u003elock(GraphicBuffer::USAGE_SW_READ_OFTEN, \u0026readPtr);\n\n// setting the write pointer\nwritePtr = \u003cset to a valid memory area, like malloc(_YOUR_SIZE_)\u003e\n\n// obtaining the stride (for me it was always = width)\nint stride = graphicBuf-\u003egetStride();\n\n// loop over texture rows\nfor (int row = 0; row \u003c height; row++) {\n    // copying, 4 = 4 channels RGBA because of the format above\n    memcpy(writePtr, readPtr, width * 4);\n\n    // adding stride * 4 to read pointer\n    readPtr = (void *)(int(readPtr) + stride * 4);\n\n    // adding width * 4 to write pointer\n    writePtr = (void *)(int(writePtr) + width * 4);\n}\n\n// NOW data is in writePtr memory\n\n// unlocking the buffer\ngraphicBuf-\u003eunlock();\n```\n\nExample for API \u003e= 26. This repository is NOT needed, because there is an open alternative in NDK [1].\nThe example does exactly the same thing as the one above.\n```c++\n// for EGL calls\n#define EGL_EGLEXT_PROTOTYPES\n#include \"EGL/egl.h\"\n#include \"EGL/eglext.h\"\n#include \"GLES/gl.h\"\n#define GL_GLEXT_PROTOTYPES\n#include \"GLES/glext.h\"\n\n// for API \u003e= 26\n// Also add -lEGL -lnativewindow -lGLESv3 at link stage\n#include \"android/hardware_buffer.h\"\n\n// bind FBO (create FBO my_handle first!)\nglBindFramebuffer(GL_FRAMEBUFFER, my_handle);\n\n// attach texture to FBO (create texture my_texture first!)\nglFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, my_texture, 0);\n\n// OUR parameters that we will set and give it to AHardwareBuffer\nAHardwareBuffer_Desc usage;\n\n// filling in the usage for HardwareBuffer\nusage.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;\nusage.height = outputHeight;\nusage.width = outputWidth;\nusage.layers = 1;\nusage.rfu0 = 0;\nusage.rfu1 = 0;\nusage.stride = 10;\nusage.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER\n        | AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;\n\n// create GraphicBuffer\nAHardwareBuffer* graphicBuf;\nAHardwareBuffer_allocate(\u0026usage, \u0026graphicBuf); // it's worth to check the return code\n\n// ACTUAL parameters of the AHardwareBuffer which it reports\nAHardwareBuffer_Desc usage1;\n\n// for stride, see below\nAHardwareBuffer_describe(graphicBuf, \u0026usage1);\n\n// get the native buffer\nEGLClientBuffer clientBuf = eglGetNativeClientBufferANDROID(graphicBuf);\n\n// obtaining the EGL display\nEGLDisplay disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n\n// specifying the image attributes\nEGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};\n\n// creating an EGL image\nEGLImageKHR imageEGL = eglCreateImageKHR(disp, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuf, eglImageAttributes);\n/**\n * @note this part should be earlies than any draw or framebuffer options.\n * @note refer to answer of @solidpixel at https://stackoverflow.com/questions/64447069/use-gleglimagetargettexture2does-to-replace-glreadpixels-on-android\n * @{\n */\n// binding the OUTPUT texture\ngl-\u003eglBindTexture(GL_TEXTURE_2D, my_texture);\n\n// attaching an EGLImage to OUTPUT texture\nglEGLImageTargetTexture2DOES(GL_TEXTURE_2D, imageEGL);\n/**\n * @}\n */\n// Doing some OpenGL rendering like glDrawArrays\n// Shaders also work, need `#extension GL_OES_EGL_image_external_essl3 : require`\n// Now the result is inside the FBO my_handle\n\n// Obtaining the content image:\n\n// pointer for reading and writing texture data\nvoid *readPtr, *writePtr;\n/**\n * @note We must make sure all drawing options finished before read back.\n * @{\n */\n glFinish();\n /**\n * @}\n */\n// locking the buffer\nAHardwareBuffer_lock(graphicBuf, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr, (void**) \u0026readPtr); // worth checking return code\n\n// setting the write pointer\nwritePtr = \u003cset to a valid memory area, like malloc(_YOUR_SIZE_)\u003e\n\n// obtaining the stride (for me it was always = width)\nint stride = usage1.stride;\n\n// loop over texture rows\nfor (int row = 0; row \u003c height; row++) {\n    // copying, 4 = 4 channels RGBA because of the format above\n    memcpy(writePtr, readPtr, width * 4);\n\n    // adding stride * 4 to read pointer\n    readPtr = (void *)(int(readPtr) + stride * 4);\n\n    // adding width * 4 to write pointer\n    writePtr = (void *)(int(writePtr) + width * 4);\n}\n\n// NOW data is in writePtr memory\n\n// unlocking the buffer\nAHardwareBuffer_unlock(graphicBuf, nullptr); // worth checking return code\n```\n\n# How to access private libraries on API 24-25\nOn API 26, there is a public `HardwareBuffer` [1] option which replaces GraphicBuffer hacks. On API \u003c= 23 the hack from the repo worked because the access to private libraries such as `libui.so` was allowed.\n\nIt's still allowed [2] in 24-25, however, `libui.so` also requires `gralloc.exynos5.so` (see full list of its dependencies [3]) which is **not allowed to use on API 24-25**. The app is killed when trying to dlopen `libui.so` (on `new GraphicBuffer()`).\n\nIt seems that there is a solution for API \u003c= 23 and for API \u003e= 26, but on 24 and 25 it seems that it's impossible to use any kind of GraphicBuffer-like access.\n\nThe solution for API 24-25, along with using code from this repository, is to make your application a system application.\nIt requires root privileges.\nThe process is described in https://stackoverflow.com/questions/24641604/qt-application-as-system-app-on-android for Qt-based apps.\n\n# How to tweak API\n\nThe API 23 version in https://github.com/fuyufjh/GraphicBuffer/blob/fa346e1f6266a717758d32aee9c75c85da8a7263/GraphicBuffer.cpp uses the `_ZN7android13GraphicBufferC1Ejjij` constructor symbol, which was replaced by `_ZN7android13GraphicBufferC1EjjijNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE` in API 24-25 (a std::string argument added at the end). This repository works for the API 24-25 as well.\n\nSince I'm not sure if any other APIs have different constructors, below you can find directions on how to tweak the code for your API.\n\n1. Copy your file `/system/lib/libui.so` from your Android device to your PC. This is the file that contains symbol names for `GraphicBuffer`.\n2. Using Android NDK's `nm` for your architecture, run:\n```\n$ /somewhere/android-ndk/find-it/arm-linux-androideabi-gcc-nm -C -D libui.so | grep GraphicBuffer | sort\n```\n\nIt will produce output similar to this:\n\n```\n\u003cother stuff\u003e\n0000de2c T android::GraphicBuffer::GraphicBuffer()\n0000de2c T android::GraphicBuffer::GraphicBuffer()\n0000dec8 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, std::__1::basic_string\u003cchar, std::__1::char_traits\u003cchar\u003e, std::__1::allocator\u003cchar\u003e \u003e)\n0000dec8 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, std::__1::basic_string\u003cchar, std::__1::char_traits\u003cchar\u003e, std::__1::allocator\u003cchar\u003e \u003e)\n0000dfd8 T android::GraphicBuffer::initSize(unsigned int, unsigned int, int, unsigned int, std::__1::basic_string\u003cchar, std::__1::char_traits\u003cchar\u003e, std::__1::allocator\u003cchar\u003e \u003e)\n0000e074 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, unsigned int, native_handle*, bool)\n0000e074 T android::GraphicBuffer::GraphicBuffer(unsigned int, unsigned int, int, unsigned int, unsigned int, native_handle*, bool)\n0000e120 T android::GraphicBuffer::GraphicBuffer(ANativeWindowBuffer*, bool)\n0000e120 T android::GraphicBuffer::GraphicBuffer(ANativeWindowBuffer*, bool)\n\u003cother stuff\u003e\n```\n\nFind a constructor that is suitable for you. Try googling for source code of `GraphicBuffer.cpp` for your API, for example: https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/ui/GraphicBuffer.cpp. Once you have identified the constructor signature you would like to use, find the name of it's symbol in\n\n```\n# same as above but without -C\n$ /somewhere/android-ndk/find-it/arm-linux-androideabi-gcc-nm -D libui.so | grep GraphicBuffer | sort\n```\n\nCopy the name of the symbol, for example: `_ZN7android13GraphicBufferC1EjjijNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE`. It corresponds 1-to-1 to the human-readable signature. For my API 24-25 the difference from API 23 code was that there was an `std::string` argument added.\n\nFor lower APIs (unclear which ones) the solution uses `_ZN7android13GraphicBufferC1Ejjij` which is absent in API 24-25.\n\n3. Having identified your constructor, change the code in `GraphicBuffer.cpp` appropriately. For API 24-25 a `std::string` argument was added, it has to be passed by reference and the variable with the string should remain after function call ends (I just made it `static`).\n4. Debug the code using `print` statements showing error codes\n\n[1] https://developer.android.com/ndk/guides/stable_apis https://developer.android.com/reference/android/hardware/HardwareBuffer\n\n[2] https://developer.android.com/about/versions/nougat/android-7.0-changes\n\n[3] `libbacktrace.so libbase.so libbinder.so libc.so libc++.so libcutils.so libdl.so gralloc.exynos5.so libhardware.so libion.so liblog.so liblzma.so libm.so libsync.so libui.so libunwind.so libutils.so`, obtained by a simple recursive jupyter notebook using `!{readelf_bin} -d {file} | grep NEEDED`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuyufjh%2Fgraphicbuffer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffuyufjh%2Fgraphicbuffer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffuyufjh%2Fgraphicbuffer/lists"}