Android 显示框架:Surface详解之一_android surface-程序员宅基地

技术标签: android  

1、Surface图形系统概览

Surface是一个显示系统中的组件,无论是在图形系统的结构之中,还是在生产消费模型的流程之中都做作为一个举足轻重的角色,参与整个安卓的显示生命周期之中。

我们摘抄了两段谷歌对surface的描述作为贯穿整个文章的中心:
1.A surface is an interface for a producer to exchange buffers with a consumer.
2.No matter what rendering API developers use, everything is rendered onto a surface. The surface represents the producer side of a buffer queue that is often consumed by SurfaceFlinger. Every window that is created on the Android platform is backed by a surface.

  • 下图是安卓官网对于安卓图形架构组成的说明
    • 其中High-level components 是在编写安卓程序时使用到的具体类,安卓app通过控制这些工具,来间接控制surface在底层的使用。
    • 其中Low-level components 是真正属于在framework层中的图形显示实践。

在这里插入图片描述

  • 下图是整个Low-level components的Graphic Oerview,着重说明了整个显示系统的流转。我们从每个组件,每个箭头来一一分析。
    在这里插入图片描述

我们将整个过程当做一次美术博物馆的展出,便于理解这些组件在显示过程中的作用。

1.1 IMAGE STREAM PRODUCERS

在这里插入图片描述
位于生产消费模型的生产端,所有可以生成buffer data 的内容。读取media中的内容,读取camera中的内容,用NDK生成图像,用OpenGL生成图像等等。他们都可以作为纯粹的画家,也就是内容生产者。
他们既决定Buffer Data中的内容,也同时决定“取景框”Windows的大小位置。

1.2 NATIVE FRAMEWORK

在这里插入图片描述

  • 在native framework层中,libgui负责构建buffer队列,安排buffer的消费者,组织有序的生产和消费流程。
  • 可以理解为“不懂画但是手握画品的拍卖工厂”。

1.3 WINDOW POSITIONING

在这里插入图片描述

  • 大部分显示系统,无论安卓、windows、qnx都会需要一个window管理,用来管理不同buffer的大小、层级、位置等等信息,在一个屏幕中,尽可能的配合所有画面的内容。
  • 相当于“杂志的排版编辑”

1.4 IMAGE STREAM CONSUMERS

在这里插入图片描述

  • 自此真正的消费者出现了,他们根据排版编辑的排列信息,去到拍卖工厂中的GraphicBufferQueue中,整合信息将展览画面传到屏幕中。SurfaceFlinger会与HWC通信,决定由谁来合成layer画面。

1.5 HAL

在这里插入图片描述

  • 硬件部分的内容,HWC是Android中进行窗口(Layer)合成和显示的HAL层模块,Gralloc是用于给graphicbuffer申请内存地址的。

2 Surface的创建

surface在很多层面都有自己的属性,从base到native。由上而下来看看surface到底是怎么创建的。

2.1 构造函数

  • 第一层:java接口调用
    • 位置:/frameworks/base/core/java/android/view/Surface.java
    /**
     * Create an empty surface, which will later be filled in by readFromParcel().
     * @hide
     */
    public Surface() {
    
    }

    /**
     * Create Surface from a {@link SurfaceTexture}.
     *
     * Images drawn to the Surface will be made available to the {@link
     * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
     * SurfaceTexture#updateTexImage}.
     *
     * Please note that holding onto the Surface created here is not enough to
     * keep the provided SurfaceTexture from being reclaimed.  In that sense,
     * the Surface will act like a
     * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture.
     *
     * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
     * Surface.
     * @throws OutOfResourcesException if the surface could not be created.
     */
    public Surface(SurfaceTexture surfaceTexture) {
    
		....
        mIsSingleBuffered = surfaceTexture.isSingleBuffered();
        synchronized (mLock) {
    
            mName = surfaceTexture.toString();
            setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
        }
    }

    /* called from android_view_Surface_createFromIGraphicBufferProducer() */
    private Surface(long nativeObject) {
    
        synchronized (mLock) {
    
            setNativeObjectLocked(nativeObject);
        }
    }

Surface类对外有两个构造方法,对内一种:

  • 第一个是无参构造,实现也是空的,主要是给readFromParcel()反序列化用的
public void readFromParcel(Parcel source) {
    
	...
    synchronized (mLock) {
    
        mName = source.readString();
        mIsSingleBuffered = source.readInt() != 0;
        setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    }
}
  • 第二个是针对GPU绘制内容的,绑定surfacetexture
    • 此时Surface是生产者,SurfaceTexture(Native层对应GLConsumer)是消费者。消费者负责把从BufferQueue中获取的GraphicBuffer转换为纹理,然后业务层可以对纹理进一步处理,例如:上特效或者上屏。
  • 第三个是由android_view_Surface_createFromIGraphicBufferProducer函数调用的,如media/ImageReader中的getsurface方法
static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
{
    
	...
	IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
	...
    // Wrap the IGBP in a Java-language Surface.
    return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
}

2.1.1 setNativeObjectLocked

  • 仔细看上述三个构造函数,无论是私有办法,还是共有办法,都会调用一个函数setNativeObjectLocked(),区别在与参数的不同
    • 私有办法:setNativeObjectLocked(nativeObject);
    • 无参数: setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
    • 绑定surfacetexture:setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
    private void setNativeObjectLocked(long ptr) {
    
        if (mNativeObject != ptr) {
    
            ...
            //只是更新了变量的数值,只是针对不同数据来源的处理
            //其中最重要的是mNativeObject 是一个指向native 层surface的指针
            mNativeObject = ptr;
            ...
        }
    }

2.2 native 层

2.2.1 nativeReadFromParcel

  • 进入native层的第一个内容就是nativeReadFromParcel(mNativeObject, source)
static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject parcelObj) {
    
    Parcel* parcel = parcelForJavaObject(env, parcelObj);
    ...
    android::view::Surface surfaceShim;
    // 解析 Parcel 数据,并填充到 native层 的 Surface对象 surfaceShim
    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
    // 将传入的指针转换为 native层 的 Surface对象 self
    sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
    // 比对 surfaceShim 和 self 中的 Binder 对象 IGraphicBufferProducer
    if (self != nullptr
            && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
                    IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
    
        //  判断是同一个 IGraphicBufferProducer ,直接返回当前指针
        return jlong(self.get());
    }
    sp<Surface> sur;
    if (surfaceShim.graphicBufferProducer != nullptr) {
    
        // IGraphicBufferProducer 不同
        // 且 surfaceShim 的 IGraphicBufferProducer 不为空
        // 创建一个新的 Surface 对象 sur
        sur = new Surface(surfaceShim.graphicBufferProducer, true);
        sur->incStrong(&sRefBaseOwner);
    }
    ...
    // 将 sur 的指针返回给 Java 层
    return jlong(sur.get());
}
  • 传入native层中的surface对象为surfaceshim ,将此内容传入native层的surface中,注意这个surfaceshim需要持有一个graphicBufferProducer以此生成一个新的surface对象。

2.2.2 android_view_Surface_createFromIGraphicBufferProducer

  • 通过bufferProducer建立新的surface对象
jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
        const sp<IGraphicBufferProducer>& bufferProducer) {
    
    if (bufferProducer == NULL) {
    
        return NULL;
    }
    sp<Surface> surface(new Surface(bufferProducer, true));
    return android_view_Surface_createFromSurface(env, surface);
}

2.2.3 nativeCreateFromSurfaceTexture(surfaceTexture)

在这里插入图片描述


static jlong nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
        jobject surfaceTextureObj) {
    
    sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
...
    sp<Surface> surface(new Surface(producer, true));
...
    surface->incStrong(&sRefBaseOwner);
    return jlong(surface.get());
}

2.2.4 native 中的surface构造函数

不难看出所有的surface创建中,都需要一个IGraphicBufferProducer对象作为参数,而IGraphicBufferProducer对象是一个Binder引用对象,BufferQueue的生产者接口,实现类是BufferQueueProducer

  • 注释中还贴心的说明了Surface是ANativeWindow的一种实现,它将图形缓冲区馈送到BufferQueue中
/*
 * An implementation of ANativeWindow that feeds graphics buffers into a
 * BufferQueue.
 */
class Surface
	//ANativeObjectBase,属于模板的一部分
	//class ANativeObjectBase : public NATIVE_TYPE, public REF
    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
public:
    /*
     * creates a Surface from the given IGraphicBufferProducer (which concrete
     * implementation is a BufferQueue).
     *
     * Surface is mainly state-less while it's disconnected, it can be
     * viewed as a glorified IGraphicBufferProducer holder. It's therefore
     * safe to create other Surfaces from the same IGraphicBufferProducer.
     *
     * However, once a Surface is connected, it'll prevent other Surfaces
     * referring to the same IGraphicBufferProducer to become connected and
     * therefore prevent them to be used as actual producers of buffers.
     *
     * the controlledByApp flag indicates that this Surface (producer) is
     * controlled by the application. This flag is used at connect time.
     */
    Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
    
private:
    // mSurfaceTexture is the interface to the surface texture server. All
    // operations on the surface texture client ultimately translate into
    // interactions with the server using this interface.
    // TODO: rename to mBufferProducer
    // native层的Surface将IGraphicBufferProducer对象保存到了mGraphicBufferProducer变量中。
    sp<IGraphicBufferProducer> mGraphicBufferProducer;
  • 继承关系图如下,那么问题来了,mGraphicBufferProducer是从哪里来的呢
    • 第一:直接从 GraphicBufferProducer创建Surface
    • 第二:直接从SurfaceTexture创建
    • 第三:就要从surfaceShim.graphicBufferProducer,也就是上一层来获取
      在这里插入图片描述

2.3 总结

  • 所有surface在native的构建都需要一个graphicbufferproducer作为参数。而这也真好印证了1.2 NATIVE FRAMEWORK中所提到的
    • 在这里插入图片描述
  • surface在java层由三种构建方式,同样对于IGraphicBufferProducer也有不同的渠道获得。
    在这里插入图片描述

参考

https://juejin.cn/post/6944960866404007944

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/vs624010607/article/details/129666617

智能推荐

从零开始搭建Hadoop_创建一个hadoop项目-程序员宅基地

文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目

心脏滴血漏洞HeartBleed CVE-2014-0160深入代码层面的分析_heartbleed代码分析-程序员宅基地

文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析

java读取ofd文档内容_ofd电子文档内容分析工具(分析文档、签章和证书)-程序员宅基地

文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat

基于FPGA的数据采集系统(一)_基于fpga的信息采集-程序员宅基地

文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集

微服务 spring cloud zuul com.netflix.zuul.exception.ZuulException GENERAL-程序员宅基地

文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception

邻接矩阵-建立图-程序员宅基地

文章浏览阅读358次。1.介绍图的相关概念  图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为:  G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图

随便推点

MDT2012部署系列之11 WDS安装与配置-程序员宅基地

文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc

python--xlrd/xlwt/xlutils_xlutils模块可以读xlsx吗-程序员宅基地

文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗

关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题_unresolved attribute reference 'find_element_by_id-程序员宅基地

文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver

DOM对象转换成jQuery对象转换与子页面获取父页面DOM对象-程序员宅基地

文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象

什么是算法?-程序员宅基地

文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法

【网络安全】网络安全的标准和规范_网络安全标准规范-程序员宅基地

文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范