SVT benefits and pipelines

Hi,

Based on recommendations we have converted the game as much as possible to use Virtual streaming textures.

I converted all textures to be Virtual (barring those that cant, ie Render Targets, Volume Textures, Cubemaps etc)

I updated all materials/function to sample these Virtual Textures.

A couple of things I’ve noticed…

  • Landscapes couldn’t use SVT due to outputting RVT.
  • Parallax (POC) doesn’t work with SVT

And the consequences are

  • Landscapes aren’t using SVT
  • Height maps for the POC would need to be Non SVT meaning they would need to separated out of our currently packed Normal/Roughness/Height map textures (else that’s even more textures not benefiting from being SVT
  • Resulting in good mix of SVT and Non-SVT textures, with the textures needing converting one way or the other on import as there is no consistency (unless you can give rules to the importer?)

Then its just understanding how SVT works with regards to assets that have runtime modified UVs, like scrolling or frames from flick books etc. Will this break it or does it just not apply it in these instances?

Also is there a way to fully test the benefits of our new SVT setup, I’ve read the documentation in dev.epicgames.com which was very helpful, and i can see we can use the command lines to see stats/costs of it in action, its just having a good sense of before and after costs. ie is there a command line to disable the effects of the textures being SVT (as if its was Non SVT textures using the previous setups) to profile the two and compare? Maybe a before and after texture pool size to see if its handling the complete set of textures more efficiently, making better choices etc

Just to understand if this new pipeline is giving us the benefits we think it should versus the changes to our workflows, as the pipeline is a little different and all master materials will need overhauling - so if I need to revert I’d rather do it sooner rather than later. All about making better informed choices :slight_smile:

Thanks,

Leon.

Hi there,

I think it’s a good idea to start with an overview of what virtual textures are actually giving you, and what the benefits, limitations, and drawbacks are.

The main advantage of virtual textures is their generally smaller memory footprint, and more granular streaming capabilities. With standard texture streaming, an entire mip of a texture is either streamed in or not. Furthermore, streaming is entirely handled by the CPU using only CPU available data (generally built when texture streaming is built). This means that you may be loading / keeping large amounts of texture data in memory that you don’t actually need.

Virtual textures use an entirely different streaming system, which is much more granular, and actually knows what mip, and even sections (tiles), of a texture the GPU actually needs. Virtual textures are streamed in tiles, which are usually smaller than the actual mip 0 texture. This means that only the tiles in the texture that are actually visible will be streamed in (default tile size is 128x128).

This all sounds great, however, it’s good to keep in mind that there are drawbacks to using virtual textures as well. Virtual textures primarily optimize memory usage, and might provide some performance wins if your game is constantly streaming in and out textures (trashing texture memory).

However, most of the time I would actually expect to see a general performance drop by switching everything to virtual textures. This is because there is extra overhead required for sampling and filtering a texture. Each texture sample needs to first sample the indirection page table, to check where in memory the actual texture tile is located before sampling from it. Extra instructions are also required to support texture filtering of virtual textures (anisotropy filtering support for virtual textures needs to be enabled as a separate option in project settings). Generally, texture filtering is not as robust on virtual textures. If you are using TAA or TSR (temporal anti-aliasing methods), you may not notice much quality difference. However, you may notice shimmering / aliasing artifacts if you are not using a temporal anti-aliasing method.

For landscapes, yes, you are right that these cannot use virtual textures when outputting to an RVT. This is likely due to the textures needing to be available immediately whenever an RVT renders. If the lower mips are not loaded in memory already, then the RVT tiles close to the camera will be rendered using the available high mips, resulting in blurry RVT output. The RVT tile then thinks that it is up to date, and the tile will stay blurry, even if the VT feedback system tells the CPU the next frame to load the required tiles for the source texture.

For parallax occlusion mapping (POM), I probably wouldn’t try to use virtual textures for the height map. POM is already quite expensive due to doing many texture samples in a loop per pixel. If you were to introduce virtual texture sampling for the height map as well, you would essentially be doubling the texture samples required per pixel for your parallax occlusion step. Technically you could probably get this to work with some effort. You would have to re-write the custom node (needed to support loops in a material) part of the POM material function to support virtual texture samples. You can technically sample from a virtual texture in a custom node, as is done for regular texture samples in the engine POM material function. If you still want to, you can take a look at the HLSL output of a material using a virtual texture sample to figure out how it does virtual texture samples in code.

In terms of import pipelines, you can enable auto virtual texture import in the project settings and specify a texture size above which all textures will get imported as virtual. Since VTs are mainly a memory optimization, it makes sense to keep small textures non-virtual to avoid the extra sampling overhead.

[Image Removed]

Flipbooks, and scrolling textures should technically still work, but I would check these in your project to see if you notice any blurry frames. Especially the first time the loop plays. Generally I probably wouldn’t use virtual textures for these anyway, as the use case seems like it would mostly be effects, and these tend to use lower resolution textures, which work better with the standard streaming system (lower performance overhead, already take up little memory). To get an idea of how flip books / scrolling textures might have issues, it might be useful to understand a bit about how the VT feedback system works. The feedback system randomly samples 1 pixel in every VT feedback tile size (default 16x16) pixels. When a texture sample happens in a shader which is writing to one of these pixels, it stores some extra data about the required mip level needed by that texture sample. Since this is a random sample, it’s possible it could take more than 1 frame to catch a required texture streaming update. So for panning / flip book textures, and even just general effect texture (for effects that appear and disappear suddenly), this can produce bad results, since the virtual texture feedback system might not be quick enough to keep up with sudden changes in texture sample locations / mips.

For testing / profiling, there unfortunately isn’t a nice way to just toggle VTs on / off at runtime and have them fall back to normal texture samples. The best way to test the performance / memory tradeoff is probably to package out a Test build of two versions of the same test level. One using virtual textures, and one not. Run each and compare the difference in performance (I recommend having a setup where the camera positions / orientation are fixed for this, or using a benchmark fly through camera so the tests are consistent).

My personal recommendation for using virtual textures, is that if you have a lot of unique, high resolution textures in your game, and / or you are struggling with texture memory budgets, then you should enable virtual textures on all your large textures (so long as you can afford the performance hit). If you are building for a mobile platform (or even if you’re not, but your game is more stylized and less reliant on lots of high res textures), then I would probably avoid virtual textures, and try to optimize texture memory using texture atlases and trim sheets. Specific texture usages may also warrant virtual textures, even if you decide to mostly use regular textures in your project. Some good examples are Hierarchical LOD (HLOD) textures. If you are using the merge setting with texture baking for your HLODs, then it will generate a unique texture for every HLOD in your level. This might add up to a significant amount of texture memory usage, even if your underlying meshes are efficiently re-using textures. Another is virtual texture light maps. This is an extra option you can enable in the project settings for baked lighting. Baked lighting often takes up a significant amount of texture memory, and a level texture memory footprint can be greatly reduced by using virtual textures here for the extra granularity. Though again, this comes at a performance cost.

Let me know if you have any follow up questions

Regards,

Lance Chaney

Hi Lance,

Thank you so much for this rapid and extensive reply!! This is amazing and has really helped me to understand how it works and why it might fall over in certain situations.

I think my only follow up questions are…

I understand Virtual textures aren’t suitable for all platforms. Our projects tend to be on a wide range of platforms, ie high and low end PC, all the common consoles, steam, and potentially it could be Luna and Switch 2 (we likely wont support the original older Switch) so im trying to understand how single setups can work in this case. Is there a way for feature switches in master materials to cater for SVT and non SVT setups without having 2 sets of textures (ie can the cooking process for the various platforms handle this and remove/disable the virtual functionality for those platforms that cant make use of it)

Then an extension to this question, i understand from your reply above and from other sources too that it works better for larger textures for obvious reasons, so to set the importer to mark those textures smaller than, for example, 1k to be non-SVT. Is it possible to set up a master to work with this variety of SVT and non-SVT textures (some material function magic), as we could have a situation where the same master could be used for large or small assets, so might in one situation have a 2k SVT, and in another the auto import made a 1k non SVT texture - I assume we would we simply need two master material setups?

Thanks again for your time with this very detailed reply - its been extremely helpful.

All the best,

Leon.

First off, a correction to what I said about each virtual texture sample costing 2 texture samples each under the hood. There is actually an optimization for this, if all your texture samples use the same UVs. If your material has 3 VT texture samples nodes that all use the same UVs, then you will only need 1 additional indirection page table sample for all of them. So in total it would only be 4 underlying texture samples, not 6 (1 additional texture sample of overhead). See here: https://dev.epicgames.com/community/learning/tutorials/58vb/unreal-engine-guide-to-virtual-textures-for-noobs#efficiency

Regarding a single material setup which toggles between VT and non-VT samplers, unfortunately you will still need two copies of the texture if you want to support both a VT and non-VT version. You can use Feature Level / Quality / Shader Platform Info switches to support different texture samplers on different platforms or quality levels. You will still have to specify the VT and non-VT texture parameters separately for each material instance though. Note that every non-VT texture you add to a material (even if you don’t use it in the compiled shader) will force a very small mip of that texture to always be loaded in memory whenever the material is loaded. The overhead for referencing a 4k texture was about 8 KB per texture when I tested this, so it’s probably not worth worrying too much about this though.

Example Setup:

[Image Removed]Note: Although the VT / non-VT texture sampler nodes look identical, when you set them to sample a virtual texture in the graph, you will only be able to assign virtual textures to these parameters in the instance, and vice versa.[Image Removed]

You also can’t really avoid packaging both sets of texture assets if they’re referenced in the material. A workaround for this is to carefully manage your texture groups and device profiles so that you can set the maximum texture size to some small value for cooking on platforms that don’t need specific sets of textures. In order to ensure that device profiles apply at cook time (to strip out unused data), you need to make sure you set your texture LOD group settings on a platform base profile (e.g. Android, Windows, iOS) and not on an inherited profile, like Android_Mid.

Example Texture Settings:

[Image Removed]Example Device Profile Settings:

[Image Removed]In your DefaultEngine.ini you can rename the Project Group # texture groups as follows for easier management:

[EnumRemap]

TEXTUREGROUP_Project01.DisplayName=CustomVTGroup

Regarding your last question about requiring two master materials to support a VT and non-VT version of the material for different objects. Fortunately, you do not need to do this. You can simply add a static switch parameter to the material to switch between VT and non-VT texture samplers. Then in your material instance you can toggle the correct VT mode before assigning the textures.

[Image Removed][Image Removed][Image Removed]

Again, let me know if you have any more follow up questions.

Regards,

Lance Chaney

Hi Lance,

This is brilliant, thank you so much! This makes it very clear what we need to work through and decide if its the way to go for our project.

Thanks again for your very descriptive help!!

All the best,

Leon.

You’re very welcome

Hi Lance, sorry one more question, is there a list of which platforms dont support SVT please? Thanks

Taking a brief look, it looks like every platform supports virtual textures. It’s just going to be a question of the performance hit on those platforms. Here is the rendering feature support page for mobile chips (including switch). All consoles (even previous gen) should also support virtual textures.

Regards,

Lance Chaney

Thanks so much :slight_smile: