I wrote some code for use in my research which has worked well, however my timing constraints (EEG-based Brain-Computer Interfaces) are becoming more time critical, and I’ve discovered timing issues which I am posting here for help.
My application requires precise presentation of items on my monitor sync’ed with the refresh rate of 60fps. My problem might be one that people aren’t aware of because I doubt many would test with photo-detectors on the screen as I have done to see what is REALLY happening.
I’ve stripped away the application specific things, and provided a bare-bones test that anyone can reproduce. The effect happens on a variety of video cards and monitors, so it doesn’t seem to be vendor specific. However, I am using Linux (Ubuntu). Most people won’t have photo detectors and digital recording equipment, but I can test your code and post the results if you think you have a solution.
The test presents four different images repeatedly in sequence. Each image consists of two adjacent white or black squares. The frames are frame 0 through frame 3. In frame 0, both squares are black. In frame 1, only the right square is white. In frame two, the left square is white instead. In frame 3, they are both white. Each frame appears for 1/60 of a second and frames 0 to 3 are sequenced in order forever. The images are synchronized to the vertical sync of the video card/monitor.
Each square has a photo detector placed over it sampled, digitized, and recorded at 10,000 sps. By examining this recording, I can see what is really happening. What should happen is the outputs of the detectors may be viewed as a two-bit binary number progressing through 00, 01, 10, and 11 representing frame0, through frame3 respectively. At a sampling rate of 10,000 Hz, each frame is sampled almost 167 times by the recording device thereby capturing a clear record of what happened.
Rather than repeat all 167 samples for each 1/60 of a second, I will show only one number for each frame below to describe what SHOULD happen versus what ACTUALLY happens. We should see:
012301230123 …
Unfortunately, instead I see:
130012011201 …
So I miss frames, and duplicate frames with no pattern. I have the code below. If anyone has any suggestions about what to do to try to “fix” this, I can take your edits, and run them to show what the recorder generates for your solution. Please help! (And yes, if I slow this down to say one frame change per second by adding a one second sleep in the main loop, then I do faithfully get 60 0’s followed by 60 1’s followed by 60 2’s and then 60 3’s.)
At one point I put in some debugging code in my main loop to toggle a bit on an I/O port which I monitored both with a digital recorder as well as an oscilloscope to confirm that my code is indeed looping once every 1/60th of a second faithfully.
#include <iostream>
#include <cstdlib>
#include <GL/glut.h>
#include <GL/glx.h>
using namespace std;
#define SCREENWIDTH 800
#define SCREENHEIGHT 600
int hdc;
void display(void);
void keyboard(unsigned char key, int x, int y);
void configureWindow();
void configureGraphics();
static PFNGLXSWAPINTERVALSGIPROC swap_interval;
int num = 0;
int main(int argc, char **argv)
{
glutInit(&argc, argv);
configureWindow();
configureGraphics();
glutMainLoop();
return 0;
}
void configureWindow()
{
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(SCREENWIDTH, SCREENHEIGHT);
hdc = glutCreateWindow("");
glutFullScreen();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
}
void configureGraphics()
{
glDisable(GL_DEPTH_TEST);
glColor3f(0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREENWIDTH-1, 0, SCREENHEIGHT-1, -1, 1);
PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress((GLubyte*)"glXSwapIntervalSGI");
glXSwapIntervalSGI(1);
}
void display(void)
{
if (num/2 == 1) /* set the colour of the left square */
{
glColor3f(1.0, 1.0, 1.0);
}
else
{
glColor3f(0.0, 0.0, 0.0);
}
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_QUADS); /* draw the left square */
glVertex2f(SCREENWIDTH/3 - 50,SCREENHEIGHT/2 - 50);
glVertex2f(SCREENWIDTH/3 - 50,SCREENHEIGHT/2 + 50);
glVertex2f(SCREENWIDTH/3 + 50,SCREENHEIGHT/2 + 50);
glVertex2f(SCREENWIDTH/3 + 50,SCREENHEIGHT/2 - 50);
glEnd();
if (num%2 == 1) /* set the colour of the right square */
{
glColor3f(1.0, 1.0, 1.0);
}
else
{
glColor3f(0.0, 0.0, 0.0);
}
glBegin(GL_QUADS); /* draw the right square */
glVertex2f(2*SCREENWIDTH/3 - 50,SCREENHEIGHT/2 - 50);
glVertex2f(2*SCREENWIDTH/3 - 50,SCREENHEIGHT/2 + 50);
glVertex2f(2*SCREENWIDTH/3 + 50,SCREENHEIGHT/2 + 50);
glVertex2f(2*SCREENWIDTH/3 + 50,SCREENHEIGHT/2 - 50);
glEnd();
num = (num+1)%4; /* increase frame 0,1,2,3,0,1,2,3 */
glutSwapBuffers();
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
if (key == 27)
{
exit(0);
}
}
p.s. I think the problem has something to do with the fifos, but I don’t know how to get around it … if I keep the fifos empty (by sleeping a bit in the loop), the problem goes away, but at the expense of not being there in time for the next frame. Then I get something like 0011223300112233 which isn’t a solution.