您的位置:首页 > 编程语言 > C语言/C++

Android SurfaceFligner Vsync信号 Jni/C++调用实现

2017-09-29 17:32 459 查看
   在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()接口

到此流程结束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息