Android SurfaceFlinger VSync流程分析

2 篇文章 0 订阅
1 篇文章 0 订阅

一,VSync机制的作用及VSync在SurfaceFlinger服务中的位置:
VSync信号通常都来自硬件控制器,在Android中也可以采用软件模拟;
VSync的作用,如下图(以双缓冲为例,为了提高流畅性有时也采用triple三缓冲):LCD控制器在读取每一帧数据的开始都会产生一个VSync信号(垂直同步信号或帧同步信号);

这里写图片描述

LCD的频率是60Hz,显示每一帧的间隔是16ms,所以每一个VSync信号的时间间隔是16ms,上图中的A和B都是帧缓冲区framebuffer,每一个framebuffer由CPU和GPU共同完成;

在硬件芯片中,晶振产生的时钟脉冲驱动整个硬件电路连续运行;在Surfaceflinger中,VSync信号就好像晶振电路产生的时钟信号一样驱动Surfaceflinger中所有模块和谐的运行,如下图;

这里写图片描述

二,VSync流程及重要代码:
1,整体流程概览,如下图:

这里写图片描述

重点介绍如下过程:
2,App绘制请求发送流程(过程1(App)):
App进程调用invalidate或postinvalidate方法发送绘制请求;

这里写图片描述

invalidate方法最终会调用的BpDisplayEventConnection的requestNextVsync方法,在该方法中通过Binder IPC访问服务端的requestNextSync方法;

BpDisplayEventConnection方法的实例化过程如下:
1>,在ViewRootImpl的构造函数中会实例化Choreographer对象,

public ViewRootImpl(Context context, Display display) {
                . . . . . 
        mChoreographer = Choreographer.getInstance();
 }

2>,在mChoreographer 的构造函数中实例化FrameDisplayEventReceiver对象:

private Choreographer(Looper looper) {
               . . . . . .
               mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
 }

3>,在FrameDisplayEventReceiver的父类构造函数中会调用到,android_view_DisplayEventReceiver.cpp中的nativeInit方法,

4>,在nativeInit方法中有如下过程:

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj) {
        . . . . . .
    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue);
    status_t status = receiver->initialize();
    . . . . . .
   1),创建NativeDisplayEventReceiver类类型指针,

在NativeDisplayEventReceiver的构造函数中会调用DisplayEventReceiver类的无参构造函数实例化成员mReceiver;

DisplayEventReceiver::DisplayEventReceiver() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != NULL) {
        mEventConnection = sf->createDisplayEventConnection();
        if (mEventConnection != NULL) {
            mDataChannel = mEventConnection->getDataChannel();
        }
    }
}

在这段代码中获取Surfaceflinger服务的代理对象,然后通过Binder IPC创建BpDisplayEventConnection对象,然后mEventConnection->getDataChannel()方法再次通过Binder IPC创建 BitTube对象mDataChannel ,在Binder IPC创建mDataChannel 过程中会从服务端EventThread::Connection::Connection中(在EventThread类中定义)接收一个socketpair创建的FIFO文件描述符;

EventThread::Connection::Connection创建描述符的代码:
Connection构造函数调用BitTube的无参构造函数,在BitTube的构造函数中调用init函数;

void BitTube::init(size_t rcvbuf, size_t sndbuf) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
        // sine we don't use the "return channel", we keep it small...
        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
        mReceiveFd = sockets[0];
        mSendFd = sockets[1];
    } else {
        mReceiveFd = -errno;
        ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
    }
}
  2)调用到NativeDisplayEventReceiver类的父类DisplayEventDispatcher中的initialize()方法,
  将BpDisplayEventConnection对象获取到的mDataChannel (BitTube类型)中的文件描述符添加到UI主线程Looper的epoll中,
  当文件描述符中被写入数据时,该epoll_wait会被唤醒;

3,Vsync信号驱动App进程绘制流程(过程4(App)):

4,Surfaceflinger图册合成请求发送流程(过程1(sf)):

5,Vsync信号驱动Surfaceflinger合成流程(过程4(sf)):

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值