Game Development Community

Shared dts textures

by James Spellman · in Torque Game Engine · 11/09/2005 (3:12 pm) · 16 replies

I've got several character models that use a common texture for eyes, teeth, tongue, etc. If I put head.png in the folder path, all my characters seem to find it, but when I do a dumptexturestats, it appears that the texture is loaded once per character. Is there a way to have them all reference a single texture?

#1
11/09/2005 (4:22 pm)
I'm curious about this too. It would seem to be much faster if they all referenced a single texture. Perhaps there's a way to load them all textureless and then create a single texture object and apply it to all of them? Not sure if this is possible using script alone, but may be worth a try.
#2
11/10/2005 (6:08 am)
I looked at the code, and it seems to return the same texture object if it's already loaded:

TextureObject *TextureManager::loadTexture(const char* textureName, TextureHandleType type, bool clampToEdge)
{
   // Catch if we're trying to load a blank texture...
   if(!textureName || dStrlen(textureName) == 0)
      return NULL;
   
   textureName = StringTable->insert(textureName);
   
   TextureObject *ret = TextureDictionary::find(textureName, type, clampToEdge);

   if(ret)
      return ret;

   GBitmap *bmp = loadBitmapInstance(textureName);
   if(!bmp)
   {
      Con::warnf("Could not locate texture: %s", textureName);
      return NULL;
   }

   return registerTexture(textureName, bmp, type, clampToEdge);
}

The call to TextureDictionary::find() looks if the texture has already been loaded, and returns the existing texture if so. Did you monitor the memory? Check if loading different .DTS files that all use the same HUGE texture causes the RAM usage to increase proportionally to loading multiple copies of that texture.
#3
11/10/2005 (8:19 am)
I used DumpTextureStats after I realized that each character model was adding about 5MB to my memory footprint. If I had the following files (simplified):

shapes\head.png
shapes\guyone\guyone.dts
shapes\guytwo\guytwo.dts

The texture stats would look something like (simplified):

256K (shapes/guyone/head)
256K (shapes/guytwo/head)

So I assuming it is adding the texture filename to the local path and thus guyone/head and guytwo/head are "different" textures. I'll try debugging this later today and see if I guessed correctly. If so, I wonder if there would be grievous bodily harm if the texture names didn't store the path, as long as I remember that texture filenames would have to be unique.
#4
11/10/2005 (9:47 am)
Just put them up a directory. The resource manager looks in all parent directories for a texture if it can't find it to begin with.

Directories do matter in texture name, wouldn't you hate to get someone else's texture in your art just cuz they happened to use a common name like "whitebar" for a texture? :)
#5
11/10/2005 (2:48 pm)
They are found easily enough when moved up a directory but are managed in memory as though they were unique assets. I would hope that it would at least use the directory that they were found in as opposed to the directory they were referenced from.

I'm concerned that my 256KB texture is using 2.5MB of RAM just because it is referenced from 10 different sources.

I would probably throw a fit and then fire the artist for not adhearing to the naming conventions policy or failing to use the asset manager correctly. But that's just 'cause I'm evil. Plus "whitebar" is a little too descriptive. "White4old" is more like what I'm used to seeing. ;)
#6
11/10/2005 (2:55 pm)
[off topic]Btw, I'd like to thank Ben for personally responding to just about every piece of drival I post in the forums. It really helps me build confidence in my projects and for GG as a whole.[/off topic]
#7
11/10/2005 (9:59 pm)
Hmm... That's an interesting occurence... and significant enough I put in a fix for it. Now will return TexObj's from higher up the tree if they exist. In SVN, soon to be in your hands.
#8
11/10/2005 (9:59 pm)
(Thanks for the kind words. Good luck with your project! :)
#9
11/11/2005 (9:23 am)
Wait? It does load the texture again? That might explain the massive RAM usage in our games, with some simply interiors eating 2~3MB per instance.
#10
11/11/2005 (11:54 am)
@ Ben, can you post the fix somewhere, like in this thread. Its not viable for me to port my game to 1.4 so I'd like to make the changes in 1.3
#11
11/11/2005 (12:04 pm)
@Manoel

Turn on GATHER_METRICS to enable the dumpTextureStats console function. The log looks something like:

aaa 4: (1, yes) 349525 (sim/data/overhead/p75610.png)
aaa 4: (1, yes) 1398101 (sim/data/shapes/Assault_Items/DesertEagle_Texture)
aaa 4: (2, yes) 349525 (sim/data/shapes/cast/Johnson/head)
aaa 4: (2, yes) 349525 (sim/data/shapes/cast/Martin/head)
aaa 4: (2, yes) 349525 (sim/data/shapes/cast/Kassie/head)
aaa 7: (2, no) 87383 (sim/data/interiors/coffee_shop/COUNTER_SIGN)

We swap out decals for an overhead projector, so I wanted to make sure there was only one in memory at any time. Second, I noticed that someone put in a 1024x1024 texture for a handgun. Overkill! Lastly I noticed that a common texture showed up three times.

@Ben

I'd really like to try your fix for a build I need to to today if at all possible. ;)
#12
11/11/2005 (7:04 pm)
The key change is here:

TextureObject *TextureManager::loadTexture(const char* textureName, TextureHandleType type, bool clampToEdge, bool checkOnly /* = false */)
{
   // Catch if we're trying to load a blank texture...
   if(!textureName || dStrlen(textureName) == 0)
      return NULL;

   textureName = StringTable->insert(textureName);

   TextureObject *ret = TextureDictionary::find(textureName, type, clampToEdge);

   GBitmap *bmp = NULL;

   if(!ret)
   {
      // Ok, no hit - is it in the current dir? If so then let's grab it
      // and use it.
      bmp = loadBitmapInstance(textureName, false);

      if(bmp)
         return registerTexture(textureName, bmp, type, clampToEdge);

      // Otherwise...
      // We want to check for previously loaded textures with the same
      // name in higher directories. loadBitmapInstance does this too
      // but we want to reuse the actual texture object, if possible,
      // not just load things many times into video memory!
      char fileNameBuffer[512];
      dStrcpy(fileNameBuffer, textureName);

      // If unable to load texture in current directory
      // look in the parent directory.  But never look in the root.
      char *name = dStrrchr(fileNameBuffer, '/');
      if (name)
      {
         *name++ = 0;
         char *parent = dStrrchr(fileNameBuffer, '/');
         if (parent)
         {
            parent[1] = 0;
            dStrcat(fileNameBuffer, name);
            ret = loadTexture(fileNameBuffer, type, clampToEdge, true);
         }
      }
   }

   if(ret)
      return ret;

   // If we're just checking, fail out so we eventually get around to
   // loading a real bitmap.
   if(checkOnly)
      return NULL;

   // Ok, no success so let's try actually loading a texture.
   bmp = loadBitmapInstance(textureName);

The mysterious new boolean argument on loadBitmapInstance is there to make it not recurse, which I'll leave as an exercise for the reader. :)

I think that's it. Good luck with your build. :)
#13
11/11/2005 (7:52 pm)
@ Ben, thanks, builds fine with only one error at this point bmp = loadBitmapInstance(textureName, false);

Did you make changes in the loadBitmapInstance method?

I just assumed it's a left over from your dev attempts and left out the additional false parameter. It appears to work fine...
#14
11/11/2005 (9:29 pm)
I assumed that the false was to prevent loadBitmapInstance from looking in the parent directories. I added a parameter something like checkParent = true to it. In the end it saved me about 14MB just from one common texture!

Thanks again, Ben!
#15
11/12/2005 (2:50 am)
@Duncan:

Quote:The mysterious new boolean argument on loadBitmapInstance is there to make it not recurse, which I'll leave as an exercise for the reader. :)

:)

@James:

Glad to be of help, and glad it worked for you. ;)
#16
11/12/2005 (11:13 am)
Ok, got it, my attention to detail diminishes in direct proportion to any increase in multitasking.