-
Notifications
You must be signed in to change notification settings - Fork 1
Atlas Manager
The Atlas Manager is a texture atlasing system that automatically packs textures into larger texture pages to reduce draw calls and improve rendering performance. It handles page allocation, texture packing, LRU eviction, and fragmentation management.
Texture atlasing is a technique where multiple smaller textures are combined into a single larger texture. This reduces the number of draw calls because the renderer can draw many sprites from the same texture in a single batch.
| Without Atlasing | With Atlasing |
|---|---|
| One draw call per texture | One draw call per atlas page |
| 100 textures = 100 draw calls | 100 textures = 1 draw call |
| Texture switches are expensive | Texture switches are minimized |
| Poor batching efficiency | Excellent batching efficiency |
The Atlas Manager handles all of this automatically. You don't need to think about it. Just pack your textures and the system handles the rest.
The atlas is divided into pages. Each page is a fixed-size render texture (default: 2048x2048 pixels). Textures are packed into these pages until they are full, then the next page is used.
Page 0 Page 1 Page 2
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ [Tex A] [Tex B] │ │ [Tex G] [Tex H] │ │ [Tex M] [Tex N] │
│ [Tex C] │ │ [Tex I] │ │ [Tex O] [Tex P] │
│ [Tex D] [Tex E] │ │ [Tex J] [Tex K] │ │ │
│ [Tex F] │ │ [Tex L] │ │ │
└────────────────────┘ └────────────────────┘ └────────────────────┘
The Atlas Manager supports two packing algorithms through the IAtlasPacker interface.
The Guillotine algorithm maintains a list of free rectangles and selects the best fit for each texture.
| Feature | Description |
|---|---|
| Strategy | Best area fit (smallest free rectangle that fits) |
| Search Time | O(n) where n is the number of free rectangles |
| Fragmentation | Tends to create more fragmentation over time |
| Best For | Textures of varying sizes |
How it works:
- Maintains a list of free rectangles in the atlas
- When packing, finds the free rectangle with the smallest area that fits the texture
- Splits the chosen rectangle into remaining free space
- When freeing, merges adjacent free rectangles to reduce fragmentation
- Defragmentation repacks all textures to optimize space
The Skyline algorithm maintains a skyline of the topmost occupied pixels and places textures in the lowest available position.
| Feature | Description |
|---|---|
| Strategy | Lowest Y position that fits the texture width |
| Search Time | O(n²) where n is the number of skyline nodes |
| Fragmentation | Less fragmentation than Guillotine |
| Best For | Textures of similar sizes |
How it works:
- Maintains a skyline (topmost occupied Y position for each X coordinate)
- When packing, finds the lowest Y position that can accommodate the texture width
- Places the texture at that position and updates the skyline
- When freeing, inserts free space back into the skyline
- Defragmentation repacks all textures in order of position
The AtlasManager is the main class that manages the entire atlasing system.
var atlas = AtlasManager.Instance;// Pack a texture into the atlas
if (atlas.TryPack(sfTexture, srcRect, out var packedRect, out var pageId))
{
// Texture was packed at packedRect on page pageId
var pageTexture = atlas.GetPageTexture(pageId);
// Draw using the atlas texture
batcher.DrawBypassAtlas(pageTexture, dstRect, packedRect, Color.White);
}// Get the texture for a specific page
SFTexture pageTexture = atlas.GetPageTexture(pageId);// Get atlas metrics
var metrics = atlas.GetMetrics();
Console.WriteLine($"Pages: {metrics.UsedPages}/{metrics.TotalPages}");
Console.WriteLine($"Usage: {metrics.PercentageFull:F1}%");
Console.WriteLine($"Textures: {metrics.TextureCount}");
Console.WriteLine($"Evictions: {metrics.EvictionCount}");// Process pending defragmentation moves (call once per frame)
bool stillDefragging = atlas.ProcessPendingDefragMoves(maxMovesPerFrame: 10);// Clear all atlas data
atlas.Clear();When the atlas is full, the Atlas Manager evicts the least recently used textures to make room for new ones.
| Step | What Happens |
|---|---|
| 1 | Atlas is full |
| 2 | Least recently used texture is identified |
| 3 | Texture is removed from the atlas page |
| 4 | Space is freed for the new texture |
| 5 | New texture is packed into the freed space |
Evictions are tracked in the AtlasMetrics structure.
Over time, packing and freeing textures can leave fragmented free space that cannot be used for larger textures. Defragmentation rearranges packed textures to consolidate free space into larger contiguous blocks.
| Condition | Action |
|---|---|
| No free space found in any page | Find the most fragmented page |
| Fragmentation > threshold (default: 30%) | Defragment that page |
| Space is freed | Continue |
- Identify the most fragmented page
- Get all textures on that page
- Repack them into a clean atlas page
- Queue move operations for processing over multiple frames
- Update packed positions in the map
Defragmentation is spread across multiple frames to avoid frame rate hitches.
// Process up to 10 moves per frame
atlas.ProcessPendingDefragMoves(10);Atlas settings are configured through GameSettings.
var settings = GameSettings.Instance
.SetAtlasPageSize(2048) // Page size in pixels
.SetAtlasPageCount(4) // Number of pages
.SetAtlasDefragThreshold(0.3f) // 30% fragmentation triggers defrag
.SetAtlasDefragMovesPerFrame(10) // Moves per frame
.SetAtlasPacker(typeof(SkylinePacker)) // Packing algorithm
.Build();| Setting | Description | Default |
|---|---|---|
AtlasPageSize |
Size of each atlas page in pixels | 2048 |
AtlasPageCount |
Number of atlas pages | 4 |
AtlasDefragThreshold |
Fragmentation percentage that triggers defrag | 30% |
AtlasDefragMovesPerFrame |
Number of texture moves per frame during defrag | 10 |
AtlasPacker |
Packing algorithm to use | SkylinePacker |
| Scenario | Without Atlas | With Atlas |
|---|---|---|
| 50 textures | 50 draw calls | 1 draw call |
| 500 textures | 500 draw calls | 1-2 draw calls |
| 5000 textures | 5000 draw calls | 3-5 draw calls |
| Component | Memory Usage |
|---|---|
| Atlas page (2048x2048) | 16 MB |
| Atlas page (4096x4096) | 64 MB |
| Texture data (in packer) | Minimal |
| Metric | Value |
|---|---|
| Moves per frame | Configurable (default: 10) |
| Time per move | ~0.1-0.5 ms |
| Total defrag time | Spread across frames |
public class MyGame : Game
{
private AtlasManager _atlas;
private SpriteBatcher _batcher;
protected override void OnEnter()
{
_atlas = AtlasManager.Instance;
_batcher = new SpriteBatcher();
}
protected override void OnUpdate(FrameTime frameTime)
{
// Process defragmentation moves
_atlas.ProcessPendingDefragMoves(10);
}
protected override void OnDraw(FrameTime frameTime)
{
// Pack and draw textures
var texture = AssetManager.Instance.Load<Texture>("player.png");
if (_atlas.TryPack(texture, texture.Bounds, out var packedRect, out var pageId))
{
var pageTexture = _atlas.GetPageTexture(pageId);
_batcher.Begin(SortMode.BackToFront);
_batcher.DrawBypassAtlas(pageTexture, new Rect2(100, 100, 64, 64), packedRect, Color.White);
_batcher.End();
}
}
}public void CheckAtlasHealth()
{
var metrics = AtlasManager.Instance.GetMetrics();
if (metrics.PercentageFull > 90f)
{
Console.WriteLine("Atlas is nearly full! Consider increasing page count.");
}
if (metrics.EvictionCount > 100)
{
Console.WriteLine("High eviction count. Atlas may be too small.");
}
}| Feature | Description |
|---|---|
| Texture Atlasing | Combines textures into larger pages |
| Automatic Packing | Textures are packed automatically |
| Multiple Algorithms | Guillotine and Skyline packing |
| LRU Eviction | Least recently used textures are evicted |
| Defragmentation | Fragmented space is consolidated |
| Page Management | Multiple pages are managed automatically |
| Metrics | Usage statistics are tracked |
- CollisionHelper
- MathHelper
- FileHelper
- HashHelper
- JsonHelper
- MapHelper
- TextHelper
- SoundHelper
- AlignHelpers
- Instance Helper
- Enum Extensions
- String Extensions
- Int Extensions
- Float Extensions
- IEnumerable Extensions
- Random Extensions
- Sound Extensions
- Font Extensions