GUI:SurfaceFlinger

1.Project Butter

Butter中有两个重要的组成部分:Vsync和Triple Buffering

1.1 单缓冲的问题

在一个典型的显示系统中Frame Buffer代表了屏幕即将要显示的一帧画面,加入cpu/gpu绘制过程与屏幕刷新使用的buffer是同一块,那么当他们速度不同步的时候,很有可能出现画面的割裂现象。比如显示器的刷新频率是66Hz,而cpu/gpu的绘图能力是100Hz。那么显示器处理一帧数据需要0.015秒,cpu/gpu处理一帧数据需要0.01秒。

TU 9-23

  • 0.01秒:cpu/gpu处理一帧数据需要0.01秒,那么这是buffer中已经准备好了第一帧数据,而显示器处理一帧数据需要0.015秒,也就是说,这时显示器只显示了一部分数据。

  • 0.015秒:显示器显示一帧数据需要0.015秒,这时,一帧画面完整的显示在屏幕上,而此时buffer中有一部分已经被填充上第二帧数据。

  • 0.02秒:第二帧数据在buffer填充完成,但显示器中有一部分显示的是第一帧数据一部分显示的是第二帧数据(显示器显示一帧需要0.015秒,在0.02秒时,前0.015处理了第一帧数据,0.005秒用于处理第二帧,也就是说只处理了1/3的数据,所以只有1/3的屏幕显示第二帧数据)

在单缓冲的情况下,这个问题是很难规避的,所以需要双缓冲技术,基本原理就是采用了两块buffer,起重工一块back buffer用于cpu/gpu后台绘制,另一块frame buffer用于屏幕显示;当back buffer就绪之后,他们才进行交换。

1.2 Vsync

一个典型的显示器有两个特性,行频和场频;
行频又称水平扫描频率,是屏幕每秒钟从左到右扫描的次数;
场频又称垂直扫描频率,是屏幕每秒钟整个屏幕的刷新次数。

当扫描完一个屏幕之后,设备需要重新回到第一行以进入下一轮循环,此时有一段时间空隙,称为vertical blanking interval,这个时间点是进行缓冲区交换的最佳时间,因为此时屏幕没有在刷新,也就避免了交换过程中出现割裂的情况。Vsync是vertical synchronizing的缩写,它利用VBI时期出现的Vertical Sync Pulse来保证双缓冲能在最佳时间点交换。

1.3 Vsync和双缓冲结合使用

TU 9-25
TU 9-26
一旦Vsync信号出现,cpu便即刻开始执行buffer的准备工作,大部分android显示设备的刷新频率是60Hz,也就意味着每一帧最多只能留给系统1/60=16ms左右的准备时间,加入cpu/gpu的FPS(frames per second)高于这个值,那么方案是完美的,显示效果将很好。只要cpu/gpu的处理时间控制在16ms以内,就不会影响显示效果。

1.4 FPS低于屏幕刷新频率的情况。

TU 9-27
如果cpu/gpu的处理时间高于16ms,那么第一个Vsync到来的时候,缓冲区B的数据还没有准备好,就只能显示之前A缓冲区中的内容,而B完成后,又因为缺乏Vsync信号,只能等到下一轮交换,于是这一过程中,有一大段时间 是被浪费的。当下一个Vsync出现时,cpu/gpu马上执行操作,此时它操作的是A,相应的屏幕显示的是B,不过因为时间仍然超过16ms,导致一下次执行缓冲区的交换又被延迟,如此往复就出现了越来越多的卡顿现象。

除非升级设备,否则,第一次的卡段是没有办法避免的。我们关注的是cpu/gpu浪费的时间怎么才能被充分的利用,造成cpu/gpu时间浪费无事可做的原因是当前没有可用的buffer了,back buffer已经填充好,但vsync还没有到来这段时间;如果新增一个buffer情况会不会好转?

1.5 三缓冲解决FPS低于屏幕刷新频率的情况

TU 9-28
第一次卡顿无法避免,但是当第一次Vsync之后,cpu不再等待,会使用C来进行数据准备,对然对Buffer C的处理时间依然超过了16ms,但这并不影响最终的显示,第二次Vsync来之后,它选择Buffer B进行显示,到了第三次VSync时会显示Buffer C,而不是像双缓冲那样在显示一遍Buffer B。

2.SurfaceFlinger的启动


extern "C" status_t system_init()
{ 
    sp proc(ProcessState::self()); 
    sp sm = defaultServiceManager();  
    char propBuf[PROPERTY_VALUE_MAX];
    property_get("system_init.startsurfaceflinger", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) { 
        SurfaceFlinger::instantiate();
    }
    //...   
}   

system_init调用instantiate来创建一个Bind Server,名称为SurfaceFlinger;而且强指针的特性使得它在第一次被引用时触发了onFirstRef方法。


void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this); 
    //启动一个名为SurfaceFlinger的线程并设置优先级
    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); 
    mReadyToRunBarrier.wait();//等待上面那个线程执行完成
}

run方法之后,Thread会自动调用threadLoop方法

bool SurfaceFlinger::threadLoop() {
    waitForEvent();
    return true;
}

void SurfaceFlinger::waitForEvent() {
    mEventQueue.waitMessage();
}


void MessageQueue::init(const sp& flinger)
{
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
}

status_t SurfaceFlinger::readyToRun()
{ 
    // EGL配置
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL); 
    mHwc = new HWComposer(this,
            *static_cast(this)); 
    mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
    mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); 
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig,
            EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId); 
    sp hw(getDefaultDisplayDevice()); 
    DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
    initializeGL(mEGLDisplay);

    // start the EventThread
    mEventThread = new EventThread(this);
    mEventQueue.setEventThread(mEventThread);
 
    // We're now ready to accept clients...
    mReadyToRunBarrier.open();//打开  
    //开启
    startBootAnim(); 
    return NO_ERROR;
}

SurfaceFlinger在启动的同时建立了一个消息分发和处理机制

3.接口的服务端-Client

3.1概述

SurfaceFlinger运行于SystemServer这一系统进程中,需要显示UI界面的应用程序则通过Binder与它进行跨进程通信。而且每一个有UI界面的程序都在SurfaceFlinger端有相对应的Client实现。
TU 9-30

TU 9-31

应用程序与Client之间的Binder接口是ISurfaceComposerClient,所以作为接口的服务端实现,Client继承自BnSurfaceComposerClient.
ISurfaceComposerClient的两个接口

virtual status_t createSurface(
        const String8& name, uint32_t w, uint32_t h,
        PixelFormat format, uint32_t flags,
        sp* handle,
        sp* gbp) = 0;


virtual status_t destroySurface(const sp& handle) = 0;

需要注意的是,SurfaceFlinger的客户端程序拥有的Surface数量可能不止一个,通常情况下,同一个Activity的UI布局公用系统分配的Surface进行绘图,但像SurfaceView这种UI组件却独占一个Surface进行绘制,比如我们制作一个带SurfaceView的视频播放器,这样的设计师必须的,因为播放视频对刷新频率要求很高,采用单独的Surface既可以满足视频的流畅度同时又可以让用户的交互得到及时的反应。

3.2 SurfaceFlinger::createConnection

sp SurfaceFlinger::createConnection()
{
    sp bclient;
    sp client(new Client(this));
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        bclient = client;
    }
    return bclient;
}

Client属于匿名Binder服务,外界进程不能直接获取,需要借助SurfaceFlinger这个实名的BinderServer来获取Client这个匿名Binder服务;该函数首先生成一个Client本地对象,然后调用initCheck进行必要的有效性检查,如果没有出错,就把新生成的Client对象用ISurfaceComposerClient强指针的形式返回。

3.3 Client::createSurface

第一步:createSurface

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp* handle,
        sp* gbp)
{
    /*
     *这个函数需要从OpenGLES环境线程中被调用,这样它才能够使用OpenGLES提供的服务 
     */

    class MessageCreateLayer : public MessageBase {
        SurfaceFlinger* flinger;
        Client* client;
        sp* handle;
        sp* gbp;
        status_t result;
        const String8& name;
        uint32_t w, h;
        PixelFormat format;
        uint32_t flags;
    public:
        MessageCreateLayer(SurfaceFlinger* flinger,
                const String8& name, Client* client,
                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
                sp* handle,
                sp* gbp)
            : flinger(flinger), client(client),
              handle(handle), gbp(gbp),
              name(name), w(w), h(h), format(format), flags(flags) {
        }
         
        virtual bool handler() {
            result = flinger->createLayer(name, client, w, h, format, flags,
                    handle, gbp);
            return true;
        }
    };

    sp msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    mFlinger->postMessageSync(msg);//发送消息
    return static_cast( msg.get() )->getResult();
}

第二步:postMessageSync

status_t SurfaceFlinger::postMessageSync(const sp& msg,
        nsecs_t reltime, uint32_t flags) {
    status_t res = mEventQueue.postMessage(msg, reltime);
    if (res == NO_ERROR) {
        msg->wait();
    }
    return res;
}

通过messageQueue将消息压入消息队列中,并且会进入等待状态。

第三步:handleMessage

void MessageBase::handleMessage(const Message&) {
    this->handler();
    barrier.open();
};

Client收到来自客户端的请求,并不会马上让SurfaceFlinger执行,而是把请求投递到SurfaceFlinger的消息队列中,这样既保证了消息不会丢失,又使得SurfaceFlinger不至于中断当前的操作。在createSurface的执行过程中,Client所在的线程会进入wait状态,直到SurfaceFlinger成功完成业务后,它才被唤醒,然后返回最终结果给客户端。

你可能感兴趣的:(GUI:SurfaceFlinger)