3/25/22

Managing the Texture Streaming Pool | Tips & Tricks | Unreal Engine

Engagement 73k+ views, 90+ comments

Topics Include Texture streaming pool, mip generation, texture resolution, VRAM

Another Tips & Tricks video for Unreal Engine, but this time focusing on how to optimize scenes when messages occur for texture streaming. Sam Anderson helps Unreal Engine project developers adjust texture resolutions, utilize power-of-two textures, and curate texture sizes to best fit within the Texture Streaming Pool. Learn how different view modes can also assist in the process.

Credit Epic Games

Model Sam Anderson

3D Environment Sam Anderson

Script Matthew Doyle, Matt Otzalay, and Sam Anderson

Voiceover Sam Anderson

Editing Sam Anderson

Tools Unreal Engine, Adobe Premiere NVIDIA A6000, Atomos Ninja, Apollo Solo, RE20

Transcript

00:00 Intro

01:33 Streaming Stats

02:50 Texture Stats

04:12 Changing texture resolution size

04:47 Bulk Edit via Property Matrix

06:04 Recommended resolution sizes

06:58 Power of Two texture size

07:30 MIP map generation

08:48 Required Texture Resolution viewmode

11:03 Changing the streaming pool size

12:01 Summary

Introduction

00:00 Welcome to another Unreal Engine Tips and Tricks. In today's episode, we are going to take a look at how to deal with the texture streaming pool over budget warning that you can see here on the top left hand side of my viewport. If you are seeing some blurry textures in your scene, this may be a result from that warning. And this is because I am over budget on my texture streaming pool. The streaming pool is the maximum amount of video memory available to display streaming textures. The system basically ensures that you get the best visual quality of those textures while also managing the available texture memory on your video card for those displayed textures.

00:50 Now, the way it all works is in the backend is there are some calculations done by the Unreal Renderer based on the texel size and the world bounds to determine the best texel-to-pixel ratio for all of the display textures on the screen. And then Unreal has to determine whether they all fit inside the amount of memory that is available.

01:13 If they don't fit inside the allocated memory inside the streaming pool, Unreal will start to go down in the different MIP levels to find a smaller texture that will fit that can still be drawn on the screen with the best possible quality. And it will keep doing this until everything fits safely in that streaming pool.

Streaming Stats

01:33 Now we can get a little bit more information using a stat command by going up to this window, going down to Developer Tools, and selecting Output Log. Now, here in my console command line, I'm going to type in Stat Streaming. Now the first thing to take note of is the streaming pool line, which is set to 200 megabytes here.

01:58 Now this is the max amount of VRAM, or video memory that we can make use of. By default, Unreal Engine's High Scalability Settings have this value set at a thousand megabytes. But I've gone ahead and changed this value to a lower value so that we can get our warning message and see what to do. Now keep in mind, any changes that we make here are going to depend on your target video card's available RAM.

02:25 So in other words, we don't want to increase this value beyond what our video card can handle, but we're definitely going to need more than 200 megabytes. So below this we have our required pool here, which is 1,341. So that's going to be 671 percent over that 200 megabyte. So we are overflowing our budget by quite a lot.

Texture Stats

02:50 We're going to want this number to be below 100. Now before we go any further, let's first take a look at how our textures are being used inside the project. To do that, I'm going to go up to the window on the top left-hand side, go down to Statistics, and you're going to want to make sure that the Texture Stats is selected here.

03:07 Now you'll see we have a lot of different information here, so we can take a look at the Max Dimension and the Current Dimension of the textures inside our scene. We also have our fully loaded memory, how many times the textures are used, and the current memory, which is what we're going to take a look at today.

03:24 So if you click on this, it's going to enable you to toggle between ascending and descending orders. Now we can see that there are many textures here that could be optimized. So one option would be to reduce the number of textures we are using in the scene, or reduce the size of those textures. If I look at the dimensions, you'll see that I have a lot of 4K textures.

03:47 Now for this project, I've used a lot of Quixel Megascans. I have my export settings set to 4K. That's great for the foreground, but I probably don't need that 4K for every single texture in my project. Now, sampling higher resolution textures is more expensive on the GPU, so I'm going to go ahead and reduce some of these textures.

Changing texture resolution size

04:12 So here we're seeing the textures that take up the most memory. Now we can adjust each of these textures individually. I could do this by double clicking here where it says Normal, and double clicking on this texture. This is a normal map for my foliage, so I absolutely do not need this to be 4k. So here underneath Maximum Texture Size, I could lower this.

04:30 I'll go ahead and set it to 1024, hit enter, and Save. Now I can refresh my Statistics and you'll see that it no longer pops up. Now, this could be time consuming depending on how many textures you need to change.

Bulk Edit via Property Matrix

04:47 So rather than doing that one at a time, a quick trick is to select all of the textures in the Content Browser. So to do that, I'm going to go to the Content folder. I'll select the Filters button down below. I'll go up to Materials and Textures. Select Texture. I'll go down to other filters. Select In Use by Level. I'm going to click on the first texture. Scroll down on the right hand side. Hit shift on my keyboard. Select that last texture. Now I'm going to right click. Go up to Asset Actions. and select Bulk Edit Via Property Matrix. Now we'll be using this to change texture information. However, there are a lot of different settings that you can change in a bulk manner. Now, if I go up to the Maximum Texture Size, I could go in here and type 1024, and it's going to change all of the textures I had selected.

05:47 Now we may want to curate our texture resolutions a little bit. For instance, some we may want to be at a 4k texture, others at much lower. So I can hit the pin icon next to Maximum Texture Size, and you'll see that column pops up here.

Recommended resolution sizes

06:04 Now a good rule of thumb would be to keep albedo numbers at full res, normal maps at about half the resolution, and roughness maps at a quarter of the resolution. So in order to do that, I'm going to scroll down to where it says Normal here. In this last column, I'm going to type in 1024 and hit enter. Now I'm going to select that cell, hit control C on my keyboard. Go down to the next line, scroll down, and using shift on my keyboard, select all of those Normals, and then hit control V on my keyboard to paste that texture size into all of them.

06:41 Now I'm going to do the same thing for the Roughness. I'll set this to 512, copy and paste this number for all of the Roughness textures. Now I can go hit File, Save, to save all of them.

Power of Two texture size

06:58 Now you may have noticed that the numbers I am referring to for the texture sizes are power-of-twos. This is important for mip generation. So something like 512 by 512, as opposed to numbers like 2000 or 4000. If you do not do that, Unreal will not be able to generate mipmaps for that texture. These textures with no mips will affect what's loaded into VRAM, but are not streamed. So this can still cause crashes if you are trying to load too many of these textures at once.

MIP map generation

07:30 Now, mipmap generation happens during importing of the texture and creates a mipmap chain for the texture. So the mipmap chain consists of multiple levels of the sample image, each half the resolution of the level before, which means the graphic card can render faster when using the lower mips, and also reduces the texture aliasing or shimmering and it becomes visible when having detailed texture in certain distances. The mips that are created are resolution dependent, so the higher resolution textures will want higher mips. Now the engine will only go down the mip chain to find a resolution that fits all of the heuristics of Required Resolution Streaming Pool. Which is why you might be getting some blurriness in your project because sometimes the engine needs to use lower mips than desired in order to fit everything inside of the streaming pool.

08:26 Now there may be moments where you do not want to generate a mip map. We will cover that information another day. For now we've saved the new texture resolutions. Let's go ahead and double check everything that we have. I'll go ahead and close out of this window. Now I'm going to go back to my Output Log and type in stat streaming to turn off those stats.

Required Texture Resolution viewmode

08:48 Now I'm going to go up to my viewmode and select Optimization Viewmodes. Go down and select Required Texture Resolution. Now you'll see everything is a dark gray here. We will need to specify a texture for it to give us information about it. So I'll go ahead and select this table that I have here.

09:10 I'll go up to textures and since we changed the normal and the roughness, I'll go ahead and double check my roughness texture and make sure that the resolution we applied is indeed an appropriate resolution for this texture. So here when I click it, you can see we're getting a gradient color. So this is showing the ratio between the currently streamed texture resolution and the resolution wanted by the GPU.

09:38 So you'll see that here in the foreground, this is a good ratio for the resolution. And in the back, it's going into that green territory, saying that the resolution is higher than we need back there. Now for this texture, it might be something that we're willing to give up. Since it is in the foreground, however, if we take a look at another texture, say at this gold pendant here, if I take a look at the albedo, everything comes in green here.

10:06 So since this isn't an important part of the design, there's not a lot of detail and it doesn't take up a lot of pixels on the screen, I'm going to go ahead and lower that texture size. To do that, I'll go over to the details panel on the right hand side. I'll scroll down to the Materials, hit the magnifying glass next to the gold, and I'm going to pull up that albedo texture.

10:27 And you'll see that it's imported here at 2048. displayed at 2048 in the game. So I'm actually going to set this texture size to 128. You can save that, close out of it, and you'll see that the texture is still green. Now I could keep lowering this until it gets to white. But I wanted to showcase how you could really curate specific memory usage this way.

10:54 So you'll see that we've reduced the texture size for this material, but it won't be reducing the quality for my desired look for this scene. So now that we've made some changes, let's go back and look at the differences. I'll go back to my Output Log, I'm going to type in stat streaming.

Changing the streaming pool size

11:03 Now we see that required pool size here. It's now 898, so this is 449 percent over, and that's over that 200 megabyte that I had changed prior to this video. So the default number for this is 1000. So let's go ahead and change that streaming pool size back to 1000. To do that I'm going to go down to my output log. And I'm going to type in r. streaming. poolsize space and then the value that I'll be setting it to, which is 1000. I'll hit enter on my keyboard. Now our warning at the top left hand side has gone away. And if we look at the required pool, this is now below 100 at 90%.

Summary

12:01 So let's summarize working with the streaming pool today and the options we have available. The steps that I showed you today are pretty general. Depending on your use case in your industry, you may take different steps to get to a stream pool setup that works for you. But let's review the steps we talked about today. We can reduce the total number of visible textures in our scene. Also, we can reduce the resolution of those visible textures. So, by bringing both of these things down, we can help to eliminate the amount of memory needed by our texture streaming system. And then finally, we can increase the streaming pool size, which will allow us to have more texture memory in use. Now, we will want to make sure that those textures are powers of two and generating mipmaps.

12:50 And then finally, we can increase the texture streaming pool size. Which allows us to have more texture memory in use. Now this is going to be limited by the video card for your target system, so I'd advise you to double check your VRAM before moving forward. If you raise the number too high and try to fit more into VRAM than the video card can handle, it will result in a crash.

13:13 Now there is one more option available that you might want to check out on your own, and that's to use virtual textures. This system streams only the required parts of a texture from the disk, which can reduce the overall memory burden of a given texture. This Tips and Tricks video will not be covering those, but feel free to look that up in the Unreal documentation for additional information, or check out the video link located in the description of this video.

13:41 Alright, that's going to do it for this Tips and Tricks episode. I hope you enjoyed it and found it useful. We'll see you next time.

Previous

Unreal Engine for Architecture

Next

Unreal Engine Apple Silicon Support