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性能 的相关文章

  • 如何制作像 Google+ 应用程序中那样的气泡? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 有谁知道如何使用 Google An
  • 通过代码在创建时突出显示 ListView 项目

    我想在创建 listView 时突出显示 ListView 的第一行 0 我尝试了不同的方法 就像您在注释代码中看到的那样 但没有任何效果 这很奇怪 因为 OnItemClickListener 中的突出显示工作正常 它通过 xml 选择器
  • Android ToggleButton 始终检查

    如果切换按钮处于选中或取消选中状态 我想存储在 SharedPreferences 中 toggle setOnCheckedChangeListener new OnCheckedChangeListener public void on
  • Android:如何暂停和恢复可运行线程?

    我正在使用 postDelayed 可运行线程 当我按下按钮时 我需要暂停并恢复该线程 请任何人帮助我 这是我的主题 protected void animation music6 music4 postDelayed new Runnab
  • Android中将JSON数据存储到本地数据库

    好的 我创建了一个应用程序 它使用 JSON 从我的服务器检索数据 现在我想将检索到的数据存储在手机的本地存储 数据库中 我该怎么做 我是android编程新手 这是我从服务器收到的 JSON messages id 44 issender
  • 音频流的最佳实践

    我正在编写一个应用程序来播放远程服务器的音频 我尝试了多种方法来实现流音频 但它们对我来说都不够好 这就是我尝试过的 幼稚地使用 MediaPlayer 就像是 MediaPlayer player new MediaPlayer play
  • CoordinatorLayout 和 ImageView 在滚动时调整宽度的问题

    我正在尝试放置一个ImageView in a CollapsingToolbarLayout它在加载时占据整个屏幕 并且当您滚动内容时 16x9 分辨率图像宽度会调整大小 直到图像占据屏幕的整个宽度 那时 我希望图像具有视差app lay
  • Android 和 Google 地图内部片段以及其他控件和 viewpager

    我是android编程新手 我有一个带有 3 个页面 片段 的小应用程序 使用 pageradapter 和 viewpager 在它们之间滑动 其中一个页面包含复选框 和其他控件 和地图 我的问题是程序在启动时崩溃 Fragment co
  • 在光标所在行强制关闭!

    嘿 我正在尝试创建一个应用程序来查找存储在 SQlite 数据库中的 GPS 数据 但我面临一个问题 我构建了一个 DbAdapter 类来创建数据库 现在我尝试使用以下函数从另一个类获取所有数据上的光标 public Cursor fet
  • 在 Android 中加密/解密字符串的简单方法

    我的问题是如何加密String String AndroidId Override public void onCreate Bundle savedInstanceState super onCreate savedInstanceSta
  • 如何在android中的谷歌地图上聚焦标记

    我只是想知道我们是否可以关注 Android 应用程序中添加的标记 如果是 怎么办 或者有没有其他方法可以完成这项任务 可以说我使用下面的代码添加了一个标记 map addMarker new MarkerOptions title tit
  • Android:WebView/BaseInputConnection 中的退格键

    我在 Android 4 2 中遇到软键盘退格问题 我在 WebView CodeMirror 中有一个自定义编辑器 它使用一个空的
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • AndEngine MenuScene - 无法单击按钮

    我有一个关于 android 和 andengine 的小问题 这是我的主菜单的源代码 AbstractScene is extending Scene public class MainMenuScene extends Abstract
  • Android Google Map V2:如何在单击另一个标记时更改先前单击的标记的图标

    更新 我通过添加 previousMarker 对象解决了性能问题 因此 只有先前单击的标记将被删除并替换为默认图标 但是 当我单击标记时 信息窗口仍然不显示 我有一个地图视图并在上面设置了一些标记 我想要的是 当我单击一个标记时 它将其图
  • 使用 Proguard 通过 Dropbox.com 库混淆 Android 应用程序

    我刚刚创建了一个需要 Dropbox com API 库的 Android 应用程序 我现在尝试在 发布 模式下构建应用程序 并希望在代码上运行混淆器以对其进行混淆 但是 每当我尝试运行 Proguard 时 都会收到以下错误 Progua
  • Expresso 的 Android 测试首选项片段

    我在通过 Expresso 测试我的代码时遇到问题 我写了这段代码 public class SettingsActivity extends Activity Override protected void onCreate Bundle
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • Android ScrollView,检查当前是否滚动

    有没有办法检查标准 ScrollView 当前是否正在滚动 方向是向上还是向下并不重要 我只需要检查它当前是否正在滚动 ScrollView当前形式不提供用于检测滚动事件的回调 有两种解决方法可用 1 Use a ListView并实施On
  • TabLayout 的不同 tabMode

    我正在使用 ViewPager 和 TabLayout 如果选项卡可以放置在显示 tabMode 上 则它们必须是 app tabMode fixed else app tabMode scrollable 我怎样才能做到这一点 我不明白你

随机推荐

  • 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