hardware question

I’m practicing openGL on my brand new laptop, which has an integrated graphics card. I’m still learning openGL and I haven’t gotten into display lists yet, or the use of vertex arrays. Right now I just wrote some code to draw ellipsoids because I found you can draw quite a few interesting shapes by combining ellipsoids of various sizes and colors. Each ellipsoid has 20x20 or 400 quad primitives to describe it. I thought this was fairly modest amount but when i draw 6 or 7 such shapes, the frame rate begins to drop below 60 per second.

I thought maybe my code was inefficient so I added some timers, but they quickly revealed the drawing was by far the longest operation.

Is this merely because I am drawing primitives one by one, or is it more likely my cheap graphics card? Still, this is a brand new windows 7 laptop and I’m pretty sure its capable of more than this!

Are you computing the ellipsoids every time you draw? Or are you just calling glVertex3f, etc? If you are computing them every time, all the trig can become a bottleneck.

It doesn’t sound like you are drawing much even for an integrated graphics card. Try using display lists or VBOs for a performance boost.

Regards,
Patrick

I am updating the ellipsoids which uses a lot of trig, but that is done in my update() function which takes less than 1 millisecond according to my experiments. The drawing function which uses no trig functions, takes about 16 milliseconds.

Will display lists make that big a difference?

what framerate do you get if you draw just one (out of the 400) quads?

mark_ds,

hmm… the frame rate increases to around 720 fps, about 12 times faster for 1/400 the amount of drawing. That makes little sense… maybe computation is the issue here. Doesn’t agree with my time measurements though… strange.

okay, the following code is enough to reduce my speed to about 60 fps:


	glColor3f(0.5,0.5,0);
	for (int i = 0; i < 35; i++)
	{
		
		for (int j =0; j < 35; j++)
		{
			glBegin(GL_QUADS);
				glVertex3f(i,j,0);
				glVertex3f(i+1,j,0);
				glVertex3f(i+1,j+1,0);
				glVertex3f(i,j+1,0);
			glEnd();
		}
	}

thats just a 35x35 checkerboard. Something seems wrong here.

How much faster if you replace the code with a display list as follows:


static GLuint list=0;

if (list==0) {
  list=glGenLists(1);
  glNewList(list,GL_COMPILE);

  glColor3f(0.5,0.5,0);
  for (int i = 0; i < 35; i++)
  {
    
    for (int j =0; j < 35; j++)
    {
      glBegin(GL_QUADS);
        glVertex3f(i,j,0);
        glVertex3f(i+1,j,0);
        glVertex3f(i+1,j+1,0);
        glVertex3f(i,j+1,0);
      glEnd();
    }
  }

  glEndList();
}

glCallList(list);


If you are constantly updating the data, I’m not sure how much display lists will help since they need to be compiled. Can you just compute a sphere up front and use translations, rotations, and non uniform scales? Note that the surface normals will be incorrect due to the non uniform scale but you might be able to tolerate it.

Regards,
Patrick

marshats: it was a liiittle better. But not significantly.

Isn’t that strange?

Okay well here is a review of the graphics chip, its an Intel Media Accelerator 4500MHD: http://pcgamingcorner.com/wordpress/?p=820

apparently it is not at all suitable for high speed graphics. However! What I’m doing is not even close to the kind of graphics quality in todays games.

One more thought, what if you pull the glBegin/glEnd pair outside of the inner foor-loop, do you see any speed improvement?


static GLuint list=0;

if (list==0) {
  list=glGenLists(1);
  glNewList(list,GL_COMPILE);

  glColor3f(0.5,0.5,0);

  glBegin(GL_QUADS);
  for (int i = 0; i < 35; i++)
  {
    for (int j =0; j < 35; j++)
    {
        glVertex3f(i,j,0);
        glVertex3f(i+1,j,0);
        glVertex3f(i+1,j+1,0);
        glVertex3f(i,j+1,0);    
    }
  }
  glEnd();

  glEndList();
}

glCallList(list);

ps What call are you using to measure time? This can be tricky because some timer functions have poor resolution ie 10s of millseconds.

I tried what you suggested. I observed a slight improvment but less than 100%.

I’m using the clock_t class from <ctime>. It may not be the most accurate timer, but I am rotating the objects 1 degree per frame as I display them and so I have a rough idea of the frame rate based on how long it takes to complete one rotation.

Even so, I think the above nested loop shows that this is more of a hardware issue. I’m going to test the program on my desktop to see if there’s any improvement.

Well I uploaded the project folder to my desktop (which also has an integrated graphics chip) and saw no improvement. Maybe it has something to do with my programming environment such as Visual C++ or the Windows API…

Cool, trying on your PC is a good idea. I wrote a quick program and saw 407171 FPS with my NVIDIA 9600 GT – note that nothing is actually drawn faster than the refresh rate of the monitor but openGL skips the in between frame to give such a high FPS.

Note the use of a timer like ctime with 1ms precision may lead to misleading results for instance a difference of 1ms could lead to a FPS difference of 500FPS!


1ms/frame = 1/1e-3=1000FPS
2ms/frame = 1/2e-3=500FPS
3ms/frame = 1/3e-3=333FPS
...

so at very high frame rates your FPS values could be completely off. So to deal with an imprecise clock it is best to measure the number of frames that are drawn in say 1 second – that takes the precision of the timer out of the issue.

For what its worth here is a glut based code used to time your example on my Linux box – will run on windows too but you would have to setup your compiler with glut accordingly. Note when you run this for the first second it is calibrating itself to the frame rate – but after that it knows the frame rate so scales the rate of rotation to be 8 rotations per second – still running a full FPS possible.


//this shows a way to get FPS using an imprecise clock glutTimerFunc
//on linux: g++ glut_fps_demo.cpp -lGL -lglut
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <iostream>

//linux openGL headers
#include <GL/gl.h>
#include <GL/glut.h>

GLint gFramesPerSecond = 0;
GLfloat gAngle = 0.0;

void FPS(void) {
  static GLint Frames = 0;         // frames averaged over 1000mS
  static GLuint Clock;             // [milliSeconds]
  static GLuint NextClock = 0;     // [milliSeconds]

  ++Frames;
  Clock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( Clock < NextClock ) return;

  gFramesPerSecond = Frames/1; // store the averaged number of frames per second

  NextClock = Clock+1000; // 1000mS=1S in the future
  Frames=0;
}

void timer(int value)
{
  const int desiredFPS=1000000; //make infinity to go as fast as possible
  glutTimerFunc(1000/desiredFPS, timer, ++value);
  GLfloat dt = (gFramesPerSecond>0 ? 1.0/gFramesPerSecond : 1.0);

  //put your specific idle code here
  //... this code will run at desiredFPS
    gAngle += dt*360./8.; //rotate 360 degrees every 8 seconds
    gAngle = fmodf(gAngle,360.); // keep between 0 and 360 degrees
  //end your specific idle code here

  FPS(); //only call once per frame loop to measure FPS
  glutPostRedisplay(); // initiate display() call at desiredFPS rate
}

void display() {
  // Will be called at FPS rate, ok to use global values now to rener scene
  glClear(GL_COLOR_BUFFER_BIT);

  //quick and dirty way to display FPS value
  printf("FPS %d Angle %g\r",gFramesPerSecond,gAngle); fflush(stdout);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef( 35/2, 35/2,0);
  glRotatef(gAngle,0,0,1);
  glTranslatef(-35/2,-35/2,0);

  static GLuint list=0;

  if (list==0) {
    list=glGenLists(1);
    glNewList(list,GL_COMPILE);

    glColor3f(0.5,0.5,0);

    glBegin(GL_QUADS);
    for (int i = 0; i < 35; i++)
    {
      for (int j =0; j < 35; j++)
      {
          glVertex3f(i,j,0);
          glVertex3f(i+1,j,0);
          glVertex3f(i+1,j+1,0);
          glVertex3f(i,j+1,0);    
      }
    }
    glEnd();

    glEndList();
  }

  glCallList(list);

  glutSwapBuffers();
}

void init() {
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-10.0,46.0,-10.0,46.0,-1.0,1.0);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE);
   glutCreateWindow("FPS test /w glutTimerFunc");

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);

   init();

   glutMainLoop();
   return 0;
}

I have used glut before so I had little trouble installling it on my laptop.

I compiled and ran your code without modification. It ran at about 65 frames per second. Thats only about half a million fewer than yours. Man thats depressing!

It may not be as bad as you think – the fact that you are seeing a suspicious number of 65FPS (near the standard 60Hz Vertical sync of monitors) may mean that you are being limited not by the drawing speed. It sounds more like your FPS is matching the vertical refresh rate of your monitor. One way to see this is to increase the number of QUADS being drawn per frame – and hopefully you can increase it much greater than 35x35 grid size and still see the same refresh rate. To help I modified the code so there is a "#define GSIZE 358" to make the number of quads (358)x(35*8) for instance. Trying recompiling this for different values of GSIZE 35, 70, … and note if the FPS stays fixed at 65 or drops rapidly


//this shows a way to get FPS using an imprecise clock glutTimerFunc
//on linux: g++ glut_fps_demo.cpp -lGL -lglut
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <iostream>

//linux openGL headers
#include <GL/gl.h>
#include <GL/glut.h>

#define GSIZE 32*8

GLint gFramesPerSecond = 0;
GLfloat gAngle = 0.0;

void FPS(void) {
  static GLint Frames = 0;         // frames averaged over 1000mS
  static GLuint Clock;             // [milliSeconds]
  static GLuint NextClock = 0;     // [milliSeconds]

  ++Frames;
  Clock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( Clock < NextClock ) return;

  gFramesPerSecond = Frames/1; // store the averaged number of frames per second

  NextClock = Clock+1000; // 1000mS=1S in the future
  Frames=0;
}

void idle()
{
  GLfloat dt = (gFramesPerSecond>0 ? 1.0/gFramesPerSecond : 1.0);

  //put your specific idle code here
  //... this code will run at desiredFPS
    gAngle += dt*360./8.; //rotate 360 degrees every 8 seconds
    gAngle = fmodf(gAngle,360.); // keep between 0 and 360 degrees
  //end your specific idle code here

  FPS(); //only call once per frame loop to measure FPS
  glutPostRedisplay(); // initiate display() call at desiredFPS rate
}

void display() {
  // Will be called at FPS rate, ok to use global values now to rener scene
  glClear(GL_COLOR_BUFFER_BIT);

  //quick and dirty way to display FPS value
  printf("FPS %d Angle %g\r",gFramesPerSecond,gAngle); fflush(stdout);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glRotatef(gAngle,0,0,1);
  glTranslatef(-GSIZE/2,-GSIZE/2,0);

  static GLuint list=0;

  if (list==0) {
    list=glGenLists(1);
    glNewList(list,GL_COMPILE);

    glColor3f(0.5,0.5,0);

    glBegin(GL_QUADS);
    for (int i = 0; i < GSIZE; i++)
    {
      for (int j =0; j < GSIZE; j++)
      {
          glVertex3f(i,j,0);
          glVertex3f(i+1,j,0);
          glVertex3f(i+1,j+1,0);
          glVertex3f(i,j+1,0);    
      }
    }
    glEnd();

    glEndList();
  }

  glCallList(list);

  glutSwapBuffers();
}

void init() {
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-GSIZE*0.8,GSIZE*0.8,-GSIZE*0.8,GSIZE*0.8,-1.0,1.0);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE);
   glutCreateWindow("FPS test /w glutTimerFunc");

   glutIdleFunc(idle);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);

   init();

   glutMainLoop();
   return 0;
}

p.s. I also found that using glutTimerFunc() allowed the code to skip many calls of display() giving an over exagerated FPS value. So I replaced with glutTimerFunc() with glutIdleFunc(). In this case I did not see it skip any display calls and the result is 9626 FPS with GSIZE=35,

I compiled and executed your code. It dropped to 13 fps.

My only other idea is to try running in fullscreen mode.

Mhhm, I was thinking the 65FPS was so close to 60Hhz that it had to be sync limited – but your test with 8X GSIZE with a drop down to 13FPS stopped that thought.

Is it an issue that you are not getting the accelerated graphics with GLUT?

What does this print out.


    printf("GL_VENDOR: %s
", glGetString(GL_VENDOR));
    printf("GL_RENDERER: %s
", glGetString(GL_RENDERER));
    printf("GL_VERSION: %s
", glGetString(GL_VERSION));
    printf("GL_EXTENSIONS: %s
", glGetString(GL_EXTENSIONS));

   glutMainLoop();


Hi Frodak!

Nah, I’m using WGL and handling the windowing myself. Marshats just posted a few glut programs to try different ideas. The issues are the same on both windows and glut.