bill.connelly
Posts: 6
Joined: Wed Jan 29, 2014 12:20 pm

Unpredictable timing with ioctl - mailboxes and double buffering

Fri Aug 16, 2019 5:38 am

To flip the frame buffer, I am updating the mailbox virtual offset with a function like this:

Code: Select all

int flip_buffer(int buffer_num, fb_config fb0){
        int fd = open("/dev/vcio",0);
        if(fd == -1){
                perror("VCIO OPEN ERROR: ");
                return 1;
        }

        volatile uint32_t property[32] __attribute__((aligned(16))) =
        {
        0x00000000,//Buffer size in bytes
        0x00000000,//Request / Response code
        0x48009, //TAG: set vir offset
        8,
        8,
        0,//x offset
        0,//y offset
        0
        };
        property[0] = 8*sizeof(property[0]);
        if(buffer_num != 0){
                property[6] = fb0.height;
        }
        //send request via property interface using ioctl

        if(ioctl(fd, _IOWR(100, 0, char *), property) == -1){
                perror("BUFFER FLIP IOCTL ERROR");
        }

        close(fd);
        return 0
}
In order to synchronize with vsync I have tried

Code: Select all

flip_buffer(buffer, fb0);
ioctl(fb0.framebuffer, FBIO_WAITFORVSYNC, &dummy);
or in the opposite order

Code: Select all

ioctl(fb0.framebuffer, FBIO_WAITFORVSYNC, &dummy);
flip_buffer(buffer, fb0);
However, I have found that when I perform the second of those two (FBIO wait for vsync then flip bluffer) the behaviour of the this line

Code: Select all

        if(ioctl(fd, _IOWR(100, 0, char *), property) == -1){
         
Is odd. Sometimes it executes in a few microseconds, sometmes taking several milliseconds, and screwing up the timings.

I've tried going through the code for ioctl but I can't understand it. Any reason why the order of the operations, re FBIO_WAITFORVSYNC and updating the mailbox should cause one function to hang for so long?

Hanicef
Posts: 10
Joined: Thu Apr 18, 2019 5:15 pm

Re: Unpredictable timing with ioctl - mailboxes and double buffering

Thu Aug 22, 2019 7:56 pm

The hang is most likely due to vertical sync.

The way that monitors work is that the monitor requires a very specific timing for drawing. These timings are synchronized with horizontal sync and vertical sync.
Horizontal sync is signaled when the monitor is finished drawing a horizontal line on the screen. Vertical sync, on the other hand, is signaled when the entire screen has been drawn, and the next frame will begin.

FBIO_WAITFORVSYNC will cause the current thread to stop until a vertical sync is signaled, as the name implies. Assuming we have a 60 Hz monitor, this makes the monitor signal a vertical sync 60 times a second. This means that it's 1 / 60 = 0.01666666... seconds, or 16.666666... milliseconds between each vertical sync.
Basically, the further away in time a vertical sync is, the longer the processor will wait. It can wait multiple milliseconds if a vertical sync was signaled right before the wait was started, but if a sync is just around the corner, the wait can be in microseconds, hence the inconsistent timing. It basically depends on where the monitor is during the drawing process when the wait is initiated.

Why it only affects the second case, though, is probably because FBIO_WAITFORVSYNC doesn't take immediate effect, but instead changes the behavior of _IOWR, causing it to wait for vertical sync. On the first case, however, FBIO_WAITFORVSYNC is called after _IOWR is called, causing _IOWR to write immediately without waiting for a vertical sync to occur. However, I might be wrong about that.

Return to “C/C++”