| |
|
|
||||
![]() |
||||||
| |
|
|||||
|
Texture Priorities Depending on your operating environment, your performance requirements, and your boss's mood, you may elect to do your own texture memory management. Conceivably, you could have one really large texture and several smaller textures in your scene. Suppose you keep swapping the large texture back and forth to make room for some little texture. Suppose you're using a PCI graphics card with limited texture memory available, and all this swapping back and forth is killing your frame rate. Wouldn't it be nice if you could tell OpenGL that your bigger textures are going to be used for every frame, and that if it needs to make room for more textures on board, to discard the smaller textures first? By default, most OpenGL drivers will use an LRU (Least Recently Used) algorithm to swap textures. This means that if your big texture is used once for the floor or ceiling, it could continually get bumped out of your graphics card's memory to make room for a bunch of little textures that are used by multiple objects in the scene (say, for debris on the floor). In this scenario, even texture sorting won’'t provide the maximum benefit, because one large texture is continually being shuffled back and forth over the bus (PCI or AGP — in either case it takes more time than not moving the texture). While some APIs force you to do all the low-level details of texture management, OpenGL has a much more elegant solution. OpenGL's philosophy is that all textures should be resident. This approach provides the optimum texturing performance. So what happens when there isn't enough room for all textures to be resident? OpenGL will make the most commonly used textures resident, which, in a great many cases, is a good memory management solution. As in the example given previously, when all textures cannot be resident, the most commonly used textures may not be those that you want to keep in the card's memory. If you have to do texture swapping, you want to move the smaller textures, not the bigger ones. You may also need to change this prioritization from scene to scene or room to room within your environment. You could write your own texture management algorithms, taking into account the amount of memory on the board and the size of the textures. You could then call special API functions to lock specific textures in graphics memory and juggle all of this throughout your game or simulation. Many users of other APIs have bemoaned OpenGL's lack of support for this kind of approach. But this complaint is rather like insisting on a VW do-it-yourself kit at the car lot instead of just taking the keys to the Ferrari. After all, with a kit you can do your own performance tuning. OpenGL's answer to this situation is texture priorities. A single function call, glPrioritizeTextures(), is all that is required, and it works with texture objects. void glPrioritizeTextures(GLsizei n, GLuint *textures, GLclampf *priorities); This function lets you tell OpenGL which texture objects are the most important to keep in graphics memory. The first parameter is the number of texture objects, the second is an array of texture object names (remember that these are integer names), and the third parameter is an array of priorities. Texture priorities are floating-point values ranked from 0.0 to 1.0, with 1.0 being the highest priority. You can call this function as many times as you need to in order to reassign texture priorities. Texture objects with a 1.0 priority will most likely be in graphics memory at any given time, and those with 0.0 priority will only be in memory if they have been used at least once and there is still texture memory to burn. Being in graphics memory is called being resident in OpenGL terminology. Prioritizing textures allows OpenGL to worry about how many and which textures will fit in the available texture memory space. Compromise is always possible. Even when you do your own low-level texture management in some other API, you’'ll still have to handle a situation in which you have more textures than will fit in texture memory. Suppose, you want to know if all your important textures are actually resident? One final function worth mentioning here can help you with this: glAreTexturesResident(). GLboolean glAreTexturesResident(GLsizei n, GLuint *textures, GLboolean *residences) Given an array of texture objects (stored in *textures), this function fills an array of corresponding flags (*residences) that will tell you whether the texture object is resident or not. You can use this function to load all of your texture objects and then test to see if they all fit within local texture memory. For example, you might want to adjust the size of some large texture in order to get more texture objects resident. A nice feature of this function is that if all of the texture objects specified are resident, the function returns TRUE. Thus, you can avoid having to test each individual flag returned in *residences. The last example program, REFLECT_P.EXE, uses the texture priority functions to set the larger marble texture as the highest priority. It also checks to see if all textures are fitting within available hardware texture memory and displays this information, along with the frame rate, in the window caption (Figure 4).
On a modern graphics card with plentiful texture memory, all textures in this example will be resident. A good exercise would be to experiment with the REFLECT_P.EXE and REFLECT_SORTED.EXE programs on different hardware configurations. You may need to experiment with changing the texture sizes in order to exceed texture memory on one of the newer big-boy boards (32MB of memory on board). By experimenting with different texture sizes and different amounts of available texture memory, you'll find that the best performance is achieved when all textures can be resident. When all textures cannot possibly be resident, you'll see an improvement in REFLECT_P.EXE (textures sorted and using priorities) over REFLECT_SORTED.EXE (just sorting textures). Richard S. Wright Jr. is the lead author of the OpenGL SuperBible and does OpenGL consulting for Starstone Software Systems Inc. You can download the code and textures for the sample programs from Richard’'s OpenGL web site at http://www.starstonesoftware.com/OpenGL. |
|
|