Why does CPU load change depending on resolution?

Hi!

I have downloaded NeHe’s lesson33 (GLX version) and compiled it.
But when running this source code (some modification done by me, but shouldn’t be significant changes anyway), I get different CPU load depending on the resolution I select.
If I select resolution to be 1920x1200 (my desktop resolution) then my CPU is only using about 2-4%, but if I select it to be something else (i.e: 1024x768) my CPU is about 70-80%. This I measured with command utility “top”.

Why is my program using so much of the CPU ?

Thanks in advance :smiley:

Kim


/*
 * IMPORTANT: install "libxxf86vm-dev" package before compiling.
 *
 * TO COMPILE:
 *    gcc -Os -Wall -ansi -pedantic -ffloat-store -c -g -o main.o main.c
 *    gcc -g -o lesson33 main.o -L/usr/X11R6/lib -lm -lGL -lXxf86vm
 *
 * Nehe Lesson 33 Code (ported to Linux//GLX by Patrick Schubert 2003
 * with help from the lesson 1 basecode for Linux/GLX by Mihael Vrbanec)
 */

#include <GL/glx.h>
#include <GL/gl.h>
#include <X11/extensions/xf86vmode.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

/* Application size */
static int desk_size_x = 1920; /* 1024;    <--- Changing size affects CPU, why? */
static int desk_size_y = 1200; /* 768;     <--- Low CPU load if your desktop resolution, but  */
                               /*          <--- high CPU load if not. Why 2-4% to 70-80% CPU load??? */
                               /*          <--- Used "top" to messaure */

typedef struct
{
    Display *dpy;
    int screen;
    Window win;
    GLXContext ctx;
    XSetWindowAttributes attr;
    Bool fs;
    XF86VidModeModeInfo deskMode;
    int x, y;
    unsigned int width, height;
    unsigned int depth;
} GLWindow;

static GLWindow GLWin;
static XEvent event;
static int running;
float	spin;													/* Spin Variable */

static void initGL(void);
static void resizeGLScene(void);
static void swapBuffers(void);

void createGLWindow(const char*,int,int,int,int);
void killGLWindow(void);
void MessageHandler(void);
void run(void);

int drawGLScene(GLvoid)											/* Here's Where We Do All The Drawing */
{
	int loop;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			/* Clear The Screen And The Depth Buffer */
	glLoadIdentity();											/* Reset The Modelview Matrix */
	glTranslatef(0.0f,0.0f,-10.0f);								/* Translate 20 Units Into The Screen */

	spin += 0.05f;												/* Increase Spin */

	for(loop = 0;loop < 20;loop++)								/* Loop Of 20 */
	{
		glPushMatrix();											/* Push The Matrix */
		glRotatef(spin+loop*18.0f,1.0f,0.0f,0.0f);				/* Rotate On The X-Axis (Up - Down) */
		glTranslatef(-2.0f,2.0f,0.0f);							/* Translate 2 Units Left And 2 Up */

		glBegin(GL_QUADS);										/* Draw Our Quad */
			glVertex3f(-1.0f,  1.0f, 0.0f);
			glVertex3f( 1.0f,  1.0f, 0.0f);
			glVertex3f( 1.0f, -1.0f, 0.0f);
			glVertex3f(-1.0f, -1.0f, 0.0f);
		glEnd();												/* Done Drawing The Quad */
		glPopMatrix();											/* Pop The Matrix */
	}
	return True;												/* Keep Going */
}

int main(void)
{
	createGLWindow("NeHe's Lesson 33",desk_size_x,desk_size_y,24,False); 		/* Create our window*/
	run();														/* Start Event-Loop */
	killGLWindow();												/* shutdown window */
	return 0;
}


/* Create our window */
void createGLWindow(const char* title,int width,int height,int bits,int fullscreen)
{
	int attrListSgl[] = { GLX_RGBA, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, None};
	int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16, None};

	XVisualInfo *vi;
	Colormap cmap;
	int dpyWidth, dpyHeight;
	int i;
	int vidModeMajorVersion, vidModeMinorVersion;
	XF86VidModeModeInfo **modes;
	int modeNum;
	int bestMode;
	Atom wmDelete;
	Window winDummy;
	unsigned int borderDummy;

	GLWin.fs = fullscreen;
	bestMode = 0;

	GLWin.dpy = XOpenDisplay(0);
	GLWin.screen = DefaultScreen(GLWin.dpy);
	XF86VidModeQueryVersion(GLWin.dpy, &vidModeMajorVersion, &vidModeMinorVersion);

	XF86VidModeGetAllModeLines(GLWin.dpy, GLWin.screen, &modeNum, &modes);

	GLWin.deskMode = *modes[0];

	for (i = 0; i < modeNum; i++)
	{
		if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height))
		{
			bestMode = i;
		}
	}

	vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl);
	if(NULL == vi)
	{
		vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl);
		printf("Singlebuffered : true
");
	}
	else
	{
		printf("Doublebuffered : true
");
	}

	GLWin.ctx = glXCreateContext(GLWin.dpy, vi, 0, GL_TRUE);

	cmap = XCreateColormap(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),vi->visual, AllocNone);
	GLWin.attr.colormap = cmap;
	GLWin.attr.border_pixel = 0;

	if(GLWin.fs)
	{
		XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, modes[bestMode]);
		XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
		dpyWidth = modes[bestMode]->hdisplay;
		dpyHeight = modes[bestMode]->vdisplay;
		XFree(modes);
		GLWin.attr.override_redirect = True;
		GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
		GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
								0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual,
								CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
								&GLWin.attr);
		XWarpPointer(GLWin.dpy, None, GLWin.win, 0, 0, 0, 0, 0, 0);
		XMapRaised(GLWin.dpy, GLWin.win);
		XGrabKeyboard(GLWin.dpy, GLWin.win, True, GrabModeAsync,GrabModeAsync, CurrentTime);
		XGrabPointer(GLWin.dpy, GLWin.win, True, ButtonPressMask,
		GrabModeAsync, GrabModeAsync, GLWin.win, None, CurrentTime);
	}
	else
	{
		GLWin.attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
		GLWin.win = XCreateWindow(GLWin.dpy, RootWindow(GLWin.dpy, vi->screen),
								  0, 0, width, height, 0, vi->depth, InputOutput, vi->visual,
								  CWBorderPixel | CWColormap | CWEventMask, &GLWin.attr);
		wmDelete = XInternAtom(GLWin.dpy, "WM_DELETE_WINDOW", True);
		XSetWMProtocols(GLWin.dpy, GLWin.win, &wmDelete, 1);
		XSetStandardProperties(GLWin.dpy, GLWin.win, title, title, None, NULL, 0, NULL);
		XMapRaised(GLWin.dpy, GLWin.win);
	}

	glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx);
	XGetGeometry(GLWin.dpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, &GLWin.width, &GLWin.height, &borderDummy, &GLWin.depth);

	printf("Direct Rendering: %s
",glXIsDirect(GLWin.dpy, GLWin.ctx) ? "true" : "false");
	printf("Running in %s mode
",GLWin.fs ? "fullscreen" : "window");

	initGL();
}

/* Release our window */
void killGLWindow(void)
{
	if(GLWin.ctx)
	{
		if(!glXMakeCurrent(GLWin.dpy, None, NULL))
		{
			printf("Error releasing drawing context : killGLWindow
");
		}
		glXDestroyContext(GLWin.dpy, GLWin.ctx);
		GLWin.ctx = NULL;
	}

	if(GLWin.fs)
	{
		XF86VidModeSwitchToMode(GLWin.dpy, GLWin.screen, &GLWin.deskMode);
		XF86VidModeSetViewPort(GLWin.dpy, GLWin.screen, 0, 0);
	}
	XCloseDisplay(GLWin.dpy);
}

void MessageHandler()
{
			switch(event.type)
			{
				case Expose:
					if (event.xexpose.count != 0)
						break;
					break;
				case ConfigureNotify:
					if ((event.xconfigure.width != GLWin.width) ||
						(event.xconfigure.height != GLWin.height))
					{
						GLWin.width = event.xconfigure.width;
						GLWin.height = event.xconfigure.height;
						resizeGLScene();
					}
					break;
				case KeyPress:
					switch(XLookupKeysym(&event.xkey,0))
					{
					case XK_Escape:									/* Quit application */
						running = 0;
						break;
					case XK_F1:										/* Switch fullscreen<->window mode */
						killGLWindow();
						createGLWindow("NeHe's Lesson 33",desk_size_x,desk_size_y,24,!GLWin.fs);
						break;
					}
					break;
				case ClientMessage:
					if (*XGetAtomName(GLWin.dpy, event.xclient.message_type) == *"WM_PROTOCOLS")
					{
						running = 0;
					}
					break;
				default:
					break;
			}
	return;
}

/* Our event loop */
void run(void)
{
	running = 1;
	while(running)
	{
		while(XPending(GLWin.dpy))
		{
			XNextEvent(GLWin.dpy, &event);
			MessageHandler();
		}

		drawGLScene();
		swapBuffers();
	} 
}

/* Setup basic Opengl stuff */
static void initGL(void)
{
	glShadeModel(GL_SMOOTH);
	glEnable(GL_TEXTURE_2D);
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	resizeGLScene();
	glFlush();
}

/* Resize,set viewport,frustum */
static void resizeGLScene(void)
{
	float width,height;
	if(GLWin.height == 0)
		GLWin.height = 1;
	if(GLWin.width == 0)
		GLWin.width = 1;
	glViewport(0,0,GLWin.width,GLWin.height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	width = 0.5f;
	height = 0.5f * ((float)(GLWin.height)/GLWin.width);
	glFrustum(-width,width,-height,height,1.0f,100.0f);
	glMatrixMode(GL_MODELVIEW);
}

/* Swap Buffers */
static void swapBuffers(void)
{
	glXSwapBuffers(GLWin.dpy, GLWin.win);
}

void run(void){
	running = 1;
	while(running) {
		while(XPending(GLWin.dpy)) {
			XNextEvent(GLWin.dpy, &event);
			MessageHandler();
		}
		drawGLScene();
		swapBuffers();
	} 
}

If drawGLScene and swapBuffers are very fast your program will keep spinning on the while cicle burning CPU cicle.
With higher resolution your application will spend more time on the GPU, leaving the CPU free.

it’s pretty simple, the faster a scene takes to render the more frames it renders, and for each frame it preforms a set amount of cpu work, so higher framerate= higher cpu load.

there may also be some differences in the application scheduling that different rendering modes have.
And finally if you have v-sync turned on the higher resolution could cause the framerate to drop under the v-sync threshold causing it sync up with half the v-sync rate.

so there is any of a multitude of reasons why

Rosario and zeoverlord, you both are correct.
After some testing I could see the CPU load change when I did resize the window.

Thanks for reply, it surly cleared something up for me :smiley:

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.