#123684 - 3D_geek - Fri Mar 30, 2007 7:15 am
Suppose for sake of argument that I allocated RAM banks A and B for textures (they are 128kbytes each). Now assume I'm using the 16 bits per texel mode and I have the following set of textures:
Seven maps each of: 128x128x2bytes = 32kbytes each
Two maps each of 8x8x2 bytes = 128 bytes each
That's a total of 32k*7+128*2 = 224.25kbytes. So theoretically, I have plenty of texture memory (2 banks==256kbytes - I only need 224.25kbytes).
However - if I say:
glTexImage2D ( .... 8x8 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 8x8 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
...then, finally:
glTexImage2D ( .... 128x128 map ....);
...the last call fails because it claims to have run out of texture map memory. The reason being (as far as I can see from the libnds code) that the system simply stuffs textures into the first bank in the order they are presented - and when there is not enough room left in that bank for the next texture, it moves on to the next bank and starts allocating from there. However, in the case above, this means that the first 8x8 map and the next three 128x128's go into bank A, then the fourth 128x128 won't quite fit - so it goes onto bank B, then in goes the 8x8 and then two more 128x128's - and finds that there is not quite enough room left for the final 128x128 map.
The problem is that there was quite a bit of space left (just short of 32kbytes) at the end of bank A that never got used. If the second 8x8 map had gone into there instead of into bank B, there would have been enough memory left over for the last map.
This is a classic memory fragmentation problem - the best heuristic for which is always to put each new object into the smallest space into which it'll fit.
Hence, the algorithm needs to remember how much memory there is left at the end of each bank when it opens a new one. Then it can fit each new texture into whichever bank has the least amount of room left into which the map will fit. If that were the case then the second of the tiny 8x8 maps would have been stuck into the end of bank A instead of taking a teeny bit out of bank B and thereby preventing the last large map from just sneaking in.
In the absence of that change, it's stongly advised that if your applications need more than 128kbytes of textures that you follow the rule of allocating your maps in some very carefully pre-planned order in order to give yourself the best chance of fitting everything in, RIght now, I think the simplest strategy is to allocate your largest maps first, moving gradually down to doing the smallest ones last.
...but it really needs to be fixed properly in libnds.
Seven maps each of: 128x128x2bytes = 32kbytes each
Two maps each of 8x8x2 bytes = 128 bytes each
That's a total of 32k*7+128*2 = 224.25kbytes. So theoretically, I have plenty of texture memory (2 banks==256kbytes - I only need 224.25kbytes).
However - if I say:
glTexImage2D ( .... 8x8 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 8x8 map ....);
glTexImage2D ( .... 128x128 map ....);
glTexImage2D ( .... 128x128 map ....);
...then, finally:
glTexImage2D ( .... 128x128 map ....);
...the last call fails because it claims to have run out of texture map memory. The reason being (as far as I can see from the libnds code) that the system simply stuffs textures into the first bank in the order they are presented - and when there is not enough room left in that bank for the next texture, it moves on to the next bank and starts allocating from there. However, in the case above, this means that the first 8x8 map and the next three 128x128's go into bank A, then the fourth 128x128 won't quite fit - so it goes onto bank B, then in goes the 8x8 and then two more 128x128's - and finds that there is not quite enough room left for the final 128x128 map.
The problem is that there was quite a bit of space left (just short of 32kbytes) at the end of bank A that never got used. If the second 8x8 map had gone into there instead of into bank B, there would have been enough memory left over for the last map.
This is a classic memory fragmentation problem - the best heuristic for which is always to put each new object into the smallest space into which it'll fit.
Hence, the algorithm needs to remember how much memory there is left at the end of each bank when it opens a new one. Then it can fit each new texture into whichever bank has the least amount of room left into which the map will fit. If that were the case then the second of the tiny 8x8 maps would have been stuck into the end of bank A instead of taking a teeny bit out of bank B and thereby preventing the last large map from just sneaking in.
In the absence of that change, it's stongly advised that if your applications need more than 128kbytes of textures that you follow the rule of allocating your maps in some very carefully pre-planned order in order to give yourself the best chance of fitting everything in, RIght now, I think the simplest strategy is to allocate your largest maps first, moving gradually down to doing the smallest ones last.
...but it really needs to be fixed properly in libnds.