AnsweredAssumed Answered

iMX FBIOPAN_DISPLAY hangs if called after FBIO_WAITFORVSYNC

Question asked by Steve Green on Dec 8, 2014
Branched to a new discussion

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);

}

Outcomes