You can often improve performance by storing frequently used commands in a
display list. If you plan to redraw the same geometry multiple times, or if
you have a set of state changes that need to be applied multiple times,
consider using display lists. Display lists allow you to define the geometry
and/or state changes once and execute them multiple times. Some graphics
hardware may store display lists in dedicated memory or may store the data
in an optimized form for rendering.

The biggest drawback of using display lists is data expansion. The display
list contains an entire copy of all your data plus additional data for each
command and for each list. As a result, tuning for display lists focuses
mainly on reducing storage requirements. Performance improves if the data that
is being traversed fits in the cache. Follow these rules to optimize display
lists:

Call glDeleteLists() to delete display lists that are no longer
needed. This frees storage space used by the deleted display lists and
expedites the creation of new display lists.

Avoid duplication of display lists. For example, if you have a scene
with 100 spheres of different sizes and materials, generate one display list
that is a unit sphere centered about the origin. Then reference the sphere
many times, setting the appropriate material properties and transforms each
time.

Make the display lists as flat as possible, but be sure not to exceed
the cache size. Avoid using an excessive hierarchy with many invocations to
glCallList(). Each glCallList() invocation requires the OpenGL
implementation to do some work (e.g., a table lookup) to find the designated
display list. A flat display list requires less memory and yields simpler
and faster traversal. It also improves cache coherency.

On the other hand, excessive flattening increases the size. For example, if
you're drawing a car with four wheels, having a hierarchy with four pointers
from the body to one wheel is preferable to a flat structure with one body and
four wheels.

Avoid creating very small display lists. Very small lists may not
perform well since there is some overhead when executing a list. Also, it is
often inefficient to split primitive definitions across display lists.

If appropriate, store state settings with geometry; it may improve
performance.

For example, suppose you want to apply a transformation to some geometric
objects and then draw the result. If the geometric objects are to be
transformed in the same way each time, it is better to store the matrix in the
display list.