Android图像处理系列:离屏GL线程的创建和使用

本文介绍了如何在Android上创建和使用离屏GL线程进行图像处理,通过EGL环境配置,创建EGLContext和EGLSurface,实现后台GPU处理图片,避免了GLSurfaceView在后台执行时的复杂性和限制。离屏渲染可以提高实时性并节省屏幕资源。
摘要由CSDN通过智能技术生成

在Android上做图片或视频帧处理一般有两种方式,一种是在CPU上运行,比如用Matrix类对bitmap做平移、缩放、旋转等变换操作,用OpenCV对图片做格式转换等;另一种是在GPU上运行,一般是通过GLSurfaceView在屏幕上申请一块Surface,调用OpenGL ES API对图片纹理做处理。CPU的图片处理耗时一般是GPU的数十倍,在实时性要求比较高的场景下还是需要用GLSurfaceView来做处理。

OpenGL ES API的调用和执行需要OpenGL上下文环境,而创建OpenGL上下文环境的过程比较复杂,GLSurfaceView的优势就在于它帮助我们封装了创建OpenGL上下文环境所需要的步骤,使我们能够直接在暴露出来的onSurfaceCreatedonSurfaceChangedonDrawFrame回调中调用OpenGL ES API。GLSurfaceView继承自SurfaceView,它是在屏幕上创建了一块可显示的Surface,我们可以把处理后的图像纹理直接显示在这个Surface上。这样的设计可以应对大部分应用场景,但是对少部分场景又存在缺陷。比如我们只是想在后台用GPU处理一些图片,并不需要把它们显示在屏幕上,或者在退后台以后图片处理任务继续执行。当然,用GLSurfaceView也可以解决不显示在屏幕的需求,比如将GLSurfaceView设置成一个像素点,但是如果要实现退后台以后图片处理任务继续执行就很困难了,Activity退出时会触发GLSurfaceView销毁,GLSurfaceView会等待任务执行完成后再销毁相关OpenGL上下文环境,如果任务执行时间过长,会报ANR,所以这种场景下用GLSurfaceView就显得力不从心了。如果我们能脱离GLSurfaceView单独创建一个包含OpenGL上下文环境的线程,并且只做离屏渲染而不将结果渲染到屏幕上,那前面的场景就会好处理很多。本文就从这种实际场景出发介绍一下如何在Android设备上不用GLSurfaceView实现GPU离屏渲染。

GLSurfaceView本质上就是一个包含OpenGL环境的普通线程,在连续渲染模式下或者调用requestRender方法后不断调用OpenGL API将图像数据渲染到它创建的Surface上,其内部实现本来就包含了创建OpenGL上下文环境的所有步骤以及普通线程与OpenGL上下文环境绑定的过程。所以我们要想实现一个离屏渲染的GL线程,本质上就是把这部分实现抽取出来。当然GLSurfaceView创建的可见Surface和离屏渲染创建的不可见Surface是两种不同的类型,这个我们后面再详细介绍。首先我们来看一下一个离屏渲染的GL线程是长什么样子的。

GL线程模板

Android应用中创建线程可以用Java API提供的Thread类和Android系统提供的HandlerThread类,HandlerThread提供了更好的生命周期封装和跨线程调用实现,所以我们以HandlerThread为例来创建一个GL线程。GL线程的基本框架如下所示:

public class SimpleGLThread {
   
    private Handler mHandler;
    private EglCore mCore;
    private OffscreenSurface mOffscreenSurface;

    public SimpleGLThread(String name) {
   
        HandlerThread ht = new HandlerThread(name); //创建线程,未来将包含OpenGL Context成为GL线程
        ht.start();
        mHandler = new Handler(ht.getLooper());     //线程对应的Handler
        mHandler.post(new Runnable() {
   
            @Override
            public void run() {
   
                mCore = new EglCore();              //EGL环境创建和配置
                mOffscreenSurface = new OffscreenSurface(mCore, 100, 100);  //创建离屏渲染Surface
                mOffscreenSurface.makeCurrent();    //绑定EGLContext、EGLSurface和当前线程
            }
        });
    }

    //在该GL线程中运行Runnable,其中可以包含OpenGL ES指令
    public void postJob(Runnable runnable) {
   
        if (mHandler != null) {
   
            mHandler.post(runnable);
        }
    }

    //销毁EGLSurface、EGLContext和相关线程
    public void destroy() {
   
        if (mHandler != null) {
   
            mHandler.post(new Runnable() {
   
                @Override
                public void run() {
   
                    mOffscreenSurface.release(
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值