在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.youkuaiyun.com/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()接口
到此流程结束