[sldev] Texture caching

Steve steve at lindenlab.com
Tue Mar 20 11:25:41 PDT 2007


Hi folks. Good to see other people looking at the texture pipeline 
quagmire. Some notes for you all:

1. Anyone looking at texture caching, be sure to keep up with the latest 
code drops because I have been rewriting that system in "First Look" 
(which is now in the main source branch) and will be releasing it very soon.

2. The way we calculate texture pixel coverage (and therefore desired 
discard level) is as follows:
 a. When anything using a texture is rendered. set its pixel coverage to 
MAX(current pixel coverage, rendered pixel coverage)
 b. Once a frame, reduce the current pixel coverage of all textures by 10%.
This way, everything rendered recently has an accurate pixel coverage, 
and everything not rendered degrades over time.  
gImageList.mForceResetTextureStats merely tells the code "assume that 
all textures are no longer visible" and resets the pixel area of all 
texture to 0. As soon as they are rendered their pixel coverage is updated.

3. Even if a textures pixel coverage gets set to 0, we do not 
immediately discard the texture data. We only discard the data if we 
need room for more textures (in which case we discard the textures with 
the lowest priority), or if no object in view is using the texture *and* 
30 seconds have elapsed.

4. Tateru is absolutely correct in that caching textures to disk mostly 
just saves on network bandwidth. Unless you have a slow network 
connection, it can be almost as fast to load textures across the network 
as from a disk, especially if that disk is not especially fast or is 
fragmented. Decoding the textures takes quite a bit longer. However, if 
you have multiple CPUs and enable Client > Rendering > Run Multiple 
Threads, the decoding will be done on the second CPU and go much faster.

If you're looking for a problem to solve, I would think about this 
scenario for a system with 256+ MB texture RAM:
1. Log in to region A. Stay there long enough for a bunch of textures to 
load. Generally this will be < 128MB.
2. Teleport to region B and stay long enough for textures to load. Stay 
 > 30 seconds.
3. Teleport back to region A.

The system will have forgotten about all of the textures in region A, 
even though it could have kept them around because texture RAM would not 
have filled up. The reason we don't just keep them around is that it 
becomes something of a bookkeeping nightmare. If you teleported to a 
region C in between, the textures in region A would need to be 
discarded. Also, if region A, B, and C all have a bunch of small 
textures, we might teleport to regions D, E, and F and never need to 
discard any of those textures. However, each texture carries additional 
system RAM and CPU overhead, so tracking tens of thousands of textures 
is problematic in itself.

Well, enough ranting from me for now, back to work.

Cheers,
-Steve



Jason Giglio wrote:
> Texture caching doesn't use VFS anymore.
>
> I'm actually working on this right now (well more like trying to 
> understand it so I can start), we should coordinate our efforts.
>
> All I have so far is a code cleanup patch for the texture cache 
> subsystem.
>
> Please get on IRC and catch me on the #opensl channel on efnet so we 
> can help each other figure this out and not step on each other's 
> work.  I was hoping someone else would be interested in texture 
> caching so I have someone to work with on this.  The code isn't 
> commented *at all*.
>
> Attached is the code cleanup patch, I haven't submitted it to LL 
> because I plan on making a lot more changes eventually.
>
> -Jason
>
> Tateru Nino wrote:
>> Well, not 100% from scratch. The textures are cached on disk - which 
>> saves a lot of bandwidth, but does not seem to give a major time-gain 
>> considering how long it takes to initialise, load and decode each 
>> texture.
>>
>> The VFS is pretty deep voodoo. I've not delved into it yet. Heck, 
>> I've stared at the source-code for like ten minutes only. That's how 
>> I found this apparent cache-invalidation - but then, I knew what I 
>> was looking for.
>>
>> Gary Wardell wrote:
>>> Hi,
>>>
>>> It sure looks like it works that way.
>>>
>>> I have two houses and I just went to house A, let it fully rez, TPed 
>>> to house B, let it fully res, TPed back to A and it sure
>>> looked like it started all over again from scratch.
>>>
>>> Since you bring up caching, any ideas why if I set the cache to over 
>>> 200mb it routinely gets corrupted to the point causing the
>>> viewer to crash immediately upon startup?  And even at 200 it 
>>> sometimes does this, but not as frequently?
>>>
>>> One might think it should reinitialize the cache upon starting.
>>>
>>> BTW, Linden told me to set it to the full 1GB.
>>>
>>> Gary
>>>
>>>  
>>>> -----Original Message-----
>>>> From: sldev-bounces at lists.secondlife.com
>>>> [mailto:sldev-bounces at lists.secondlife.com]On Behalf Of Tateru Nino
>>>> Sent: Tue, March 20, 2007 8:52 AM
>>>> To: sldev at lists.secondlife.com
>>>> Subject: [sldev] Texture caching
>>>>
>>>>
>>>> Umm. Someone correct me if I'm wrong.... Actually, _please_
>>>> someone tell
>>>> me that I'm wrong.
>>>>
>>>>                 case LLAgent::TELEPORT_START_ARRIVAL:
>>>>                         // Transition to ARRIVING.  Viewer
>>>> has received
>>>> avatar update, etc., from destination simulator
>>>>                         gTeleportArrivalTimer.reset();
>>>>
>>>> gViewerWindow->setProgressCancelButtonVisible(FALSE, "Cancel");
>>>>                         gViewerWindow->setProgressPercent(75.f);
>>>>                         gAgent.setTeleportState(
>>>> LLAgent::TELEPORT_ARRIVING );
>>>>                         gAgent.setTeleportMessage("Arriving...");
>>>> This >>>>        gImageList.mForceResetTextureStats = TRUE;
>>>>                         break;
>>>>
>>>> Now, I've glanced through. Doesn't this result in setting the
>>>> max memory
>>>> cache size for textures back to zero, essentially discarding all
>>>> in-memory textures?
>>>>
>>>> Wouldn't it be better to let the least-recently-seen
>>>> algorithm take care
>>>> of invalidation?
>>>>
>>>> So, am I wrong? Is this _not_ causing the viewer to discard
>>>> all textures
>>>> cached in-memory during a teleport? (Evidence suggests strongly that
>>>> in-memory textures are being discarded on a teleport, and I'm pretty
>>>> sure that it's not necessary given the algorithms to manage
>>>> that storage
>>>> - I let a location load for minutes, teleport away and teleport back,
>>>> and spend almost as many minutes watching those textures from
>>>> 30 seconds
>>>> ago load and decode from the disk cache)
>>>>
>>>>
>>>> -- 
>>>> Tateru Nino
>>>> http://dwellonit.blogspot.com/
>>>>
>>>> _______________________________________________
>>>> Click here to unsubscribe or manage your list subscription:
>>>> /index.html
>>>>
>>>>     
>>>
>>>
>>> _______________________________________________
>>> Click here to unsubscribe or manage your list subscription:
>>> /index.html
>>>
>>>   
>>
>
> ------------------------------------------------------------------------
>
> diff -ur linden-orig/indra/newview/lltexturecache.cpp linden/indra/newview/lltexturecache.cpp
> --- linden-orig/indra/newview/lltexturecache.cpp	2007-03-17 00:24:08.000000000 -0400
> +++ linden/indra/newview/lltexturecache.cpp	2007-03-19 19:59:19.000000000 -0400
> @@ -775,8 +775,8 @@
>  std::string LLTextureCache::getTextureFileName(const LLUUID& id)
>  {
>  	std::string idstr = id.asString();
> -	std::string delem = gDirUtilp->getDirDelimiter();
> -	std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
> +	std::string delim = gDirUtilp->getDirDelimiter();
> +	std::string filename = mTexturesDirName + delim + idstr[0] + delim + idstr;
>  	return filename;
>  }
>  
> @@ -828,11 +828,11 @@
>  
>  void LLTextureCache::setDirNames(ELLPath location)
>  {
> -	std::string delem = gDirUtilp->getDirDelimiter();
> +	std::string delim = gDirUtilp->getDirDelimiter();
>  	mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
>  	mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
>  	mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
> -	mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
> +	mTexturesDirEntriesFileName = mTexturesDirName + delim + entries_filename;
>  }
>  
>  void LLTextureCache::purgeCache(ELLPath location)
> @@ -964,26 +964,28 @@
>  
>  void LLTextureCache::purgeAllTextures(bool purge_directories)
>  {
> -	if (!mReadOnly)
> +	if (mReadOnly)
>  	{
> -		const char* subdirs = "0123456789abcdef";
> -		std::string delem = gDirUtilp->getDirDelimiter();
> -		std::string mask = delem + "*";
> -		for (S32 i=0; i<16; i++)
> -		{
> -			std::string dirname = mTexturesDirName + delem + subdirs[i];
> -			gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
> -			if (purge_directories)
> -			{
> -				LLFile::rmdir(dirname.c_str());
> -			}
> -		}
> -		ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
> +		return;
> +	}
> +
> +	const char* subdirs = "0123456789abcdef";
> +	std::string delim = gDirUtilp->getDirDelimiter();
> +	std::string mask = delim + "*";
> +	for (S32 i=0; i<16; i++)
> +	{
> +		std::string dirname = mTexturesDirName + delim + subdirs[i];
> +		gDirUtilp->deleteFilesInDir(dirname.c_str(),mask);
>  		if (purge_directories)
>  		{
> -			LLFile::rmdir(mTexturesDirName.c_str());
> +			LLFile::rmdir(dirname.c_str());
>  		}
>  	}
> +	ll_apr_file_remove(mTexturesDirEntriesFileName, NULL);
> +	if (purge_directories)
> +	{
> +		LLFile::rmdir(mTexturesDirName.c_str());
> +	}
>  	mTexturesSizeMap.clear();
>  }
>  
> @@ -998,7 +1000,9 @@
>  	
>  	S32 filesize = ll_apr_file_size(mTexturesDirEntriesFileName, NULL);
>  	S32 num_entries = filesize / sizeof(Entry);
> -	if (num_entries * (S32)sizeof(Entry) != filesize)
> +
> +	//make sure the file is a multiple of the Entry size
> +	if( filesize % (S32)sizeof(Entry) != 0)
>  	{
>  		llwarns << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << llendl;
>  		purgeAllTextures(false);
> @@ -1259,9 +1263,7 @@
>  	}
>  }
>  
> -LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
> -													  U8* data, S32 datasize, S32 imagesize,
> -													  WriteResponder* responder)
> +LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority, U8* data, S32 datasize, S32 imagesize, WriteResponder* responder)
>  {
>  	if (mReadOnly)
>  	{
>   
> ------------------------------------------------------------------------
>
> _______________________________________________
> Click here to unsubscribe or manage your list subscription:
> /index.html
>   
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.secondlife.com/pipermail/sldev/attachments/20070320/01429539/attachment.htm


More information about the SLDev mailing list