Android SurfaceFligner Vsync訊號 Jni/C++呼叫實現
阿新 • • 發佈:2018-12-31
在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()介面
到此流程結束