PDA

View Full Version : hardware question



mikau
12-08-2009, 12:08 PM
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!

pjcozzi
12-08-2009, 01:11 PM
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 (http://developer.nvidia.com/object/using_VBOs.html) for a performance boost.

Regards,
Patrick

mikau
12-08-2009, 01:59 PM
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?

mark ds
12-08-2009, 02:08 PM
what framerate do you get if you draw just one (out of the 400) quads?

mikau
12-08-2009, 04:08 PM
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.

mikau
12-08-2009, 04:54 PM
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.

marshats
12-08-2009, 05:11 PM
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);

pjcozzi
12-08-2009, 05:43 PM
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

mikau
12-08-2009, 06:43 PM
marshats: it was a liiittle better. But not significantly.

Isn't that strange?

mikau
12-08-2009, 07:08 PM
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.

marshats
12-08-2009, 07:44 PM
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.

mikau
12-08-2009, 08:17 PM
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.

mikau
12-08-2009, 09:07 PM
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...

marshats
12-08-2009, 09:10 PM
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(&amp;argc, argv);
glutInitDisplayMode(GLUT_DOUBLE);
glutCreateWindow("FPS test /w glutTimerFunc");

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

init();

glutMainLoop();
return 0;
}

mikau
12-08-2009, 10:18 PM
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!

marshats
12-09-2009, 07:57 PM
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 35*8" to make the number of quads (35*8)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(&amp;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,

mikau
12-09-2009, 08:11 PM
I compiled and executed your code. It dropped to 13 fps.

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

marshats
12-09-2009, 08:44 PM
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.

Frodak
12-10-2009, 11:01 AM
Is it an issue that you are not getting the accelerated graphics with GLUT?

What does this print out.


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

glutMainLoop();

mikau
12-11-2009, 12:10 AM
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.

Stephen A
12-11-2009, 03:31 AM
Ensure that you are using a real OpenGL driver than Microsoft's GDI/D3D emulation layer. Microsoft, in their infinite wisdom don't install OpenGL drivers by default. You have to download and install them yourself from Intel's website.


printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));

This will tell you which driver you are using (if it contains "Microsoft" you have a problem).

mikau
12-11-2009, 05:56 AM
Hi, Stephan, thanks for the info. I tested that statement and the result was "Intel". Is that what we'd like to see?

Stephen A
12-11-2009, 09:31 AM
Yes.

I'd suggest checking for newer drivers on Intel's website, but I don't have any other advice to offer on the issue...