Android使用Direct Textures提高glReadPixels、glTexImage2D性能

2023-11-13

from:https://www.jianshu.com/p/1fa36461fc6f

Android使用Direct Textures提高glReadPixels、glTexImage2D性能

96 
熊皮皮 
2017.02.05 15:52*  字数 706  阅读 4093 评论 17 喜欢 11

本文档描述改善glReadPixels读取帧缓冲区数据在华为等使用Mali GPU的手机上速度慢的办法。因产品要求应用支持最低平台为Android 4.1,故无法通过Pixel Buffer Object(OpenGL ES 3.0接口,需Android 4.3)提高glReadPixels性能。那么,剩下就一种办法:使用Direct Textures(EGLImage),这是EGL拓展,适用于需要经常更新纹理数据的场合,比如逐帧更新。可用于OpenGL ES 1.0及2.0

代码示例

Direct Textures用glEGLImageTargetTexture2DOES接口替代glReadPixels,它依赖于GraphicBuffer数据结构。算法描述如下:

  • 指定宽高及像素格式初始化GraphicsBuffer
  • 锁定
  • 读写纹理数据
  • 解锁

值得注意的是,一旦解锁,写入的数据将立即反馈在屏幕上。

初始化代码示例如下:

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <android/native_window.h>
#include <ui/GraphicBuffer.h>
#include <dlfcn.h>
// .......
GraphicBuffer* buffer = new GraphicBuffer(1024/*width*/, 1024/*height*/, 
                                          PIXEL_FORMAT_RGB_565,
                                          GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                                          GraphicBuffer::USAGE_HW_TEXTURE);

unsigned char* bits = NULL;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, (void**)&bits);
// Write bitmap data into 'bits' here
buffer->unlock();

// Create the EGLImageKHR from the native buffer
EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE };
EGLImageKHR img = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
                                    EGL_NATIVE_BUFFER_ANDROID,
                                    (EGLClientBuffer)buffer->getNativeBuffer(),
                                    eglImgAttrs);

// Create GL texture, bind to GL_TEXTURE_2D, etc.

// Attach the EGLImage to whatever texture is bound to GL_TEXTURE_2D
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img);

1、使用glEGLImageTargetTexture2DOES替换glTexImage2D或glTexSubImage2D。

// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, EGLImage);

2、使用glEGLImageTargetTexture2DOES替换glReadPixels。

// glReadPixels(0, 0, 
//              textureWidth, textureHeight, 
//              GL_RGBA, 
//              GL_UNSIGNED_BYTE, 
//              dataReadFromFramebuffer);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, pEGLImage);

值得注意的是,由于glReadPixels及其等价函数默认读取后台帧缓冲区,故需要在eglSwapBuffers前调用这些函数。

根据android 下使用Direct Texture,Android 3.0等老版本因Android EGL库存在缺陷,故需手工加载Mali等GPU驱动。在3.0之后,此问题被修复,因而直接用eglGetProcAddress替代dlopen更为简单,完整示例代码如下所示。

const char* const driver_absolute_path = "/system/lib/egl/libEGL_mali.so";
// On Gingerbread you have to load symbols manually from Mali driver because
// Android EGL library has a bug.
// From  ICE CREAM SANDWICH you can freely use the eglGetProcAddress function.
// You might be able to get away with just eglGetProcAddress (no dlopen). 
// Try it,  else revert to the following code
void* dso = dlopen(driver_absolute_path, RTLD_LAZY);
if (dso != 0)
{
    LOGI("dlopen: SUCCEEDED");
    _eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)dlsym(dso, "eglCreateImageKHR");
    _eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) dlsym(dso,"eglDestroyImageKHR");
}
else
{
    LOGI("dlopen: FAILED! Loading functions in common way!");
    _eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
    _eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
}
 
if(_eglCreateImageKHR == NULL)
{
    LOGE("Error: Failed to find eglCreateImageKHR at %s:%in", __FILE__, __LINE__);
    exit(1);
}
if(_eglDestroyImageKHR == NULL)
{
    LOGE("Error: Failed to find eglDestroyImageKHR at %s:%in", __FILE__, __LINE__);
    exit(1);
}
_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
if(_glEGLImageTargetTexture2DOES == NULL)
{
    LOGI("Error: Failed to find glEGLImageTargetTexture2DOES at %s:%in", __FILE__, __LINE__);
    return 0;
}
     
graphicBuffer = new GraphicBuffer(width, height,
            HAL_PIXEL_FORMAT_RGBA_8888,
            GraphicBuffer::USAGE_HW_TEXTURE |
            GraphicBuffer::USAGE_HW_2D |
            GRALLOC_USAGE_SW_READ_OFTEN |
            GRALLOC_USAGE_SW_WRITE_OFTEN);

status_t err = graphicBuffer->initCheck();
if (err != NO_ERROR)
{
    LOGI("Error: %sn", strerror(-err));
    return 0;
}

GGLSurface t;
graphicBuffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
memset(t.data, 128, t.stride * t.height);
graphicBuffer->unlock();

// Retrieve andorid native buffer
android_native_buffer_t *anb = graphicBuffer->getNativeBuffer();
// create the new EGLImageKHR
const EGLint attrs[] =
{
    EGL_IMAGE_PRESERVED_KHR, 
    EGL_TRUE,
    EGL_NONE, 
    EGL_NONE
};

mEngine.mTexture.pEGLImage = _eglCreateImageKHR(eglGetCurrentDisplay(),
                                                mEngine.nContext, 
                                                EGL_NATIVE_BUFFER_ANDROID, 
                                                (EGLClientBuffer)anb, 
                                                attrs);
if(mEngine.mTexture.pEGLImage == EGL_NO_IMAGE_KHR)
{
    LOGI("Error: eglCreateImage() failed at %s:%in", __FILE__, __LINE__);
    return 0;
}
checkGlError("eglCreateImageKHR");
// Create Program等常规初始化操作

编译环境

由于Android NDK不暴露以上接口,意味着使用Direct Textures需要下载Android源码,编译并打包成动态库。接着,通过dlopen或eglGetProcAddress获取eglCreateImageKHR等接口的地址,再进行调用。

编译时包含头文件:

LOCAL_C_INCLUDES +=
    $(ANDROID_SRC_HOME)/frameworks/base/core/jni/android/graphics 
    $(ANDROID_SRC_HOME)/frameworks/base/include/
    $(ANDROID_SRC_HOME)/hardware/libhardware/include
    $(ANDROID_SRC_HOME)/system/core/include
    $(ANDROID_SRC_HOME)/frameworks/base/native/include/
    $(ANDROID_SRC_HOME)/frameworks/base/opengl/include/

链接选项:

LOCAL_LDLIBS := -llog -lGLESv2 -lEGL -landroid  -lui -landroid_runtime  -ljnigraphics

存在的问题

根据火狐(Mozilla Firefox)工程师2011年的博客:using direct textures on android,使用Direct Textures因需要调用dlopen接口,Adreno和Mali等GPU驱动不允许常规应用这么操作。

If you’ve ever used the Android NDK, it won’t be surprising that GraphicBuffer (or anything similar) doesn’t exist there. In order to use any of this in your app you’ll need to resort to dlopen hacks. It’s a pretty depressing situation. Google uses this all over the OS, but doesn’t seem to think that apps need a high performance API. But wait, it gets worse. Even after jumping through these hoops, some gralloc drivers don’t allow regular apps to play ball. So far, testing indicates that this is the case on Adreno and Mali GPUs. Thankfully, PowerVR and Tegra allow it, which covers a fair number of devices.

此时可尝试使用eglGetProcAddress替换dlopen接口。

参考


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android使用Direct Textures提高glReadPixels、glTexImage2D性能 的相关文章

  • StrictMode 策略违规:我的应用程序中存在 android.os.strictmode.LeakedClosableViolation?

    Android 开发新手 第一次在我的应用程序上尝试 StrictMode 我注意到以下内容 并想知道这是否是我的应用程序或库中的问题 我不太清楚 谢谢你 D StrictMode StrictMode policy violation a
  • 在 ViewPager Fragments 中使用 Master/Detail 模板(下载链接)

    工作代码 https github com lukeallison ViewPagerMasterDetail https github com lukeallison ViewPagerMasterDetail Android 主 详细流
  • SearchView过滤ListView

    我已经实现了搜索视图来过滤我的列表视图项目 当我输入任何文本时 它会过滤列表 但当我退出搜索视图时 它不会返回原始列表项 public class PlacesListAdapter extends ArrayAdapter
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • 无法获取log.d或输出Robolectrict + gradle

    有没有人能够将 System out 或 Log d 跟踪从 robolectric 测试输出到 gradle 控制台 我在用Robolectric Gradle 测试插件 https github com robolectric robo
  • Android 中 Kotlin 协程的正确使用方式

    我正在尝试使用异步更新适配器内的列表 我可以看到有太多的样板 这是使用 Kotlin 协程的正确方法吗 这个可以进一步优化吗 fun loadListOfMediaInAsync async CommonPool try Long runn
  • 在 java 类和 android 活动之间传输时音频不清晰

    我有一个android活动 它连接到一个java类并以套接字的形式向它发送数据包 该类接收声音数据包并将它们扔到 PC 扬声器 该代码运行良好 但在 PC 扬声器中播放声音时会出现持续的抖动 中断 安卓活动 public class Sen
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 尝试将相机切换回前面但出现异常

    尝试将相机切换回前面 但出现异常 找不到 问题请检查并帮助 error 01 27 11 49 00 376 E AndroidRuntime 30767 java lang RuntimeException Unable to start
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 我的设备突然没有显示在“Android 设备选择器”中

    我正在使用我的三星 Galaxy3 设备来测试过去两个月的应用程序 它运行良好 但从今天早上开始 当我将设备连接到系统时 它突然没有显示在 Android 设备选择器 窗口中 我检查过 USB 调试模式仅在我的设备中处于选中状态 谁能猜出问
  • 增加活动的屏幕亮度

    显然 Android 操作系统中至少有三种不同的技术可以改变屏幕亮度 其中两个在纸杯蛋糕之后不再起作用 而第三个被接受的技术显然有一个错误 我想在单视图活动开始时增加屏幕亮度 然后在活动结束时将亮度恢复为用户设置 没有按钮 没有第二个视图或
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • Crashlytics 出现 Android Studio 构建错误

    我正在尝试将 CrashLytics 与 Android Studio 和 gradle 一起使用 但出现一个令人困惑的错误 java lang NoSuchMethodError 我的 build gradle 是 buildscript

随机推荐

  • CVE-2022-30190 MSDT远程代码执行漏洞复现

    目录 0x01 声明 0x02 简介 0x03 漏洞概述 0x04 影响版本 0x05 环境搭建 0x06 漏洞复现 是否存在利用点 CMD执行 生成docx文件利用 0x07 CS上线 启动CS服务端 CS客户端连接 设置监听 生成攻击e
  • JAVA 关于static中静态代码块的使用

    与一般静态方法的比较 一般情况下 如果有些代码必须在项目启动的时候就执行的时候 需要使用静态代码块 这种代码是主动执行的 需要在项目启动的时候就初始化 两者的区别就是 静态代码块是自动执行的 静态方法是被调用的时候才执行的 静态方法可以用类
  • 【多线程】ThreadLocal

    目录 简介 底层 set get 回收 简介 线程变量 以ThreadLocal为键 任意对象为值的结构 这个结构被附带在线程上 一个线程根据一个ThreadLocal对象查询到绑定在这个线程上的一个值 本地线程 线程的局部变量 只有当前线
  • 学习少儿编程成为一种必然趋势

    AI人工智能和少儿编程一直是大家热议的话题 在政策引领下 一些城市把人工智能带入中小学教材当中 格物斯坦小坦克认为从编程思维入手 让孩子养成清晰明朗的逻辑思维 在学习 做事各个方面 孩子将来都会得心应手 Scratch编程与其他代码编程 最
  • DS静态查找之折半查找

    题目描述 给出一个队列和要查找的数值 找出数值在队列中的位置 队列位置从1开始 要求使用折半查找算法 输入 第一行输入n 表示队列有n个数据 第二行输入n个数据 都是正整数 用空格隔开 第三行输入t 表示有t个要查找的数值 第四行起 输入t
  • 抓包基本命令

    一 概述 在一个A应用程序内数据有不同的格式如 Integer String等 但是通过网络将数据传输给B应用程序 那么在到达B应用程序之前 数据都将统一解析成数据包 也就是二进制串在网络中传输 在B应用程序前布置一个 网 在这个数据包到达
  • Linux: USB Gadget 驱动简介

    文章目录 1 前言 2 背景 3 USB Gadget 驱动 3 1 什么是 USB Gadget 驱动 3 2 USB Gadget 驱动框架 3 3 USB 设备控制器 UDC 驱动 3 3 1 USB 设备控制器 UDC 驱动 概述
  • Eggjs 从放弃到开始使用

    原文 codesky me archives eg 用掘金刊登虽然分流了但是主要是 现在分享的曝光率实在太低了 所以 支持的请点下原博收藏下关注下以及我的微博 咦 这篇文章标题为什么反了 实际上这是个人走过的心路历程 最初看到 eggjs
  • FastDFS的Tracker及Storage节点添加及删除

    1 增加Storage节点 通过配置 自动加入 1 安装Storage并配置mod fastdfs conf及storage conf 设置fdfs storaged及nginx自启动 2 启动新加的storage节点 会自动同步相同gro
  • openGL之API学习(四)纹理操作

    纹理操作代码流程 向着色器传递纹理单元 glUniform1i gSampler 0 向GPU上传纹理数据 GLuint m textureObj glGenTextures 1 m textureObj 生成一个纹理对象 一个纹理对象有多
  • 谁会嫌钱多啊,最适合打工人小白的Python兼职攻略以及接私活经验!

    这次小编想谈谈一个非常热门的话题 就是如何在学习python的同时去赚钱 在这篇文章中 你会学习到如何通过学习python来赚取副业收入 相信大家都对钱感兴趣吧 如果你和马云爸爸对钱不敢兴趣的话 那这篇文章就不适合你了 如果你想知道如何使用
  • 计算机英语-基础知识

    计算机专业英语基础知识 1 专业英语的专业性和客观性 科技文章属于严肃的书面语体 崇尚严谨周密 逻辑性强 要求层次分明 重点突出 各个领域的专业英语都以表达科技概念 理论和事实为主要目的 因此 它们很注重客观事实和真相 要求逻辑性强 条理规
  • APISIX源码解析-插件-客户端IP【real-ip】

    real ip 客户端IP插件 关键属性 源码解析 real ip 插件用于动态改变传递到 APISIX 的客户端的 IP 和端口 local function get addr conf ctx if conf source http x
  • 卷运维不如卷网络安全

    最近发现很多从事运维的选择了辞职 重新规划自己的职业发展方向 运维工程师这个岗位在IT行业里面确实是处于最底层的 不管什么环节出现问题 基本都是运维背锅 背锅也就罢了 薪资水平也比不上别的岗位 一般运维的薪资水平大多数都是6 9K 还要高频
  • 【Rust】用RefCell避开`&mut XX`导致的借用检查

    derive Debug struct WhatAboutThis lt a gt name String nickname Option lt a str gt impl lt a gt WhatAboutThis lt a gt fn
  • 什么是本地储存?

    本地储存的作用 把一些数据记录在浏览器中 是浏览器提供给我们的一些本地存储数据的机制 localStorage 永久缓存 除非手动删除 sessionStorage 会话缓存 关闭浏览器就没有了 共同点 只能存储字符串格式的数据 local
  • 爬虫最快框架collyx,今天开源了...

    作者 TheWeiJun 工欲善其事 必先利其器 大家好 我是TheWeiJun 之前接触colly时 写过一篇关于colly框架的文章 由于当时能力有限加上时间不够充足 一直没能够去研究这个框架 后来经过3个多月的不断尝试完善 基于col
  • int类型数据相乘,溢出问题,负号变正号

    int相乘 不做强转的话 结果为int 溢出会出现结果不正确的情况 下面方法是个坑儿 如果要使用 需加强转 获取和日期间隔一定时间的时期 适合计算短时间间隔的情况 长时间间隔会出现溢出问题 影响正负号 方法待删除 param d1 para
  • UE4和C++ 开发-新手常用C++API

    C 暴露给蓝图可编辑 UCLASS Blueprintable 创建FString FString Printf TEXT aa bb 蓝图调用变量 UCLASS ClassGroup Custom meta BlueprintSpawna
  • Android使用Direct Textures提高glReadPixels、glTexImage2D性能

    from https www jianshu com p 1fa36461fc6f Android使用Direct Textures提高glReadPixels glTexImage2D性能 熊皮皮 关注 2017 02 05 15 52