display lists and textures

i’ve been reading up on opengl stuff and from what i understand, it’s usually faster to use display lists when drawing the same shape over and over.

i’m trying to draw a rect in a display list which has a texture mapped onto it, and i’m not really sure how to proceed. i based myself on flight404’s latest particles stuff (in p5) and figured out that the code should look something like this:

  
  
glBindTexture( someTexture );  
glBegin(gl.GL_QUADS);  
glTexCoord4f( loc.x, loc.y, loc.z,  75 );  
glCallList( myRectList );  
glEnd();  
  

so, my idea is to extend ofTexture and override draw() so that instead of calling glVertex3i(…), i call glCallList(aList).

this is what i have so far:
ofListTexture.h

  
  
#include "ofTexture.h"  
  
class ofListTexture : public ofTexture {  
	  
    public:		  
        void    setList(int aList);  
        void    draw(float x, float y, float w, float h);  
                  
    private:  
        int     displayList;  
};  
  

ofListTexture.cpp

  
  
#include "ofListTexture.h"  
  
//----------------------------------------------------------  
void ofListTexture::setList(int aList) {  
    displayList = aList;  
}  
  
//----------------------------------------------------------  
void ofListTexture::draw(float x, float y, float w, float h) {  
  
	glEnable(textureTarget);  
  
	// bind the texture  
	glBindTexture( textureTarget, (GLuint)textureName[0] );  
  
		GLint px0 = 0;		// up to you to get the aspect ratio right  
		GLint py0 = 0;  
		GLint px1 = (GLint)w;  
		GLint py1 = (GLint)h;  
  
		if (bFlipTexture == true){  
			GLint temp = py0;  
			py0 = py1;  
			py1 = temp;  
		}  
  
		// for rect mode center, let's do this:  
		if (ofGetRectMode() == OF_RECTMODE_CENTER){  
			px0 = (GLint)-w/2;  
			py0 = (GLint)-h/2;  
			px1 = (GLint)+w/2;  
			py1 = (GLint)+h/2;  
		}  
  
		// -------------------------------------------------  
		// complete hack to remove border artifacts.  
		// slightly, slightly alters an image, scaling...  
		// to remove the border.  
		// we need a better solution for this, but  
		// to constantly add a 2 pixel border on all uploaded images  
		// is insane..  
  
		GLfloat offsetw = 0;  
		GLfloat offseth = 0;  
  
		if (textureTarget == GL_TEXTURE_2D){  
			offsetw = 1.0f/(tex_w);  
			offseth = 1.0f/(tex_h);  
		}  
		// -------------------------------------------------  
  
		GLfloat tx0 = 0+offsetw;  
		GLfloat ty0 = 0+offseth;  
		GLfloat tx1 = tex_t - offsetw;  
		GLfloat ty1 = tex_u - offseth;  
  
		glPushMatrix();  
		glTranslated(x, y, 0);  
		glBegin( GL_QUADS );  
            glTexCoord2f(x, y);  
            glCallList(displayList);  
		glEnd();  
		glPopMatrix();  
  
	glDisable(textureTarget);  
}  
  

i think i’m almost there, but i’m kind of stuck. i’m not sure what the params to glTexCoord2f(…) should be (between glBegin(GL_QUADS) and glEnd()).

am i on the right track ?

thanks for the help

Hey!

I am not sure how much of an improvement you will see with display lists and textures, as display lists are really optimized for quickly drawing a large number of vertices. They are great for things like complex 3D shapes with large number of vertices that don’t change position. You can then position, rotate and scale the shape by using the openGL glTranslatef, glRotatef, glScalef functions.

It looks like you are just trying to put the four vertexes of the texture’s quad in the display list - which as drawing four vertexes is not very taxing will result in almost 0 fps improvement.

Ideally you would do all those calculations that you currently have in the draw function
in the display list and then use openGL to position and scale the texture when you draw it.

I quickly made a small example class called ofTextureList that does this:
You can download it and a testApp using it here - http://www.openframeworks.cc/files/textureListSend.zip

However on my card (8800GT) I noticed no fps increase or decrease by toggling using or not using the display list. Maybe there is a big difference on other cards though?

The code for the class is bellow - I am sure it is not perfect but maybe it is helpful to build off of.

Also from: http://www.opengl.org/resources/faq/tec-…-aylist.htm

16.090 Will putting textures in a display list make them run faster?
In some implementations, a display list can optimize texture download and use of texture memory. In OpenGL 1.0, storing texture maps in display lists was the preferred method for optimizing texture performance. However, it resulted in increased memory usage in many implementations. Many vendors rallied around a better solution, texture objects, introduced in OpenGL 1.1. If your app is running on OpenGL 1.1 or later, texture objects are preferred.

**ofTexture is actually using texture objects - so I think we are already seeing the performance increase. display list + texture objects is most likely redundant. **

  
#ifndef _TEXTURE_LIST_H_  
#define _TEXTURE_LIST_H_  
  
#include "ofMain.h"  
  
  
class ofTextureList : public ofTexture{  
  
	public :  
	  
		//-------------------------------------------------------	  
		ofTextureList(){  
			bUseList = false;  
		}  
		  
		//-------------------------------------------------------  
		void setUseList(bool useList){  
			bUseList = useList;  
		}  
		  
		//-------------------------------------------------------		  
		void draw(int x, int y, int w, int h){  
				  
			//width and height - currently not implemented in draw for displayList  
			//would be a matter of using glScalef to scale the texture to the correct size  
  
			if(bUseList){  
				  
				glPushMatrix();  
					glTranslatef(x, y, 0);					  
					glCallList(texList);  
				glPopMatrix();  
				  
			}else{  
							  
				ofTexture::draw(x,y,w,h);  
			}  
		}  
		  
		//-------------------------------------------------------  
		void setupDisplayList(int scaleW = 0, int scaleH = 0){  
				  
				if(scaleW == 0) scaleW = width;  
				if(scaleH == 0) scaleH = height;  
			  
				GLint px0 = 0;  
				GLint py0 = 0;  
				GLint px1 = (GLint)scaleW;  
				GLint py1 = (GLint)scaleH;  
  
				if (bFlipTexture == true){  
					GLint temp = py0;  
					py0 = py1;  
					py1 = temp;  
				}  
				  
				GLfloat offsetw = 0;  
				GLfloat offseth = 0;  
  
				if (textureTarget == GL_TEXTURE_2D){  
					offsetw = 1.0f/(tex_w);  
					offseth = 1.0f/(tex_h);  
				}			  
				  
				GLfloat tx0 = 0+offsetw;  
				GLfloat ty0 = 0+offseth;  
				GLfloat tx1 = tex_t - offsetw;  
				GLfloat ty1 = tex_u - offseth;  
								  
				texList = glGenLists(1);  
				glNewList(texList, GL_COMPILE);			  
					glEnable(textureTarget);  
  
					// probably not a great idea to put it inside of the  
					// display list as it then makes a copy of the texture for every instance  
					// however I see no fps difference with it in or out of the display list   
					// (granted I am using an nvidia 8800GT)  
					glBindTexture( textureTarget, (GLuint)textureName[0] );					  
		  
						glBegin( GL_QUADS );  
							glTexCoord2f(tx0,ty0);			glVertex3i(px0, py0,0);  
							glTexCoord2f(tx1,ty0);			glVertex3i(px1, py0,0);  
							glTexCoord2f(tx1,ty1);			glVertex3i(px1, py1,0);  
							glTexCoord2f(tx0,ty1);			glVertex3i(px0, py1,0);  
						glEnd();  
  
					glDisable(textureTarget);  
				glEndList();  
				  
				//we now will use our display list instead of the normal draw method  
				bUseList = true;  
		}  
			  
	protected:		  
		  
		int		texList;  
		bool	bUseList;  
						  
};   
  
#endif  

Hi Theo,

First of all, thank you very much for that elaborate response!

I suspected that using a display list for a quad might be overkill, but when I read the corresponding chapter in the blue book, it said that what was expensive were the function calls and the trips to the graphics hardware, which are common no matter what you are drawing.

Anyways, I tried your testApp on my PowerBook with an NVIDIA GeForce FX Go5200 64MB and I also am not getting a difference in FPS. I thought maybe more volume would make a difference, so I tried drawing 1000 and 10000 textures each frame but once again, no difference between with and without display lists.

So, I guess it is redundant after all, but I’m not sure why… :slight_smile:

Thanks for the help!

Displaylists are the really old-skool way to compile geometry and execute it on the GPU repeatedly. For large amounts of vertices especially, displaylists are actually not that fast because you _still_ have the function call overhead. All displaylsits do is move the opengl function calls to a list of function calls stored on the GPU, which are run through just as if you were calling the functions from the CPU. The big difference is that the data doesn’t have to be transfered across the driver, which in a good number of cases can result in improved frame rates but it’s certainly not going to be the fastest your system is capable of.

Whenever you’re thinking of using displaylists, I would highly recommend looking instead at Vertex Arrays (for dynamic data) and Vertex Buffer Objects (for static and dynamic data). The former just takes a pointer to a buffer and can thus draw a very large number of vertices with 1 function call as opposed to N function calls.

The same applies to VBOs with the difference being that you can store VBOs on the GPU just like textures. Thus you don’t have data transfer overhead. When you use VBOs, you are doing about as much as you possible can to speed up your drawing code as there is a minimum of overhead. There are still some things to keep in mind when using VBOs however. The most important is to favor using GL_TRIANGLES with an index buffer over using GL_TRIANGLE_STRIP (at least on OSX). There’s something in the drivers that makes the first path to the vertex processor faster than the latter. I think it has to do with expansion of adjacency in the triangle strip mode.

Fore more info on this, see:
http://www.songho.ca/opengl/gl-vertexarray.html
http://www.songho.ca/opengl/gl-vbo.html