1 Linux 获取VSYNC核心原理解读
android系统上 获取VSYNC有现成的方法,但是Linux上想获取Vsync还是不那么直接的,这里主要是介绍使用libdrm库获取vsync信号的方法(该方法适用于ubuntu和debian系统)
我们首先要理解几个基础概念,行同步/场同步/行消隐/场消隐,如下所示:
- 行同步HSYNC:电视信号发送端为了使接收端的行扫描与场扫描规律与其同步,在行扫描正常结束后,向接收机发出一个脉冲信号,表示这一行已经结束,这个脉冲信号就是行同步信号。
- 场同步VSYNC:电视信号发送端为了使接收端的行扫描与场扫描规律与其同步,在场扫描正常结束后,向接收机发出一个脉冲信号,表示这一场已经结束,这个脉冲信号就是场同步信号。
- 行消隐HBLANK:指行与行之间的返回过程。而扫描点扫描完一帧后,要从图像的右下角返回到图像的左上角,开始新一帧的扫描,这一时间间隔,叫做行消隐。
- 场消隐VBLANK:扫描点扫描完一帧后,要从图像的右下角返回到图像的左上角,开始新一帧的扫描,这一时间间隔,叫做垂直消隐,也称场消隐。
使用Linux系统 libdrm库 获取Vsync的核心原理:使用drmWaitVBlank()可以获得场消隐VBlank,可以简单理解为要想获得2个Vsync之间的时间间隔,可以通过获得 场消隐VBlank之间的时间间隔,因为每一次场消隐伴随着场同步信号VSYNC的触发。
2 demo实现
有了这个理解,使用drmWaitVBlank方法就可以使用VSYNC信号了,demo源码如下所示:
#include <stdio.h>
#include <xf86drm.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#define DRM_VBLANK_HIGH_CRTC_SHIFT 1
struct timeval(){
long usec1 = 0;
gettimeofday(&tp2, NULL);
usec1 = 1000000 * (tp2.tv_sec - tp1.tv_sec) + (tp2.tv_usec - tp1.tv_usec);
printf("onVsync= %f ms \n",usec1/1000.0f);
gettimeofday(&tp1, NULL);
}
int main(int argc, char** argv)
{
int ret = 0;
drmVBlank vbl;
memset(&vbl, 0, sizeof(vbl));
vbl.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE);;
vbl.request.sequence = 0;
//open card0 device point
int fd = open("/dev/dri/card0",O_RDWR);
if ( fd<0 ) {
printf("failed to open /dev/dri/card0");
return -1;
}
gettimeofday(&tp1, NULL);
while (1) {
uint32_t high_crtc = (0 << DRM_VBLANK_HIGH_CRTC_SHIFT);
vbl.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK) );
vbl.request.sequence = 1;
//wait next vsync
ret = drmWaitVBlank(fd, &vbl);
if (ret != 0) {
printf("drmWaitVBlank failed ret=%d\n", ret);
return -1;
}
//vsync callback
onVsync();
}
return 0;
}
接下来 编译一下代码,编译 & 交叉编译 如下:
#Linux PC端编译
$g++ vsyncworker.cpp -I/usr/include/libdrm -ldrm
#嵌入式Linux交叉编译,注意:aarch64交叉编译要指定sysroot路径,否则找不到drm库
$aarch64-linux-gnu-g++ vsyncworker.cpp -I/usr/include/drm -ldrm --sysroot=[sysroot路径]
生成./a.out,分别在Linux和嵌入式Linux上执行,效果基本一致,如下所示:
onVsync= 11.444000 ms
onVsync= 16.332001 ms
onVsync= 16.792999 ms
onVsync= 16.490999 ms
onVsync= 16.605000 ms
onVsync= 16.643999 ms
onVsync= 16.688999 ms
onVsync= 16.639999 ms
onVsync= 16.576000 ms
onVsync= 16.611000 ms
onVsync= 16.663000 ms
onVsync= 16.608999 ms
onVsync= 16.610001 ms
onVsync= 16.709000 ms
onVsync= 16.527000 ms
onVsync= 16.768999 ms
onVsync= 16.493000 ms
onVsync= 16.757999 ms
onVsync= 16.518000 ms
onVsync= 16.627001 ms
onVsync= 16.605000 ms
onVsync= 16.649000 ms
onVsync= 16.556000 ms
onVsync= 16.649000 ms
onVsync= 16.580999 ms
onVsync= 16.874001 ms
onVsync= 16.601999 ms
onVsync= 16.708000 ms
onVsync= 16.413000 ms
onVsync= 16.679001 ms
onVsync= 16.587000 ms
onVsync= 16.624001 ms
onVsync= 16.617001 ms
onVsync= 16.639000 ms
onVsync= 16.648001 ms
onVsync= 16.627001 ms
onVsync= 16.608999 ms
onVsync= 16.804001 ms
onVsync= 16.483000 ms
onVsync= 16.601000 ms
onVsync= 16.636999 ms
onVsync= 16.594000 ms
onVsync= 16.760000 ms
onVsync= 16.493999 ms
onVsync= 16.614000 ms
onVsync= 16.635000 ms
onVsync= 16.792000 ms
onVsync= 16.441000 ms
onVsync= 16.781000 ms
onVsync= 16.431999 ms
onVsync= 16.715000 ms
onVsync= 16.540001 ms
onVsync= 16.823999 ms
看效果还是可以用的。