Android graphic: How vsync signal is passed from LCD to app?


Android graphic: How vsync signal is passed from LCD to app?
 
step 1: from LCD to eventthread.
 
EventThread and SF are two different threads in one process. it take care of dispatch vsync
signal to App.
 
 
0) let's begin from 
./frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
 
HWComposer() is created by surfaceflinger.
 
status_t SurfaceFlinger::readyToRun() {
     mHwc = new HWComposer(this,
             *static_cast<HWComposer::EventHandler *>(this));
}
 
 
in HWComposer() construction function
1)
 
it calls loadHwcModule() which opens Hwc module and assigns the device  to mHwc.
 
LoadHwcModule() does the following:
1.1)
        hw_get_module(HWC_HARDWARE_MODULE_ID, &module)
         hwc_open_1(module, &mHwc);
 
1.2) hwc_open_1()  actually invokes  hwc_device_open()
      in file hardware/intel/mfld_cdk/hwc/IntelHWComposerModule.cpp
 
      in this function it will assignes mHwc with IntelHWComposer();
                     IntelHWComposer *hwc = new IntelHWComposer();
 
1.3) 
      if (hwc->initialize() == false) 
 
IntelHWComposer initialize 初始化的过程中,
会创建IntelVsyncEventHandler 和 IntelFakeVsyncEvent
 
IntelVsyncEventHandler 负责把硬件的vsync signal 上报。
IntelFakeVsyncEvent ,如果硬件不支持vsync, 则用一个thread 伪造。
 
 hardware/intel/mfld_cdk/hwc/IntelHWComposer.cpp 
 
IntelHWComposer::initialize()
{
         mVsync = new IntelVsyncEventHandler(this, mDrm->getDrmFd());
         mFakeVsync = new IntelFakeVsyncEvent(this);
}
 
1.4)
IntelVsyncEventHandler  inherates from  android::Thread. 
the thread and SF thread belongs to the same process.
 
IntelVsyncEventHandler reads the DRM device in a thread loop,  if vsync is on,  it will calls 
 
 bool IntelVsyncEventHandler::threadLoop()
 for (i = 0; i <= VSYNC_SRC_HDMI; i++) {
 
       arg.vsync_operation_mask = VSYNC_WAIT;
 
       ret = drmCommandWriteRead(mDrmFd, DRM_PSB_VSYNC_SET, &arg, sizeof(arg));
       mComposer->vsync((uint64_t)arg.vsync.timestamp, arg.vsync.pipe);
}
 
Here, mComposer is IntelHWComposer who creates the IntelVsyncEventHandler .
 
in HWComposer() construction function
 
2) register some procedures
 
 mComposer->vsync finally invokes into. 
void IntelHWComposer::vsync(int64_t timestamp, int pipe)
{
 mProcs->vsync(const_cast<hwc_procs_t*>(mProcs), 0, timestamp);
}
 
 
Here we wodner how mProcs is registered? 
in 
./frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
 mCBContext->hwc = this;
 mCBContext->procs.invalidate = &hook_invalidate;
 mCBContext->procs.vsync = &hook_vsync;
 
 149             mHwc->registerProcs(mHwc, &mCBContext->procs);
 
 
so hook_vsync is finllay invoked from the IntelVsyncEventHandler thread loop.
 
 
3) 
./frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
 
 void HWComposer::vsync(int disp, int64_t timestamp) {
 mEventHandler.onVSyncReceived(disp, timestamp);
}
 
the mEventHandler is actally the surfaceflinger itself. when sf creates HWComposer,
it pass itself to mEventHandler.
 
4)
void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
     mEventThread->onVSyncReceived(type, timestamp);
}
 
5) 
 void EventThread::onVSyncReceived(int type, nsecs_t timestamp) {
     mCondition.broadcast();
}
 
it just wakes up Eventthread.  Eventthread main thread take care of dispatching 
vsync to App. (we skip the alogrithm on how to dispatch.)
 
That's all, vsync signal finally walks from LCD to event thread now!
 
Step Two: vsync from event thread to app
 
Application usually create DisplayEventReceiver object.
It registers a connection to eventthread, and recevice vsync signal for app from Eventthread.
 
DisplayEventReceiver and Eventthread usually are in different process, 
they comminucate with each other through binder.
 
DisplayEventReceiver is created with a looper, the looper is the execution thread.
the looper keeps messagequeue->next(). If no message, it invokes poll() to wait one
some io/FD
 
DisplayEventReceiver 包含了一个Bittube, which creates socket.
 the socket is added to the polling list
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
 
 status_t NativeDisplayEventReceiver::initialize() {
     int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
 
once the Eventthread wakes up the socket, the looper will wakeup. 
 
  ./frameworks/native/services/surfaceflinger/EventThread.cpp
             status_t EventThread::Connection::postEvent(
             DisplayEventReceiver::sendEvents(mChannel, &event, 1);
                BitTube::sendObjects(dataChannel, events, count);
 
 
When Eventthread want to notify the DisplayEventReceiver about vsync, it wakes up DisplayEventReceiver looper
the looper calls handleevent()
 int callbackResult = response.request.callback->handleEvent(fd, events, data);
        int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
             dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
 
dispatchvsync finally calls
 
frameworks/base/core/java/android/view/DisplayEventReceiver.java
 private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
     onVsync(timestampNanos, builtInDisplayId, frame);
}
 
DisplayEventReceiver::onVsync() , it sends a message into the App looper's queue.
 
e.g
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);
 
so the app start to draw now!
   
posted on 2013-03-20 14:45  keniee  阅读(2306)  评论(0编辑  收藏  举报