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

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(窗口)时,SurfaceFlinger同步创建一个Layer,并将Layer的生产者关联到Surface上。这样,应用侧便可以通过Surface申请Buffer,作为生产者渲染图像,送显由Layer中的消费者负责。

Buffer循环机制

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

Buffer的状态

Buffer队列池中持有固定数量的Buffer(由setBufferCount函数决定,一般是3块),每个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。

时间: 2024-12-28 21:09:07

Android图形显示系统——下层显示3:窗口系统的相关文章

悬浮窗-Android 通过WindowManager.addVidw创建的窗口系统是否会自动销毁?

问题描述 Android 通过WindowManager.addVidw创建的窗口系统是否会自动销毁? 如题,我做了一个类似悬浮窗的小辅助工具,设计初衷是要求在任何界面都能一直保持显示,并设计了一个开关来决定是否一直显示和隐藏.但是在运行测试的过程中发现,这个悬浮窗会在某些时候自动消失掉,但是我跟进过并log过removeView的地方,都没看到是我的误操作导致的销毁. 因此怀疑是否是系统在某些特定的环境或者情况下会自动回收这些Window的View,顺便贴下我的部分代码 WindowManag

Android图形显示系统——下层显示4:图层合成下(硬件合成器)

硬件合成器-HwComposer 使用3D合成,需要大面积的像素混合计算和大量的内存传输(GPU读写GraphicBuffer所需),对GPU和DDR来说是一个巨大的负担.在GPU/DDR重度使用的场景(比如玩游戏),会造成发热.卡顿等. 为了提升性能,减少功耗,可以将合成这个过程交由另一个芯片完成,减轻GPU负担.进一步,直接让这个芯片连LCD,在LCD需要显示某一行时在线合成. HwComposer便是这一个/多个专用合成芯片的驱动HAL层. 驱动由集成芯片系统的厂商自行设计,但需要遵循一定

电脑系统字体显示模糊怎么办 系统字体显示模糊解决办法

系统字体显示模糊,如下:     解决方案: 系统字体模糊,是由于修改系统DPI后出现故障.   解决方案如下:   鼠标右键点击桌面--分辨率--显示--设置自定义文本大小(DPI)--应用:             应用之后注销即可!

Android图形显示系统——下层显示4:图层合成上(合成原理与3D合成)

Android显示之图层合成 要点 1.图层合成指综合各个窗口的绘制内容,送往LCD显示的过程.从原理上可分为在线合成与离线合成两种方式. 2.在Android的SurfaceFlinger代码流程中,图层合成方式分3D合成(OpenGL)和硬件合成两大类. 3.图形系统采用垂直同步Vsync机制,由LCD上报vsync,触发图层合成. 图层合成的原理 什么是图层合成 以Android原生版本的Launcher为例,这个场景下有四个图层,状态栏.导航栏由SystemUI绘制,壁纸由壁纸服务提供,

Android最新版本分布图:4.4系统进展缓慢

[TechWeb报道]据Google最新公布的 Android平台版本分布图显示,果冻豆系统依旧持续飙升,作为全新生力军的Android 4.4虽进展迟缓,但版本的比重目前已经达到了1.1%.特别是由于Android 4.4对硬件配置要求非常低,所以接下来这个系统的份额还有很大提升空间.目前Android果冻豆系统的市场份额已经达到60.7%,比上月增长了1.6%.其中,4.1有略微下滑,从上月的35.9%下降至35.5%,4.2增长至16.3%,而4.3增长至8.9%.Android 2.3姜

launcher-往Launcher代码添加android小部件不显示,

问题描述 往Launcher代码添加android小部件不显示, 怎么在系统的Launcher的包里添加一个小部件啊,我把我的音乐小部件丢进default_workspace.xml里了,可以没显示出来 launcher:packageName="com.carl.android.music.ui.SLMusicWidget" launcher:className="com.carl.android.music.ui" launcher:screen="1

Android图形显示系统——概述

序 Android的图形显示系统,虽然感觉自己基本了解了,有问题基本都能解决,但要写时,一是觉得千头万绪无从下笔,一是发现还有很多并没有真正搞懂.开工写这套体系,也顺便查漏补缺下. Android图形显示系统的剖分 图形显示系统就像一个报社,它派出记者去采访,记者写成文稿后,将记者们交上来的文稿审核.排版.印刷,最终形成一期又一期报纸. 如上是Android图形显示系统的一个全貌图.每个Layer对应着一个Surface.Surface 由每个需要显示的进程View树创建(View树本身对应一个

win7系统下任务栏窗口无法显示缩略图的解决方法

  win7系统一直是微软公司推出的所有系统中口碑最好的一个,因为里面的一些功能都很具有实用性,是用户日常生活中经常会遇到的,比如说win7系统中有个缩略图功能,只要鼠标移到下方任务栏窗口中,就会看到缩略图中的内容,对于有需要的用户来说是很方便的,一直用习惯这个功能的小伙伴们都很依赖这个,每次鼠标移到这个桌面下方都会下意识的去看下.但是最近有用户反映说这个功能不见了,下面小编就来教大家win7旗舰版电脑下方任务栏窗口的缩略图不见了怎么办. win7系统下任务栏窗口无法显示缩略图的解决方法 第一步

教你使用Win7系统各种显示窗口方式

  工作或者各种需要,同时打开多个窗口,同时在多个窗口中操作,都是不可避免的.然而在同时打开多个窗口的时候,我们就需要掌握Win7系统各种显示窗口 ,如窗口的排列.摆布.显示方式就显得尤其重要了,好的摆布方式有利于提高工作效率,减少工作量. 操作步骤 1. 首先在任务栏空白的地方点击右键,然后在弹出的菜单栏中你会发现有"层叠窗口"."堆叠显示窗口"."并排显示窗口"这三个选单.然后你就可以根据自己的需要,选择自己适用的显示窗口方式了. 2. 层叠