天天看點

Android SurfaceFligner Vsync信号 Jni/C++調用實作

   在Anroid Vsync信号是用來通知APP進行渲染的,分為兩種硬體Vsync和軟體Vsync信号。我們這邊不做詳細介紹,這邊是如何通過C++去拿到Vsync信号

   首先來看上層提供的操作接口

#include "LibLoader.h"
#include <dlfcn.h>
LibLoader::LibLoader() {
	// TODO Auto-generated constructor stub
	handle = dlopen("/system/lib/libshaozhongqi.so", RTLD_NOW | RTLD_LOCAL);
	    if (!handle) {
	        //LOGE("open depend lib failed");
	        handle = NULL;
	    }
}

LibLoader::~LibLoader() {
	// TODO Auto-generated destructor stub
	if( handle ){
		dlclose(handle);
	}

	handle = NULL;
}

           
#include "VSync.h"
#include <dlfcn.h>
//http://blog.csdn.net/smfwuxiao/article/details/6591927



int VSync::init(void* h){


	    handle = h;

	    vsync_init 	= (__hwvsync_init)dlsym(handle,"_Z12hwvsync_initv");
	    hwsync		= (__hwvsync)dlsym(handle, "_Z8hw_vsyncv");
	    hwcdeint 	= (__hwvsync_deinit)dlsym(handle, "_Z12vsync_Deinitv");

		if (!vsync_init || !hwsync || !hwcdeint )
		{
			//LOGE("dlsym fail ===== %s", dlerror());
			return -1;
		}
		else
		{
			isRun = true;
			int res = vsync_init();
			//LOGI("vsync init comp: %d", res);

			return res;

		}
}


uint64_t VSync::getVSync(){
	if( !isRun ){
		return 0;
	}
	return hwsync();
}

void VSync::quit(){
//	int res = vsync_Deinit();
	isRun = false;

	if( handle != NULL ){
		hwcdeint();
	}
}


           

  這三個接口需要我來實作

  看一下我實作的代碼:

/*
* Created By Zhongqi.Shao On 2017-09-25

*/

#pragma once


#include <gui/BitTube.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
#include <gui/DisplayEventReceiver.h>
#include <utils/Looper.h>
#include <pthread.h>
#include "EventQueue.h"

#define RUN 1
#define STOP 0

using namespace android;

namespace nvr{
  
class VsyncClient
{
  
private:
    //sp<ISurfaceComposer> surfaceFligner;
	//sp<DisplayEventReceiver> mSpEventReceiver;
	VsyncClient();
	static VsyncClient * pInstance = NULL;

	int status = STOP;

public:
   	DisplayEventReceiver* mDisplayEvent;
    //sp<BitTube> mChannel;
	Looper* mloop;
	pthread_t* mPollThred; 
	EventQueue* mEventQueue;
	Event* tempEvent;

	pthread_mutex_t* eventMutex;
	pthread_cond_t*	notEmpty;

	pthread_mutex_t* threadMutex;
	pthread_cond_t*	threadStatus;
	
	virtual ~VsyncClient();
	
	static void * StartePoll( void * parm );
	void runThread();
	void startPollThread();

	void thread_resume();
	void thread_pause();

    int initClient();
	int initEnv();

	uint64_t getVsync();
	void stopClient();

	static VsyncClient* GetInstance(){
	    if(pInstance == NULL){
		  pInstance = new VsyncClient();
		}
	    return pInstance;
	}

};


}
           
#include <vsync/VsyncClient.h>
#include <gui/DisplayEventReceiver.h>
#include <utils/Errors.h>


#define ALOOPER_EVENT_INPUT              1 << 0

using namespace android;

namespace nvr{

VsyncClient::VsyncClient(){
	int envStatus = initEnv();
}

VsyncClient::~VsyncClient(){
	 ALOGD("vsyncpp happened wrong this object cannot release!!!");

}


void *VsyncClient::StartePoll( void * parm ){

	VsyncClient & client = *(VsyncClient *)parm;
	
	client.runThread();
	return NULL;
}



int VsyncClient::initClient(){
	thread_resume();
	mDisplayEvent->setVsyncRate(1);
    return 0;
}



int receiver(int fd, int events, void* data){
	VsyncClient* client = (VsyncClient*)data;
    
	DisplayEventReceiver* q = client->mDisplayEvent;
	if(q == NULL){
	  ALOGD("vsyncpp receiver event = null");
	  return 0;
	}
	//EventQueue* eventQueue = client->mEventQueue;

    ssize_t n;
    DisplayEventReceiver::Event buffer[1];

    static nsecs_t oldTimeStamp = 0;

    while ((n = q->getEvents(buffer, 1)) > 0) {
        for (int i=0 ; i<n ; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                
            }
			pthread_mutex_lock(client->eventMutex);/*鎖住互斥量*/  
			client->tempEvent->timestamp = buffer[i].header.timestamp;
			pthread_cond_signal(client->notEmpty);/*條件改變,發送信号,通知t_b程序*/ 
		    pthread_mutex_unlock(client->eventMutex);/*解鎖互斥量*/
			//ALOGD("shao1 event vsync: time=%lld\t",client->tempEvent->timestamp);
        }
    }
    if (n<0) {
        ALOGD("vsyncpp error reading events (%s)\n", strerror(-n));
    }
    return 1;
}


void VsyncClient::runThread(){
	do {
	    pthread_mutex_lock(threadMutex);
        while (!status)
        {
            pthread_cond_wait(threadStatus, threadMutex);
        }
        pthread_mutex_unlock(threadMutex);
        int32_t ret = mloop->pollOnce(-1);
    } while (1);
}



void VsyncClient::startPollThread(){

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	struct sched_param	stShedParam;

	pthread_attr_getschedparam(&attr, &stShedParam);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    stShedParam.sched_priority = 90;
    pthread_attr_setschedparam(&attr, &stShedParam);

	const int createErr = pthread_create(mPollThred, &attr ,&StartePoll, this );
	 pthread_attr_destroy(&attr);
	if ( createErr != 0 )
	{
		ALOGE("============= os create vsync thread failed");

	}else{
		ALOGD("============= os create vsync thread succ");
	}
	
}



void VsyncClient::thread_resume(){
	
	if (status == STOP){   
        pthread_mutex_lock(threadMutex);
        status = RUN;
        pthread_cond_signal(threadStatus);
       	ALOGD("vsyncpp thread run\n");
        pthread_mutex_unlock(threadMutex);
    }   
    else{   
       	ALOGD("vsyncpp thread has already run");
    }   
}


void VsyncClient::thread_pause(){

	if (status == RUN){   
        pthread_mutex_lock(threadMutex);
        status = STOP;
        ALOGD("vsyncpp thread stop\n");
        pthread_mutex_unlock(threadMutex);
    }   
    else{   
         ALOGD("vsyncpp thread has alreay stop\n");
    }

}


int VsyncClient::initEnv(){
    tempEvent = new Event();

	eventMutex = new pthread_mutex_t();
	notEmpty = new pthread_cond_t();

	threadMutex = new pthread_mutex_t();
	threadStatus = new pthread_cond_t();

    mDisplayEvent = new DisplayEventReceiver();
	status_t status = mDisplayEvent->initCheck();
	mDisplayEvent->setVsyncRate(1);
    mloop = new Looper(false);
    mloop->addFd(mDisplayEvent->getFd(), 0, ALOOPER_EVENT_INPUT, receiver,this);
	mPollThred = new pthread_t();

	pthread_mutex_init(eventMutex, NULL /* default attributes */ );
	pthread_cond_init(notEmpty, NULL /* default attributes */ );

	pthread_mutex_init(threadMutex, NULL /* default attributes */ );
	pthread_cond_init(threadStatus, NULL /* default attributes */ );

    startPollThread();
	return 0;

}


uint64_t VsyncClient::getVsync(){
    pthread_mutex_lock(eventMutex);/*鎖住互斥量*/
	pthread_cond_wait(notEmpty,eventMutex);/*解鎖mutex,并等待cond改變*/  
	Event tEvent;
	tEvent.timestamp = tempEvent->timestamp;
	pthread_mutex_unlock(eventMutex);
	ALOGD("shao2 event vsync: time=%lld\t",tEvent.timestamp);
	return tEvent.timestamp;

}


void VsyncClient::stopClient(){
	thread_pause();
	mDisplayEvent->setVsyncRate(0);
    
}


}
           

主要邏輯如下:

1:單例情況下在構造函數裡面建立DisplayEventReceiver對象

     看一下DisplayEventReceiver構造裡面做了什麼操作

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

DisplayEventReceiver::~DisplayEventReceiver() {
}

status_t DisplayEventReceiver::initCheck() const {
    if (mDataChannel != NULL)
        return NO_ERROR;
    return NO_INIT;
}

int DisplayEventReceiver::getFd() const {
    if (mDataChannel == NULL)
        return NO_INIT;

    return mDataChannel->getFd();
}

status_t DisplayEventReceiver::setVsyncRate(uint32_t count) {
    if (int32_t(count) < 0)
        return BAD_VALUE;

    if (mEventConnection != NULL) {
        mEventConnection->setVsyncRate(count);
        return NO_ERROR;
    }
    return NO_INIT;
}

status_t DisplayEventReceiver::requestNextVsync() {
    if (mEventConnection != NULL) {
        mEventConnection->requestNextVsync();
        return NO_ERROR;
    }
    return NO_INIT;
}
           

 sp<ISurfaceComposer> sf(ComposerService::getComposerService());拿到surfacefligner service binder對象,mEventConnection = sf->createDisplayEventConnection();建立connection對象,這個mEventConnectio到底是什麼?本質就是包含BitTube管道用來實作程序通信的類

2:添加

 mloop->addFd(mDisplayEvent->getFd(), 0, ALOOPER_EVENT_INPUT, receiver,this);實作對管道的監聽,有資料寫入管道就會調用receiver這個函數,我在這個函數裡面将最新資料寫入tempEvent這個Object

3:開啟線程不停調用pollonce()才能促發receiver回調,然後采用生産者消費者模式将資料傳回給getVsync()接口

到此流程結束