genpfault's answer of 'Use vertex buffers' is the correct answer, but it's worth noting that if you're constrained on your target environment and/or can't tackle a port away from the OpenGL 1.x API, there is an alternative in display lists.
With a display list you create and activate a list object (using glGenLists
and glNewList
) which essentially acts as a recorder for your vertex calls. After you've activated the list you then call your rendering calls (glBegin
, glEnd
, glVertex
, etc) as you normally would. When you're done with the geometry, you call glEndList
, which completes the recording. In future when you want to render the same geometry you can simply call glCallList
as a shortcut. Because the list data can be captured by the driver and stored on the video card, the overhead is much less.
However, the use of display lists has caveats. There's a whole set of OpenGL functions that can't be called from within a list, and they're only applicable for static geometry. Also, there's no guarantee that the driver will actually store the information on the video card, meaning that there's not necessarily a great performance boost. Your best bet is to migrates away from immediate mode and the fixed function pipeline.