Android图形系统介绍及SurfaceView、GLSurfaceView、TextureView、SurfaceTexture、EGLSurface的区别和使用场景

本文深入探讨Android图形系统,解析数据流从View到屏幕的过程,涉及Surface、BufferQueue、Layer和SurfaceFlinger。同时,详细阐述SurfaceView、GLSurfaceView、TextureView、SurfaceTexture和EGLSurface的区别与应用场景,帮助理解在多媒体开发中如何选择合适的组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

之前一直好奇一件事当我们把View控件渲染之后Android系统底层是如何把view显示到屏幕上面的。当同时打开多个app时,我们可以看到多个app的内容。Android底层系统到底是如何把多个组件、多个窗口、多个app的界面同时渲染到屏幕上的呢?之前一直在看这方面的知识,发现网上很多都是介绍Android图形系统源码分析的,关于图形系统整个数据流程的理论分析过程很少。最近又搜刮了大量播客,也找到了好多优质的博文,自己也总结下Android图形系统数据流过程的分析。最后也介绍下在应用层多媒体开发中常用的SurfaceView、GLSurfaceView、TextureView、SurfaceTexture、EGLSurface的使用场景和区别。

二、Android图形系统数据流分析

先上图,通过图先大致了解下Android图形系统数据流程:
在这里插入图片描述

Android图形系统遵循着生产者消费者模型。生产者主要包括:View、OpenGL ES、MediaPlayer等。消费者主要是Surface。无论是View的绘制,还是OpenGL ES的绘制,或者播放器对视频数据的渲染,app进程最终数据流都会流向Surface。

Surface

Surface 是一个窗口。一个App中常见的Surface窗口是:状态栏、导航栏、Activity的根View DecorView、PopupWindow等。状态栏、导航栏、Activity的根View DecorView、PopupWindow最终的绘制都会把数据渲染到各自的Surface上。Surface最终把数据放到BufferQueue。BufferQueue也是典型的生产者/消费者模型,负责连接Surface、Layer。最终我们app层渲染到Surface的数据到达了Layer层。

BufferQueue

BufferQueue 类将可生成图形数据缓冲区的组件(生产方)连接到接受数据以便进行显示或进一步处理的组件(使用方)。几乎所有在系统中移动图形数据缓冲区的内容都依赖于 BufferQueue。图形生产者先向BufferQueue申请GraphicBuffer,填充完GraphicBuffer后,将GraphicBuffer移交给BufferQueue,BufferQueue会通知图形消费者(比如SurfaceFlinger、OMX等)有新的图形数据可以使用,图形消费者就可以从BufferQueue取出GraphicBuffer,使用完之后放回到BufferQueue以便循环使用。一般图形生产者和消费者是在不同进程中,BufferQueue采用了binder和共享内存机制,因此可以高效地在进程间传递图形数据。官方提供的BufferQueue模型图:

Layer

Layer是SurfaceFlinger进行合成的基本操作单元。Layer在应用请求创建Surface的时候在SurfaceFlinger内部创建,因此一个Surface对应一个Layer。Layer其实是一个FrameBuffer,每个FrameBuffer中有两个GraphicBuffer记作FrontBuffer和BackBuffer。

SurfaceFlinger

SurfaceFlinger负责先把所有注明GPU合成的Layer合成到一个输出Buffer,然后把这个输出Buffer和其他Layer(注明HWCOMPOSER合成的Layer)一起交给HWCOMPOSER,让HWCOMPOSER完成剩余Layer的合成和显示
官方提供的Android图像系统视频流管线:

三、SurfaceView、GLSurfaceView、TextureView、SurfaceTexture、EGLSurface的区别和使用场景

SurfaceView:

SurfaceView 虽然本质上属于View,但它与View不同的是它拥有自己的Surface。我们上面介绍了Android图形系统的时候介绍过DecorView内部拥有一个Surface,而SurfaceView脱离DecorView拥有自己的Surface。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。
在这里插入图片描述

GLSurfaceView:

由于SurfaceView在游戏、视频等场景中使用的比较多,而这些游戏、视频场景中经常使用OpenGL对视频、游戏进行处理。从Android 1.5(API level 3)开始加入,作为SurfaceView的补充,Android官方提供了GLSurfaceView。GLSurfaceView在SurfaceView的基础上增加对OpenGL上下文及窗口的管理。我们可以直接在GLSurfaceView中操作OpenGL。当然GLSurfaceView也有他的不足,由于系统底层已经帮我们实现好了OpenGL上下文及窗口的管理,所以他的扩展性有些不足。所以我们常见的音视频场景是往往自己构建OpenGL上下文及窗口,SurfaceView+EGL+OpenGL。

SurfaceTexture:

SurfaceTexture 是 Surface 和 OpenGL ES (GLES) 纹理的组合。SurfaceTexture 用于提供输出到 GLES 纹理的 Surface。SurfaceTexture 包含一个应用是其使用方的 BufferQueue。当生产方将新的缓冲区排入队列时,onFrameAvailable() 回调会通知应用。然后,应用调用 updateTexImage(),这会释放先前占有的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。
SurfaceTexture经常使用的场景就是把视频流从Surface 转换为OpenGL 纹理,这样我们就可以通过OpenGL对视频流进行二次处理了。

TextureView:

TextureView必须在硬件加速的场景中使用。TextureView底层实现就是View + SurfaceTexture。它和SurfaceView不同,它没有属于自己的Surface,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。
无论是SurfaceView还是TextureView,它们的作用都是为了显示视频流。TextureView与SurfaceView虽然底层实现的原理上不同,但是TextureView也经常使用在视频场景中。TextureView最常用的用法是获取TextureView里的SurfaceTexture,通过把SurfaceTexture转换成Surface,再把Surface转换成EGLSurface。后面我们在通过OpenGL处理完视频流后就可以把视频流渲染到EGLSurface显示了。

EGLSurface:

Android 使用 OpenGL ES (GLES) API 渲染图形。为了创建 GLES 上下文并为 GLES 渲染提供窗口系统,Android 使用 EGL 库。GLES 调用用于渲染纹理多边形,而 EGL 调用用于将渲染放到屏幕上。
在使用 GLES 进行绘制之前,您需要创建 GL 上下文。在 EGL 中,这意味着要创建一个 EGLContext 和一个 EGLSurface。 GLES 操作适用于当前上下文,该上下文通过线程局部存储访问,而不是作为参数进行传递。渲染代码应该在当前 GLES 线程(而不是界面线程)上执行。
EGLSurface 可以是由 EGL 分配的离屏缓冲区(称为“pbuffer”),也可以是由操作系统分配的窗口。调用 eglCreateWindowSurface() 函数可创建 EGL 窗口 Surface。 eglCreateWindowSurface() 将“窗口对象”作为参数,在 Android 上,该对象是 Surface。Surface 是 BufferQueue 的生产方。使用方(SurfaceView、SurfaceTexture、TextureView 或 ImageReader)创建 Surface。当您调用 eglCreateWindowSurface() 时,EGL 将创建一个新的 EGLSurface 对象,并将其连接到窗口对象的 BufferQueue 的生产方接口。此后,渲染到该 EGLSurface 会导致一个缓冲区离开队列、进行渲染,然后排队等待使用方使用。

一个 Surface 一次只能与一个 EGLSurface 关联(您只能将一个生产方连接到一个 BufferQueue),但是如果您销毁该 EGLSurface,它将与该 BufferQueue 断开连接,并允许其他内容连接到该 BufferQueue。
通过更改“当前”EGLSurface,指定线程可在多个 EGLSurface 之间进行切换。一个 EGLSurface 一次只能在一个线程上处于当前状态。

EGL 不是 Surface 的另一方面(如 SurfaceHolder)。EGLSurface 是一个相关但独立的概念。您可以在没有 Surface 作为支持的 EGLSurface 上绘制,也可以在没有 EGL 的情况下使用 Surface。EGLSurface 仅为 GLES 提供一个绘制的地方。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值