Android SurfaceFligner Vsync信号 Jni/C++调用实现
2017-09-29 17:32
459 查看
在Anroid Vsync信号是用来通知APP进行渲染的,分为两种硬件Vsync和软件Vsync信号。我们这边不做详细介绍,这边是如何通过C++去拿到Vsync信号
首先来看上层提供的操作接口
这三个接口需要我来实现
看一下我实现的代码:
主要逻辑如下:
1:单例情况下在构造函数里面创建DisplayEventReceiver对象
看一下DisplayEventReceiver构造里面做了什么操作
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()接口
到此流程结束
首先来看上层提供的操作接口
#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()接口
到此流程结束
相关文章推荐
- JNI NDK (AndroidStudio+CMake )实现C C++调用Java代码流程
- Android-使用C++实现调用本地方法返回字符串显示在界面上/NDK-JNI开发实例(八)
- 在Android中,通过JNI实现C++与Java相互调用
- android实现app通过jni调用C/C++方法
- Android Cmake 编译c,c++源文件,实现JNI调用
- android实现app通过jni调用C/C++方法
- Android(安卓)开发通过NDK调用JNI,使用opencv做本地c++代码开发配置方法实现边缘检测代码(2)
- Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用
- Android开发 通过JNI实现JAVA与C/C++程序间的调用和回调
- Android利用JNI实现java调用C或C++
- android调用本地C/C++代码,jni的实现
- JNI NDK (AndroidStudio+CMake )实现Java调用C C++代码流程
- cocosdx交叉编译到android使用jni实现java端调用C++方法
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用