文档章节

Android图形显示系统——下层显示3:窗口系统

jxt1234
 jxt1234
发布于 2015/10/15 18:06
字数 1716
阅读 36
收藏 0
点赞 0
评论 0

Android之窗口系统

要点

1.Android窗口系统通过C-S架构和一套Buffer循环机制实现,在保证安全稳定的前提下基本上做到了极致性能(无大块内存拷贝,IPC通信内容最少)。
2.SurfaceFlinger创建Layer,将其中的BufferQueueProducer作为IGraphicBufferProducer传给应用侧的Surface,因而构成窗口。
3.Surface是皮,BufferQueue是肉,通过这样的皮肉关系构建了Buffer循环机制。Buffer循环机制不仅用于窗口系统,也用于视频播放解码流,相机拍照数据流等(Camera2.0架构)。

注:代码基于Android 5.0

窗口系统接口

作为一个应用,绘图是自由的,基本上也是平台无关的。但如果要把绘图的结果显示出来,就必须依赖平台提供的窗口系统。好比我们写篇文章出来容易,要投到杂志上发表,就必须按杂志社的格式,并通过审校等一堆流程,不然每个人都随便发,肯定乱套了。

Android的窗口系统设计

窗口类型
Android为应用层提供的窗口接口为ANativeWindow。这个接口可用来调整配置参数,获取图形内存并送还触发显示。应用层是Buffer的生产者。
对于非GPU绘图的应用,通过这个类去获取图形内存(dequeueBuffer),并在绘制完成之后送还(queueBuffer),让显示系统在合适的时机显示。
对于GPU绘图(严格来说,是使用EGL标准)的应用,在创建OpenGL上下文时将ANativeWindow的指针传入,GPU的驱动会在合适的时候完成获取内存和送还的操作。应用层只需要调用eglSwapBuffers换缓存即可。

Android的Windows接口

对应用层开放的windows接口定义在
system/core/include/system/windows.h
主要接口函数如下:

struct ANativeWindow
{
    /*......*/
    int     (*setSwapInterval)(struct ANativeWindow* window, int interval);//设置Buffer失效期限,当应用生产Buffer快于消费者(一般是显示系统)的消费时,这个参数决定是否丢弃之前没来得及消费的Buffer。
    int     (*query)(const struct ANativeWindow* window, int what, int* value);//查询参数
    int     (*perform)(struct ANativeWindow* window,int operation, ... );//设置参数,其中也包括做连接
    int     (*dequeueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, int* fenceFd);//从队列中取出一块Buffer用于生产(一般是图形渲染),若是第一次调用,会触发Buffer的申请
    int     (*queueBuffer)(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fenceFd);//将生产完成的Buffer送还
    int     (*cancelBuffer)(struct ANativeWindow* window,  struct ANativeWindowBuffer* buffer, int fenceFd);//释放Buffer队列中的Buffer,一般是disconnect时调用
};

用于perform和query接口的一些宏定义如下:

/*用于perform和query接口的宏*/
enum {
    NATIVE_WINDOW_SET_USAGE                 =  0,
    NATIVE_WINDOW_CONNECT                   =  1,   /* deprecated */
    NATIVE_WINDOW_DISCONNECT                =  2,   /* deprecated */
    NATIVE_WINDOW_SET_CROP                  =  3,   /* private */
    NATIVE_WINDOW_SET_BUFFER_COUNT          =  4,
    NATIVE_WINDOW_SET_BUFFERS_GEOMETRY      =  5,   /* deprecated */
    NATIVE_WINDOW_SET_BUFFERS_TRANSFORM     =  6,
    NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP     =  7,
    NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS    =  8,
    NATIVE_WINDOW_SET_BUFFERS_FORMAT        =  9,
    NATIVE_WINDOW_SET_SCALING_MODE          = 10,   /* private */
    NATIVE_WINDOW_LOCK                      = 11,   /* private */
    NATIVE_WINDOW_UNLOCK_AND_POST           = 12,   /* private */
    NATIVE_WINDOW_API_CONNECT               = 13,   /* private */
    NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
    NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
    NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
    NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
    NATIVE_WINDOW_SET_BUFFERS_DATASPACE     = 19
};

窗口的创建与使用

Surface

自Android 4.2之后,FramebufferNativeWindow被废弃,所有窗口均继承Surface。Surface本身是一种ANativeWindow。

class Surface
    : public ANativeObjectBase<ANativeWindow, Surface, RefBase>/*Surface继承于ANativeWindow*/
{
public:
    Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
    /*......*/
private:
    // ANativeWindow hooks
    /*这几个hook函数对应于 window.h 中的接口函数*/
    static int hook_cancelBuffer(ANativeWindow* window,
            ANativeWindowBuffer* buffer, int fenceFd);
    static int hook_dequeueBuffer(ANativeWindow* window,
            ANativeWindowBuffer** buffer, int* fenceFd);
    static int hook_perform(ANativeWindow* window, int operation, ...);
    static int hook_query(const ANativeWindow* window, int what, int* value);
    static int hook_queueBuffer(ANativeWindow* window,
            ANativeWindowBuffer* buffer, int fenceFd);
    static int hook_setSwapInterval(ANativeWindow* window, int interval);

    static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer** buffer);
    static int hook_lockBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    static int hook_queueBuffer_DEPRECATED(ANativeWindow* window,
            ANativeWindowBuffer* buffer);
    /*.......*/
public:
    /*这两个函数主要是CPU绘图时调用,除了获取,映射Buffer之外,额外将非脏区域从上一块Buffer拷贝到本块Buffer,以便渲染时只绘制脏区域*/
    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
    virtual int unlockAndPost();
    /*.......*/
private:
    struct BufferSlot {
        sp<GraphicBuffer> buffer;
        Region dirtyRegion;
    };
    /*Buffer生产者,Surface*/
    sp<IGraphicBufferProducer> mGraphicBufferProducer;
    BufferSlot mSlots[NUM_BUFFER_SLOTS];
    /*通过native_window_set_buffers_dimensions改变,用于在合适的时机改变GraphicBuffer的长宽*/
    uint32_t mReqWidth;
    uint32_t mReqHeight;
    /*需求的GraphicBuffer格式,用于动态调整*/
    PixelFormat mReqFormat;
    /*需求Usage说明,影响GraphicBuffer的flags*/
    uint32_t mReqUsage;
    /*时间戳,用于判断Buffer是否过期*/
    int64_t mTimestamp;
    /*Buffer的使用范围*/
    Rect mCrop;
    /*Buffer后续变换需求,只包括水平、垂直翻转,90度旋转*/
    uint32_t mTransformHint;
    /*BufferProducer是否由使用Surface的App控制,这个主要是用来决定dequeueBuffer时是否堵塞*/
    bool mProducerControlledByApp;
    /*......*/
};

}; // namespace android

窗口的创建

用于图形显示的窗口,是由SurfaceFlinger进程负责创建的:
Surface创建
为应用层创建Surface(窗口)时,SurfaceFlinger同步创建一个Layer,并将Layer的生产者关联到Surface上。这样,应用侧便可以通过Surface申请Buffer,作为生产者渲染图像,送显由Layer中的消费者负责。

Buffer循环机制

对于按一定帧率刷新的窗口系统,每一次渲染只有很有限的时间,频繁地申请/释放图形内存是不可接受的。Android的做法是维护一个Buffer队列,按生产者——消费者模式循环利用。这个Buffer就是上一章所述的GraphicBuffer。

Buffer的状态

Buffer队列池中持有固定数量的Buffer(由setBufferCount函数决定,一般是3块),每个Buffer有四种状态,决定其是否可以被生产者/消费者访问。
Buffer状态变化

Buffer的生产

序号化

由于Layer位于SurfaceFlinger进程中,GraphicBuffer是在SurfaceFlinger进程中创建的。应用层作为生产者,使用时需要将其映射到自己的进程空间。在每次申请Buffer时都做一次映射很不明智。
很容易想到的一个方法是在应用层建一个GraphicBuffer队列,和SurfaceFlinger中的Buffer队列对应地映射起来,每次申请和返还时,以序号代替真实的GraphicBuffer传替。Android也正是这么做的。

dequeueBuffer

Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd)
这接口用于申请内存进行生产(渲染)。
于Surface侧,它获取Buffer的序列号,然后检查是否已经同步过,若没有同步过调用requestBuffer同步(映射共享内存)。
于BufferQueue侧,它检查是否有 FREE 标志的Buffer,如果没有,根据 mProducerControlledByApp 标志决定返回错误码或者等待。
fenceFd是BufferQueue返回给Surface的,生产者有义务去等fence。

queueBuffer

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd)
于Surface侧,它将Buffer送还给BufferQueue,但这不一定表示生产者用完了,消费者获取到Buffer之后仍有义务等fence。
于BufferQueue侧,接收到Buffer,将其放到一个可用队列中,修改状态,并且触发监听器的onFrameAvailable函数。

Buffer的消费

acquireBuffer

消费者获取buffer,由于在queueBuffer时,会将Buffer放到一个队列中,这时便从那个队列去取。

releaseBuffer

消费者释放buffer。

版权声明:本文为博主原创文章,未经博主允许不得转载。

© 著作权归作者所有

共有 人打赏支持
jxt1234
粉丝 3
博文 36
码字总数 41634
作品 0
杭州
Android Eclipse 和Unity的APK包调试

Android Eclipse 和Unity的APK包调试 网上找了老半天,刚开始折腾Eclipse,网上搜到一点教程,打开DDMS,找了半天没有,又接着找网上说要安装ADT插件,接着找,找到一个网址根据网上的下载方...

wwlcsdn000 ⋅ 05/15 ⋅ 0

Android开发权威指南(第2版)新书发布

《Android开发权威指南(第二版)》是畅销书《Android开发权威指南》的升级版,内容更新超过80%,是一本全面介绍Android应用开发的专著,拥有45章精彩内容供读者学习。  《Android开发权威指...

androidguy ⋅ 2013/09/05 ⋅ 0

Android清单文件详解(一) ---- 一切从开始

在AndroidManifest.xml文件中,首先看到是的<manifest>节点,它是整个应用程序的基本属性,涵盖了默认进程名字,应用程序标识,安装位置,对系统的要求以及应用程序的版本等。它是AndroidMa...

mickelfeng ⋅ 06/04 ⋅ 0

(连载) Android SDK 1.5 中文联机文档

刚开始学习android,在网上找关于android方面的教程,发现没什么合适的。找来找去,发现下的android下的文档才是最好,最权威的教程。翻译下来,一是为了加深理解,二可以为了以后查看方便,...

大东哥 ⋅ 2009/08/18 ⋅ 5

Unity发布Android版本

先大概说一下我自己的经历吧,总的大概用了10小时吧。刚开始装的是jre和Android stdio,然后发现要装的是JDK和SDK,然后去装JDK和SDK,装JDK很顺利,装SDK失败了,原因未知。后面是用 Androi...

a_clear_chen ⋅ 05/08 ⋅ 0

Android 自定义相机开发(三) —— 了解下EGL

胡说八道 如果要使用OpenGl来自定义相机,这个还是要了解下的。可能大多数开发者使用过OpengGL但是不知道EGL是什么?EGL的作用是什么?这其实一点都不奇怪,因为Android中的GlSurfaceView已经...

aserbao ⋅ 05/10 ⋅ 0

android自学笔记《三》——系统架构分析

下面是Android的系统架构图 翻译后 从上图中可以看出,Android系统架构为4层结构,从上层到下层分别是应用程序层、应用程序框架层、系统运行库层以及Linux内核层,分别介绍如下: 1)应用程序...

郭子 ⋅ 2012/02/03 ⋅ 5

activity属性设置大全

属性 可选值 含义 android:allowTaskReparenting true or false 是否允许activity更换从属的任务,比如从短信息任务 切换到浏览器任务。 android:alwaysRetainTaskState true or false 是否保...

会飞柚子 ⋅ 2016/03/02 ⋅ 0

如何实现安卓手机“天上飞”?需要像GPU Turbo这样的“天梯”

在安卓手机产业中,一直流传着一个传说:发布会上展示出的一切参数配置,在新机拿到手后都要打个七折,使用一年之后,还要再打个五折。 这一说法虽然有些玄学的味道,但也非常贴近现实情况。...

脑极体 ⋅ 06/06 ⋅ 0

学习Android开发平台需要了解的体系结构和源码结构

本文转自迅为iTOP-4412开发板实战书籍:http://www.topeetboard.com 下面这张图出自Google官方,展示了Android系统的主要组成部分。 可以看出,Android系统架构由5部 分组成,分别是:Linux...

歌之王子殿下 ⋅ 2016/07/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

开启Swarm集群以及可视化管理

在搭建的两台coreos服务器上开启swarm集群 前置条件: docker均开启2375端口 同一个局域网内 主服务器上安装Portainer容器 安装Portainer容器执行: docker run -d -p 9000:9000 --restart=a...

ykbj ⋅ 16分钟前 ⋅ 0

单例设计模式

1、单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例 2、饿汉式单例类 在这个类被加载时,静态变量instance会被初始化,此时类的私有构造子会被调用 饿汉式是典型...

职业搬砖20年 ⋅ 21分钟前 ⋅ 0

前端基础(四):前端国际规范收集

字数:1142 阅读时间:5分钟 前言 由于前端技术的灵活性和杂乱性,导致网上的许多解决方案不够全面甚至是完全错误,容易起到误导作用。所以,我对搜索到的解决方案往往是存疑态度。那么,如何...

老司机带你撸代码 ⋅ 23分钟前 ⋅ 0

Failed to open/create Network-VirtualBox Host-Only

虚拟机版本 : Oracle Vm VirtualBox 5.2.12 报错时机:开网卡二,重启虚拟机报错 "Failed to open/create the internal network 'HostInterfaceNetworking-VirtualBox Host-Only Ethernet Ada......

p至尊宝 ⋅ 26分钟前 ⋅ 0

三分钟学会如何在函数计算中使用 puppeteer

摘要: 使用 puppeteer 结合函数计算,可以快速的构建弹性的服务完成各种功能,包括:生成网页截图或者 PDF、高级爬虫,可以爬取大量异步渲染内容的网页、模拟键盘输入、表单自动提交、登录网...

阿里云云栖社区 ⋅ 30分钟前 ⋅ 0

springMVC接收表单时 Bean对象有Double Int Char类型的处理

前台ajax提交表单price为double类型 后台controller就介绍不到 400错误 前台 实体类: public class ReleaseMapIconConfig{ private String id; private long maxValue; private long minVal......

废柴 ⋅ 32分钟前 ⋅ 0

ZOOKEEPER安装

工作需要在ubuntu上配置了一个zookeeper集群,有些问题记录下来。 1. zookeeper以来java,所以首先要安装java。但是ubuntu系统有自带的jdk,需要通过命令切换java版本: $ sudo update-alter...

恰东 ⋅ 35分钟前 ⋅ 0

linux 进程地址空间的一步步探究

我们知道,在32位机器上linux操作系统中的进程的地址空间大小是4G,其中0-3G是用户空间,3G-4G是内核空间。其实,这个4G的地址空间是不存在的,也就是我们所说的虚拟内存空间。 那虚拟内存空间...

HelloRookie ⋅ 35分钟前 ⋅ 0

myatis #{}与${}区别及原理

https://blog.csdn.net/wo541075754/article/details/54292751

李道福 ⋅ 38分钟前 ⋅ 0

三分钟学会如何在函数计算中使用 puppeteer

摘要: 使用 puppeteer 结合函数计算,可以快速的构建弹性的服务完成各种功能,包括:生成网页截图或者 PDF、高级爬虫,可以爬取大量异步渲染内容的网页、模拟键盘输入、表单自动提交、登录网...

猫耳m ⋅ 39分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部