Quick answer: Enabling QualitySettings.streamingMipmapsActive globally does nothing unless each texture also has Streaming Mipmaps checked in its import settings. Use an AssetPostprocessor to enable it in bulk for textures 256px and larger, and leave UI textures non-streaming.
Here is how to fix Unity’s Texture Streaming failing to reduce memory use. You enabled Streaming Mipmaps in Quality Settings, confirmed the checkbox is on, ran the game — and the Memory Profiler shows the same 2 GB of textures resident that you had before. The reason is that enabling streaming globally is only half the setup. Each texture must individually be marked for streaming in its TextureImporter settings. On a project with 5,000 textures imported before you enabled streaming, none of them are set up.
The Symptom
- QualitySettings.streamingMipmapsActive is true but memory has not dropped
- Texture memory in Profiler stays at baseline with or without streaming enabled
- Individual textures show “Streaming” as off in their Inspector
- Texture.desiredTextureMemory equals currentTextureMemory (no variance)
- Runtime logs show streaming system active but idle (no promotions/demotions)
What Causes This
Streaming is opt-in per texture. The TextureImporter has a Streaming Mipmaps checkbox in the Advanced section. Textures imported before you enabled streaming at the project level have this off. Unity does not auto-convert existing textures when you flip the global flag.
Not all textures should stream. UI textures are always on screen — streaming just adds latency before they become sharp. VFX atlases need all mips immediately. Icons and loading screens must be full-res. Streaming these is wrong.
Small textures do not benefit. A 128x128 texture is 87 KB uncompressed. Streaming saves maybe 60 KB if only mip 3 is needed — a rounding error in a scene using gigabytes of texture memory. The overhead of tracking streaming state for thousands of small textures may cost more than it saves.
Renderer reference required. Streaming only activates for textures assigned to materials on active Renderers in rendered cameras. A texture loaded and assigned in code to an off-screen or disabled renderer is not streamed — it loads full-res.
Quality level not active. If you set streamingMipmapsActive only on the Ultra quality level but the player runs on Medium, streaming is off. Apply to all levels you ship, or set via script at startup.
The Fix
Step 1: Enable streaming per-texture in bulk. Create an editor script to iterate existing textures and enable streaming on those above a size threshold:
using UnityEditor;
using UnityEngine;
public static class EnableStreaming
{
[MenuItem("Tools/Enable Streaming Mipmaps (>=256)")]
public static void Enable()
{
string[] guids = AssetDatabase.FindAssets("t:Texture2D");
int count = 0;
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var imp = AssetImporter.GetAtPath(path) as TextureImporter;
if (imp == null) continue;
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
if (tex == null || tex.width < 256 || tex.height < 256) continue;
if (imp.textureType == TextureImporterType.Sprite) continue; // skip UI
if (imp.streamingMipmaps) continue; // already on
imp.streamingMipmaps = true;
imp.SaveAndReimport();
count++;
}
Debug.Log($"Enabled streaming on {count} textures");
}
}
Run this once to convert the project. Reimport takes time on large projects — tens of minutes for 10,000 textures — because each texture’s mip chain must be rebuilt.
Step 2: Add an AssetPostprocessor for future imports. So new textures default correctly:
using UnityEditor;
using UnityEngine;
public class TextureStreamingDefault : AssetPostprocessor
{
void OnPreprocessTexture()
{
TextureImporter imp = (TextureImporter)assetImporter;
if (imp.textureType == TextureImporterType.Sprite) return;
if (assetPath.Contains("/UI/") || assetPath.Contains("/Icons/")) return;
imp.streamingMipmaps = true;
imp.streamingMipmapsPriority = 0;
}
}
This runs on every texture imported or reimported. Path-based exclusions keep UI and icon folders opt-out.
Step 3: Activate streaming at runtime. Ensure the quality settings are right:
using UnityEngine;
public class StreamingBootstrap : MonoBehaviour
{
void Awake()
{
QualitySettings.streamingMipmapsActive = true;
QualitySettings.streamingMipmapsMemoryBudget = 1024;
QualitySettings.streamingMipmapsRenderersPerFrame = 512;
QualitySettings.streamingMipmapsMaxLevelReduction = 2;
QualitySettings.streamingMipmapsAddAllCameras = true;
}
}
streamingMipmapsAddAllCameras = true is the easiest way to get every camera participating. Without it, only cameras tagged MainCamera contribute to streaming calculations, and non-main cameras (minimaps, cutscenes) fail to load their visible textures.
Step 4: Assign priorities to important textures. Use priority to win budget contention:
// At import time via editor script:
imp.streamingMipmapsPriority = 2; // hero character textures
imp.streamingMipmapsPriority = 1; // key props
imp.streamingMipmapsPriority = 0; // everything else (default)
At runtime, priorities can also be adjusted via Texture.streamingMipmapsPriority.
Step 5: Verify with Memory Profiler. Window > Analysis > Memory Profiler. Take a snapshot. Find a large texture and inspect it. The Memory Profiler shows “current” vs “max” mip levels. If current is higher than 0 (lower resolution), streaming is active. If every texture shows current = 0, the system is not streaming — either the budget is huge or streaming is off.
When to Disable Streaming
Explicit opt-outs for:
- UI textures (always full res, small, always visible)
- VFX particle atlases (all frames must be ready instantly)
- Loading screens and splash art (must display at full res immediately)
- Lightmap textures (loaded once, stay forever)
- Small gameplay icons under 256px
Use naming conventions or folder conventions so the AssetPostprocessor can exclude them.
Measuring the Savings
Log texture memory before and after enabling streaming:
Debug.Log($"Texture memory: {Texture.currentTextureMemory / 1024 / 1024}MB");
Debug.Log($"Desired: {Texture.desiredTextureMemory / 1024 / 1024}MB");
Typical savings on a console-scale project: 30-50% texture memory reduction, zero quality loss on visible surfaces, with about 1-2% GPU overhead for the streaming system.
“Global streaming flag on, per-texture flags off — nothing streams. Fix the imports, not just the Quality Settings.”
Streaming With Addressables
Addressable textures stream normally as long as the import settings include Streaming Mipmaps. The Addressables system manages loading/unloading of the texture asset itself (all mips bundled), while streaming controls which mip levels are resident. Both systems cooperate — you get coarse (asset-level) and fine (mip-level) memory management together.
See Texture Streaming Blurry on Load for the other side of this feature.
Per-texture checkbox. Bulk convert with editor script. AssetPostprocessor for future. UI opts out.