I'm finding that calling FBIOPAN_DISPLAY hangs if it's called after FBIO_WAITFORVSYNC, see example code below.
Interestingly I found if I put a usleep() delay between them of 40mSec, it does not hang, and being a PAL system the frame time happens to be 40mSec.
No error messages are printed out, it just hangs after I print my "Flip to..." debug statement. Can anyone please suggest what might be wrong?
Thank you.
/******************************************************************************************
**
** demo example showing display buffer flipping hanging, if called immediately
** after waiting for VSYNC
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <linux/videodev.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
int ctrl_c_rev = 0;
int NumberOfBuffers;
static int FlipDisplayBuffers(char *name, int fd);
static int AwaitVSync(char *name, int fd);
/******************************************************************************************
**
*/
void
ctrl_c_handler(int signum, siginfo_t *info, void *action)
{
ctrl_c_rev = 1;
}
/******************************************************************************************
**
*/
int
main(int argc, char *argv[])
{
struct sigaction action;
int retval;
int Fd_Fb;
int FbNumber = 0;
char FbDeviceName[] = "/dev/fb0"; // the '0' can be overwritten later
unsigned int FbFormat;
unsigned long FbScreenSize;
unsigned long FbMMAPSize;
struct fb_fix_screeninfo Fb_fixInfo;
struct fb_var_screeninfo Fb_varInfo;
int count;
/*for ctrl-c*/
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
action.sa_sigaction = ctrl_c_handler;
if (sigaction(SIGINT, &action, NULL) < 0)
{
printf("install ctrl-c handler error\n");
return (-1);
}
retval = system("echo 0 > /sys/class/graphics/fb0/blank");
retval = system("echo 0 > /sys/class/graphics/fb1/blank");
memset(&Fb_fixInfo, 0x00, sizeof(Fb_fixInfo));
memset(&Fb_varInfo, 0x00, sizeof(Fb_varInfo));
/*
* select which framebuffer to try. I found both fb0 and fb1 hang in the same way
*/
FbNumber = 1; // set for 0 or 1, in reality I want to use fb1
FbDeviceName[7] = '0' + FbNumber; // overwrite to set actual fb device number
FbFormat = v4l2_fourcc('U', 'Y', 'V', 'Y');
printf("Opening frame buffer %d: %s\n", FbNumber, FbDeviceName);
if ((Fd_Fb = open(FbDeviceName, O_RDWR)) < 0)
{
printf("Can't open frame buffer %s\n", FbDeviceName);
return (-1);
}
if (ioctl(Fd_Fb, FBIOGET_FSCREENINFO, &Fb_fixInfo) < 0)
{
printf("Failed initial FBIOGET_FSCREENINFO on %s (%s)\n", FbDeviceName,
strerror(errno));
goto closeandfinish;
}
if (ioctl(Fd_Fb, FBIOGET_VSCREENINFO, &Fb_varInfo) < 0)
{
printf("Failed initial FBIOGET_VSCREENINFO on %s (%s)\n", FbDeviceName, strerror(errno));
closeandfinish:
close(Fd_Fb);
return (-1);
}
/*
* note: just use the display's native Fb_varInfo.xres and Fb_varInfo.yres
*/
NumberOfBuffers = 2; // number of buffers we want to flip between
/*
* Set video display format and allocate enough buffer space
*/
Fb_varInfo.yres_virtual = NumberOfBuffers * Fb_varInfo.yres; // allocate enough memory for all buffers
Fb_varInfo.nonstd = FbFormat;
if (ioctl(Fd_Fb, FBIOPUT_VSCREENINFO, &Fb_varInfo) == -1)
{
printf("Failed FBIOPUT_VSCREENINFO on %s (%s)\n", FbDeviceName, strerror(errno));
goto closeandfinish;
}
if (ioctl(Fd_Fb, FBIOGET_FSCREENINFO, &Fb_fixInfo) < 0)
{
printf("Failed FBIOGET_FSCREENINFO on %s (%s)\n", FbDeviceName, strerror(errno));
goto closeandfinish;
}
FbScreenSize = Fb_fixInfo.line_length * Fb_varInfo.yres; // actual number of bytes in a screen
FbMMAPSize = Fb_fixInfo.line_length * Fb_varInfo.yres_virtual; // actual total number of bytes in all buffers
printf("Set %s: xres:%d yres:%d line_length:%u yres_virtual:%d\n"
" NumberOfBuffers:%d FbMMAPSize:%lu\n",
FbDeviceName, Fb_varInfo.xres, Fb_varInfo.yres, Fb_fixInfo.line_length,
Fb_varInfo.yres_virtual,
NumberOfBuffers, FbMMAPSize);
/*
* just doing flipping.
* Note my display is PAL, so each frame (vsync) is 40mSec apart
*/
printf("\n========= buffer flipping - works great ===========\n");
for (count = 0; (count < 25) && (ctrl_c_rev == 0); count++)
{
FlipDisplayBuffers(FbDeviceName, Fd_Fb);
usleep(40000); // simulating waiting for one frame time of 40mSec
}
/*
* just doing VSYNC
*/
printf("\n========= VSYNCs - works great ===========\n");
for (count = 0; (count < 25) && (ctrl_c_rev == 0); count++)
{
AwaitVSync(FbDeviceName, Fd_Fb);
}
/*
* doing both buffer flipping and VSYNC - this hangs!!!
*/
printf("\n========= buffer flipping upon VSYNCs - hangs if no usleep() ! ===========\n");
for (count = 0; (count < 25) && (ctrl_c_rev == 0); count++)
{
/* SO THIS IS WHAT HAPPENS:
* ------------------------
* It should be OK to have AwaitVSync() and FlipDisplayBuffers() following
* after each other, but this causes FlipDisplayBuffers to hang on the
* SECOND time through.
*
* But as an experiment I inserted a usleep() between FlipDisplayBuffers()
* and the next AwaitVSync(), and it does *not* hang.
*
* If the usleep is less than 40mSec, it hangs, if greater then it
* does *not* hang.
*
* Note that my display is PAL and so the frametime is 40mSec, is this a clue ?
*/
usleep(40000); // put this in to make it work, remove it or make less than 40mSec to make it hang
AwaitVSync(FbDeviceName, Fd_Fb);
FlipDisplayBuffers(FbDeviceName, Fd_Fb);
printf("\n");
}
close(Fd_Fb);
printf("Test finished\n\n");
return(0);
}
/******************************************************************************************
**
*/
static int
FlipDisplayBuffers(char *name, int fd)
{
static int DisplayIdx = 0;
struct fb_var_screeninfo varInfo;
/* get vscreeninfo so we can know the yres */
if (ioctl(fd, FBIOGET_VSCREENINFO, &varInfo) == -1)
{
printf("Failed FBIOGET_VSCREENINFO[%s] (%s)\n", name, strerror(errno));
return (-1);
}
/* index to next buffer */
DisplayIdx++;
DisplayIdx %= NumberOfBuffers;
/* set offset to next buffer */
varInfo.yoffset = varInfo.yres * DisplayIdx;
printf("FlipTo idx:%d yoffset:%d\n", DisplayIdx, varInfo.yoffset);
/* flip the display buffer */
if (ioctl(fd, FBIOPAN_DISPLAY, &varInfo) == -1)
{
printf("Failed FBIOPAN_DISPLAY[%s] (%s)\n", name, strerror(errno));
return (-1);
}
printf(" FBIOPAN_DISPLAY[%s] OK\n", name);
return (0);
}
/******************************************************************************************
**
*/
static int
AwaitVSync(char *name, int fd)
{
int dummy = 0;
printf("Await VSync...\n");
/* Wait for vertical sync */
if (ioctl(fd, FBIO_WAITFORVSYNC, &dummy) == -1)
{
printf("Failed Capture FBIO_WAITFORVSYNC (%s)\n", strerror(errno));
return (-1);
}
printf(" FBIO_WAITFORVSYNC[%s] OK\n", name);
return (0);
}