Skip to content

Asset System

The Asset System in EntropyPortal ensures secure, efficient, and stutter-free loading of content.

The AssetLoaderService is the entry point for all content retrieval.

graph TD
    Req[Request AssetId] --> Cache{In Cache?}
    Cache -->|Yes| Return[Return Data]
    Cache -->|No| Fetch[Fetch URI]
    
    Fetch --> Decrypt[Decrypt AES-256]
    Decrypt --> Hash[Verify Hash]
    Hash --> Store[Store in Cache]
    Store --> Return
  • Encryption: Assets are encrypted at rest (AES-256-GCM). The service automatically fetches decryption keys from the AssetClient.
  • Verification: Content integrity is verified using SHA-256 hashes before being returned to the application.
  • LRU Strategy: An in-memory Least Recently Used cache keeps frequently accessed assets ready.
  • Deduplication: Simultaneous requests for the same asset are coalesced into a single network fetch.

These services bridge the gap between CPU data and GPU memory.

To prevent frame spikes when loading large levels, uploads are performed asynchronously.

graph TD
    Start[Request Upload] --> Work[Async Worker]
    
    subgraph "CPU Work"
        Work --> Swizzle[Swizzle / Pack]
        Swizzle --> Stage[Copy to Staging]
    end
    
    Stage --> Ready[Mark Ready]
    
    subgraph "Render Thread"
        Ready --> Check{Process Pending?}
        Check -->|Limit/Frame| Upload[Copy Staging -> GPU]
    end
  1. Preparation: CPU-intensive work (texture swizzling, vertex packing) is offloaded to worker threads via WorkContract.
  2. Staging: Data is copied to a staging buffer.
  3. Transfer: The copy from Staging -> Default heap is sliced across multiple frames if necessary (throttled).

Resources are tracked via AssetId (a 128-bit UUID).

  • Lookup: The renderer (and MaterialService) looks up resources by AssetId to verify they are loaded and ready.

Shaders follow a specialized pipeline to handle High-Level Shading Language (Slang), variants, and diverse backends.

graph TD
    Load[Load Source] --> Pool[Acquire Compiler]
    
    subgraph "Worker Thread Pool"
        Pool --> Compile["Compile (Slang)"]
        Compile --> Reflect[Reflect & Layout]
        Reflect --> Bytecode["Bytes (SPIR-V/DXIL/MSL)"]
    end
    
    Bytecode --> Callback[OnCompileComplete]
    
    subgraph "Render Thread"
        Callback --> PSO[Create Pipeline State]
        PSO --> Cache[Store in VariantSet]
    end

The ShaderCompilerService maintains a Thread Pool of Compiler Instances.

  • Isolation: Each worker thread gets its own slang::ISession to avoid lock contention.
  • Async: Compilation happens in the background. The engine continues rendering with “fallback” shaders (e.g., magenta) until the real shader is ready.

Once bytecode is ready, the ShaderVariantSet on the main thread:

  1. Creates the GpuShader object.
  2. Binds it to the required Render State (Blend, Depth, Rasterizer).
  3. Uploads it to the GPU.