Horde3D

Next-Generation Graphics Engine
It is currently 27.04.2024, 13:00

All times are UTC + 1 hour




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: Patch: Texture streaming
PostPosted: 10.03.2009, 22:00 
Offline

Joined: 23.06.2008, 10:23
Posts: 21
Location: Sweden
The past week I've been implementing texture streaming for Horde3D, and now I'm ready to release it back to the community.

Please note that texture streaming is only supported for dds files with pre-generated mipmaps. My implementation begins with loading and displaying the lowest mipmap level and then gradually display higher mipmap levels as they become available.

Attached to the post is a patch against the sourceforge svn and a sample. The sample is based on the chicago sample, but modified to read textures from the disk in a separate thread and stream them to Horde3D.


Attachments:
texture_streaming.patch [24.08 KiB]
Downloaded 828 times
texture_streaming_sample.zip [289.09 KiB]
Downloaded 720 times
Top
 Profile  
Reply with quote  
PostPosted: 11.03.2009, 14:44 
Offline

Joined: 22.11.2007, 17:05
Posts: 707
Location: Boston, MA
Very nice feature - I will give it a spin when I get the chance!

_________________
Tristam MacDonald - [swiftcoding]


Top
 Profile  
Reply with quote  
PostPosted: 12.03.2009, 20:55 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
Very cool! I had a look over your implementation.
I like that you try to keep the implementation inside the Horde core rather minimal and that your code looks clean and thought-out. Just one thing, I would prefer the term "streamable" to "streaming". When I read isResourceStreaming, I thought the function would return if the resource is currently doing data streaming which is not intended; isResourceStreamable would make this clear.

As I understand from what I have seen, your streaming helps to reduce the time the loading screen is visible since it can load data in the background while the game is already running. In theory it could also be used to support large worlds, but in practice not yet, because it is only texture streaming and not streamig of models and materials. Furthermore, it does not free any memory, so you would quickly run out of memory with huger worlds. Another drawback is that the default dummy texture is used before the texture gets streamed in which is very noticable for the user.

I would find it more useful if the streaming would try to reduce the memory consumption instead of reducing the loading time. I would suggest that textures are always loaded before the game starts, but only a low resolution mipmap (assuming the texture is streamable). If the player gets closer to an object, the full resolution mipmap gets streamed in. There is a fixed texture pool size. If the current texture memory consumption is over the budget, the least recently used high-res texture is removed and replaced by the low-res mipmap again. The player would see some popping but it is not that bad since the low-res mip still represents the color of an object. A similar approach is described here, although it contains much PS3-specific stuff:

http://www.insomniacgames.com/tech/articles/1107/files/texture_streaming.pdf

IMHO it would be very cool to have this since it would make it possible to use really high res textures for a scene, even on hardware with limited memory (e.g. consoles). Please don't get me wrong, this is not meant as criticism of your work, just a suggestion to make your great efforts more widely usable :)


Top
 Profile  
Reply with quote  
PostPosted: 12.03.2009, 23:49 
Offline

Joined: 23.06.2008, 10:23
Posts: 21
Location: Sweden
Thank you for your feedback marciano, your are correct that my implementation is used to reduce loading times. I actually read that paper and thought about implementing streaming to reduce memory usage for textures. The problem with it though is at which distances would you switch between different mip levels (and how long before would you start streaming from file)?

What are your thoughts on the interface (other than streaming vs. streamable, which i agree with)?
If I were to re-implement texture streaming to reduce memory usage but keep the current interface do you think it would have any chance to get integrated into official Horde3D?


Top
 Profile  
Reply with quote  
PostPosted: 13.03.2009, 14:45 
Offline

Joined: 22.11.2007, 17:05
Posts: 707
Location: Boston, MA
marciano wrote:
I would find it more useful if the streaming would try to reduce the memory consumption instead of reducing the loading time.
In some ways, I would find that less desirable. If I need to use huge textures, then I can implement texture LOD in some form (clipmaps for terrain, for instance), but loading times are still a big problem.
Quote:
Another drawback is that the default dummy texture is used before the texture gets streamed in which is very noticable for the user.
This definitely needs to be corrected, such that the smallest mipmap level is loaded immediately - dummy texture is not good ;)

_________________
Tristam MacDonald - [swiftcoding]


Top
 Profile  
Reply with quote  
PostPosted: 18.03.2009, 02:05 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
Fidora, sorry for the late reply.

Fidora wrote:
What are your thoughts on the interface (other than streaming vs. streamable, which i agree with)?
If I were to re-implement texture streaming to reduce memory usage but keep the current interface do you think it would have any chance to get integrated into official Horde3D?

Basically your interface is quite good. But to be included in Horde, it would really have to support texture streaming for coping with limited memory.

Basically I see two types of streaming which are important: streaming of world sectors and streaming of details. World streaming is something very specific to a game world (may require non-graphics data, e.g. sounds, entities, ...) so it should be handled by the application. The only thing Horde could contribute there is a thread-safe loadResource function, so that the graphics data deserialization could be done in a separate thread. The second thing, the detail streaming, is basically the texture streaming that we have discussed so far. A simple solution for texture streaming could be implemented directly in Horde. Here a few thoughts:

I would suggest that streamable texture resources have two OpenGL textures: one low resolution version which is always loaded and kept in memory and a high resolution one that is loaded and freed as required, depending on the distance and free space in the texture pool. For the beginning, a simple distance function (e.g. log(dist) or something like that) can be used to determine which highres mip needs to be loaded. The function can always be tweaked later. Horde would add that texture to a list of requested streamed textures. The user polls the textures to be streamed, gets the file offset and size, loads it in a background thread and forwards the data to Horde. The interface for this can be very similar to what you have now.

There is still one drawback with the described solution: although a lowres mip is used for a streamable texture at loading time, the whole dds needs to be read from disk. We could implement a more complicated mechanism here (e.g. queryUnloadedResource gives back a file offset and size) but I don't know if this will really be faster. I think reading a dds file from disk without uploading it to the GPU should be very fast. A more complicated loading mechanism would require several accesses to the file. I don't know exactly how expensive seeking a file is compared to reading in a few megabytes.


Top
 Profile  
Reply with quote  
PostPosted: 18.03.2009, 02:37 
Offline

Joined: 22.11.2007, 17:05
Posts: 707
Location: Boston, MA
marciano wrote:
I would suggest that streamable texture resources have two OpenGL textures: one low resolution version which is always loaded and kept in memory and a high resolution one that is loaded and freed as required, depending on the distance and free space in the texture pool.
Wouldn't it be cleaner to do this just by manipulating mipmap levels, rather than having two separate textures? In particular, you always need the smaller mipmap levels to display the largest, so you must have that low resolution version already loaded as part of the mipmap chain. You can then set GL_TEXTURE_MIN_LOD and GL_TEXTURE_MAX_LOD as needed to control display.

Quote:
For the beginning, a simple distance function (e.g. log(dist) or something like that) can be used to determine which highres mip needs to be loaded.
This is roughly duplicating the internal opengl LOD calculations for mipmaps.

Quote:
There is still one drawback with the described solution: although a lowres mip is used for a streamable texture at loading time, the whole dds needs to be read from disk. We could implement a more complicated mechanism here (e.g. queryUnloadedResource gives back a file offset and size) but I don't know if this will really be faster. I think reading a dds file from disk without uploading it to the GPU should be very fast. A more complicated loading mechanism would require several accesses to the file. I don't know exactly how expensive seeking a file is compared to reading in a few megabytes.
I recall (but haven't benchmarked), that uploading to the GPU is much less expensive than loading from disk. As far as seeking vs reading, the seeking is more expensive for single block reads, but on the order of several megabytes it will become far less important - I would expect transfer to be the bottleneck for consumer hard drives.

_________________
Tristam MacDonald - [swiftcoding]


Top
 Profile  
Reply with quote  
PostPosted: 18.03.2009, 09:28 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
swiftcoder wrote:
Wouldn't it be cleaner to do this just by manipulating mipmap levels, rather than having two separate textures? In particular, you always need the smaller mipmap levels to display the largest, so you must have that low resolution version already loaded as part of the mipmap chain. You can then set GL_TEXTURE_MIN_LOD and GL_TEXTURE_MAX_LOD as needed to control display.

I was also thinking about that and it would be cleaner. But is it possible to free the memory of specific mips?

swiftcoder wrote:
I recall (but haven't benchmarked), that uploading to the GPU is much less expensive than loading from disk. As far as seeking vs reading, the seeking is more expensive for single block reads, but on the order of several megabytes it will become far less important - I would expect transfer to be the bottleneck for consumer hard drives.

Maybe you are right, I have never done any disk benchmarking so far. It really needs to be tried out how much time it costs.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 35 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group