系统之家提供 Windows 系统、Ghost 系统、驱动与常用软件的安全下载及安装教程。 后台管理
📢 欢迎访问系统之家!所有资源均经过安全检测。

Android图形系统之SurfaceTextureSurfaceTexture是离屏渲染和TextureView的核心

发布时间:2026-09-28 | 浏览:1
📥 下载地址(文章开头)
装机神器,可安装一切系统,纯净版,英文版,繁体版 ,精简版,原版等等等
SurfaceTexture是离屏渲染和TextureView的核心,内部包含了一个BufferQueue,可以把Surface生成的图像流,转换为纹理,供业务方进一步加工使用。整个架构如下图所示: 首先,通过Canvas、OpenGL、Camera或者Video Decoder生成图像流。 接着,图像流通过Surface入队到BufferQueue,并通知到GLConsumer。 然后,GLConsumer从BufferQueue获取图像流GraphicBuffer,并转换为纹理。 最后,业务方可以对纹理进一步处理,例如:上特效或者上屏。 下面我们分别看下SurfaceTexture初始化以及图像数据在SurfaceTexture内部的流转。 SurfaceTexture初始化 new SurfaceTexture(textureId) 启动SurfaceTexture初始化,核心逻辑如下所示: SurfaceTexture初始化后,向 GLConsumer 设置了 JNISurfaceTextureContext 监听器,该监听器会回调到Java层 SurfaceTexture.postEventFromNative 方法,进一步回调到注册到SurfaceTexture中的OnFrameAvailableListener监听器,用于通知业务层有新的 GraphicBuffer 入队了。如果业务层对最新的 GraphicBuffer 感兴趣,则调用 updateTexImage 把 GraphicBuffer 更新到纹理,否则啥也不做,忽略一些图形数据。 GLConsumer 是BufferQueue的直接消费者,负责把 GraphicBuffer 转化为纹理。然后通过监听类 wp<FrameAvailableListener> mFrameAvailableListener 通知间接消费者消费纹理。 当间接消费者是 SurfaceFlinger 时,监听类为Layer,Layer进一步通知 SurfaceFlinger 去合成所有Layer,然后上屏。 当间接消费者是 SurfaceTexture 时,监听类为JNISurfaceTextureContext,用于通知Java层新的图像数据可用了。 SurfaceTexture图像数据流转 这块主要看下生产者 Surface 的创建,业务层收到帧可用通知以及更新目标纹理的流程。 基于SurfaceTexture创建生产者Surface 基于纹理ID创建 SurfaceTexture 后,一般会创建Surface,此时Surface是生产者,SurfaceTexture(Native层对应GLConsumer)是消费者。消费者负责把从BufferQueue中获取的GraphicBuffer转换为纹理,然后业务层可以对纹理进一步处理,例如:上特效或者上屏。 作为生产者的Surface通过BufferQueueProducer,向BufferQueue写GraphicBuffer;作为消费者的GLConsumer通过BufferQueueConsumer,从BufferQueue读GraphicBuffer。 根据 SurfaceTexture 创建 Surface 的核心逻辑在Native层:根据SurfaceTexture持有的BufferqueueProducer创建一个Surface对象,并把该对象的地址绑定到Java层 Surface.mNativeObject 变量。核心代码如下所示: 可见,创建Native层 Surface 对象, BufferqueueProducer 参数是必须的,它负责从 BufferQueue 中出队和入队 GraphicBuffer 。 创建好 Surface 后,就可以通过多种方式向Surface绘制图像数据了,例如:Canvas绘制、Camera输出、视频解码器渲染和OpenGL渲染。 下面,我们分两步看下图形数据是怎么更新到目标纹理的? 这里,我们以Canvas绘制为例,看下业务层收到帧可用回调流程,如下所示: Java层OnFrameAvailableListener监听器收到回调后,需要从OpenGL线程调用 updateTexImage 把 GraphicBuffer 更新到纹理。这里的纹理就是我们创建SurfaceTexture时传入的纹理ID,整个更新流程如下所示: OnFrameAvailableListener.onFrameAvailable回调可以发生在任意线程,所以不能在回调中直接调用updateTexImage,而是必须切换到OpenGL线程调用。因为updateTexImage调用链涉及到OpenGL操作,所以必须在GL线程。
📥 下载地址(文章中间)
装机神器,可安装一切系统,纯净版,英文版,繁体版 ,精简版,原版等等等
核心代码是 GLConsumer::updateTexImage : 首先,通过 BufferQueueConsumer 从BufferQueue中获取可用的 BufferItem ,其中包含了 GraphicBuffer 。 然后,基于 GraphicBuffer 创建EglImage及EGLImageKHR。 最后,基于 EGLImageKHR 更新纹理内容。 简单来说,通过 updateTexImage ,我们把最新的图形数据更新到了纹理,至于如何使用纹理,就是业务层的事情了。 基于GraphicBuffer更新OES纹理 上面讲到, updateTexImage 方法最终会把 GraphicBuffer 更新到目标纹理,实际是通过 EglImage 及 EGLImageKHR 实现的,这里我们看下在Android平台上使用 EGLImageKHR 的方式: 纹理目标需要从 GL_TEXTURE_2D 替换为 GL_TEXTURE_EXTERNAL_OES ,例如:glBindTexture、glTexParameteri等函数。 纹理目标需要从 GL_TEXTURE_2D 替换为 GL_TEXTURE_EXTERNAL_OES ,例如:glBindTexture、glTexParameteri等函数。 片元着色器中,声明OES扩展: #extension GL_OES_EGL_image_external : require 。同时,使用 samplerExternalOES 替代 sampler2D 纹理类型。 片元着色器中,声明OES扩展: #extension GL_OES_EGL_image_external : require 。同时,使用 samplerExternalOES 替代 sampler2D 纹理类型。 基于 GraphicBuffer 图形数据,通过 eglCreateImageKHR 创建 EGLImageKHR 。 基于 GraphicBuffer 图形数据,通过 eglCreateImageKHR 创建 EGLImageKHR 。 GraphicBuffer 可以从BufferQueue中获取,也可以lock后获取内存地址,写入图形数据,具体可参考 GraphicBuffer.cpp 。 通过 glEGLImageTargetTexture2DOES 把 EGLImageKHR 填充为纹理数据 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, static_cast(EGLImageKHR)); 最后,使用 eglDestroyImageKHR 销毁 EGLImageKHR 。 创建和销毁 EGLImageKHR 的函数原型如下所示: 具体使用方式可参考 GLConsumer::EglImage::createImage 。 GLConsumer 内部封装了 EglImage 类,负责 GraphicBuffer 、 EGLImageKHR 和OES纹理的处理逻辑,核心代码如下所示: SurfaceTexture是离屏渲染的核心,例如:我们可以把SurfaceTexture设置给Camera接收摄像头图像数据,并转换为OES纹理,然后可以利用OpenGL对OES纹理做进一步特效处理,最后上屏或者录制成视频。所以,理解 SurfaceTexture 底层原理有助于业务层开发和问题排查,希望本文对有心人有所帮助。 Using GL_OES_EGL_image_external on Android EGL_KHR_image_base.txt
📥 下载地址(文章结尾)
装机神器,可安装一切系统,纯净版,英文版,繁体版 ,精简版,原版等等等