]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Optimize parallax VRAM usage (#37180)
authorPieter-Jan Briers <pieterjan.briers+git@gmail.com>
Thu, 22 May 2025 01:22:08 +0000 (03:22 +0200)
committerGitHub <noreply@github.com>
Thu, 22 May 2025 01:22:08 +0000 (11:22 +1000)
* Disable parallax texture preloading

Many parallax layers are specific to a single map and will likely never be loaded for the duration of the game. Save VRAM by not loading them always.

Requires engine master

* Put generated parallax identifier in texture name

Makes it show up properly in debugging tools

* Don't load generated parallaxes multiple times

Many parallax prototypes re-use the same generated parallax configs. These generated parallaxes were being loaded multiple times at once, which was a massive waste of VRAM.

We now move these into a separate cache for deduplication. I had to write a lot of logic to handle loading cancellation and ref counting. Yay.

Also fixes some spaghetti with the previous parallax loading system: cancellation didn't work properly, give proper names to generated texture names, etc.

This saves like 100+ MB of VRAM.

19 files changed:
Content.Client/IoC/ClientContentIoC.cs
Content.Client/Parallax/Data/GeneratedParallaxTextureSource.cs
Content.Client/Parallax/Data/IParallaxTextureSource.cs
Content.Client/Parallax/Managers/GeneratedParallaxCache.cs [new file with mode: 0644]
Content.Client/Parallax/Managers/ParallaxManager.cs
Resources/Textures/Parallaxes/AspidParallaxBG.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/AspidParallaxNeb.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/Asteroids.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/KettleParallaxBG.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/KettleParallaxNeb.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/core_planet.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/debris_large.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/debris_small.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/gas_giant.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/land.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/layer1.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/noise.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/planet.png.yml [new file with mode: 0644]
Resources/Textures/Parallaxes/space_map2.png.yml [new file with mode: 0644]

index 370188e3c61de280009b53fae19264da2083e090..1ea7868e9a5721e93819f3ccad912e5a7aef482d 100644 (file)
@@ -34,6 +34,7 @@ namespace Content.Client.IoC
             var collection = IoCManager.Instance!;
 
             collection.Register<IParallaxManager, ParallaxManager>();
+            collection.Register<GeneratedParallaxCache>();
             collection.Register<IChatManager, ChatManager>();
             collection.Register<ISharedChatManager, ChatManager>();
             collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
index 2e69a5a5625d1f9c3b5f17f5b94db01f15782ad1..cb9164591884b3afdd50d2e89d35ca4eb460e858 100644 (file)
@@ -1,17 +1,9 @@
-using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 using JetBrains.Annotations;
-using Nett;
-using Content.Shared.CCVar;
-using Content.Client.IoC;
+using Content.Client.Parallax.Managers;
 using Robust.Client.Graphics;
 using Robust.Shared.Utility;
-using Robust.Shared.Configuration;
-using Robust.Shared.ContentPack;
-using Robust.Shared.Graphics;
-using SixLabors.ImageSharp;
-using SixLabors.ImageSharp.PixelFormats;
 
 namespace Content.Client.Parallax.Data;
 
@@ -29,116 +21,21 @@ public sealed partial class GeneratedParallaxTextureSource : IParallaxTextureSou
     /// <summary>
     /// ID for debugging, caching, and so forth.
     /// The empty string here is reserved for the original parallax.
-    /// It is advisible to provide a roughly unique ID for any unique config contents.
+    /// It is required to provide a unique ID for any unique config contents.
     /// </summary>
     [DataField("id")]
     public string Identifier { get; private set; } = "other";
 
-    /// <summary>
-    /// Cached path.
-    /// In user directory.
-    /// </summary>
-    private ResPath ParallaxCachedImagePath => new($"/parallax_{Identifier}cache.png");
-
-    /// <summary>
-    /// Old parallax config path (for checking for parallax updates).
-    /// In user directory.
-    /// </summary>
-    private ResPath PreviousParallaxConfigPath => new($"/parallax_{Identifier}config_old");
-
     async Task<Texture> IParallaxTextureSource.GenerateTexture(CancellationToken cancel)
     {
-        var parallaxConfig = GetParallaxConfig();
-        if (parallaxConfig == null)
-        {
-            Logger.ErrorS("parallax", $"Parallax config not found or unreadable: {ParallaxConfigPath}");
-            // The show must go on.
-            return Texture.Transparent;
-        }
-
-        var debugParallax = IoCManager.Resolve<IConfigurationManager>().GetCVar(CCVars.ParallaxDebug);
-        var resManager = IoCManager.Resolve<IResourceManager>();
-
-        if (debugParallax
-            || !resManager.UserData.TryReadAllText(PreviousParallaxConfigPath, out var previousParallaxConfig)
-            || previousParallaxConfig != parallaxConfig)
-        {
-            var table = Toml.ReadString(parallaxConfig);
-            await UpdateCachedTexture(table, debugParallax, cancel);
-
-            //Update the previous config
-            using var writer = resManager.UserData.OpenWriteText(PreviousParallaxConfigPath);
-            writer.Write(parallaxConfig);
-        }
-
-        try
-        {
-            return GetCachedTexture();
-        }
-        catch (Exception ex)
-        {
-            Logger.ErrorS("parallax", $"Couldn't retrieve parallax cached texture: {ex}");
-
-            try
-            {
-                // Also try to at least sort of fix this if we've been fooled by a config backup
-                resManager.UserData.Delete(PreviousParallaxConfigPath);
-            }
-            catch (Exception)
-            {
-                // The show must go on.
-            }
-            return Texture.Transparent;
-        }
+        var cache = IoCManager.Resolve<GeneratedParallaxCache>();
+        return await cache.Load(Identifier, ParallaxConfigPath, cancel);
     }
 
-    private async Task UpdateCachedTexture(TomlTable config, bool saveDebugLayers, CancellationToken cancel = default)
+    void IParallaxTextureSource.Unload(IDependencyCollection dependencies)
     {
-        var debugImages = saveDebugLayers ? new List<Image<Rgba32>>() : null;
-
-        var sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("parallax");
-
-        // Generate the parallax in the thread pool.
-        using var newParallexImage = await Task.Run(() =>
-            ParallaxGenerator.GenerateParallax(config, new Size(1920, 1080), sawmill, debugImages, cancel), cancel);
-
-        // And load it in the main thread for safety reasons.
-        // But before spending time saving it, make sure to exit out early if it's not wanted.
-        cancel.ThrowIfCancellationRequested();
-        var resManager = IoCManager.Resolve<IResourceManager>();
-
-        // Store it and CRC so further game starts don't need to regenerate it.
-        await using var imageStream = resManager.UserData.OpenWrite(ParallaxCachedImagePath);
-        await newParallexImage.SaveAsPngAsync(imageStream, cancel);
-
-        if (saveDebugLayers)
-        {
-            for (var i = 0; i < debugImages!.Count; i++)
-            {
-                var debugImage = debugImages[i];
-                await using var debugImageStream = resManager.UserData.OpenWrite(new ResPath($"/parallax_{Identifier}debug_{i}.png"));
-                await debugImage.SaveAsPngAsync(debugImageStream, cancel);
-            }
-        }
-    }
-
-    private Texture GetCachedTexture()
-    {
-        var resManager = IoCManager.Resolve<IResourceManager>();
-        using var imageStream = resManager.UserData.OpenRead(ParallaxCachedImagePath);
-        return Texture.LoadFromPNGStream(imageStream, "Parallax");
-    }
-
-    private string? GetParallaxConfig()
-    {
-        var resManager = IoCManager.Resolve<IResourceManager>();
-        if (!resManager.TryContentFileRead(ParallaxConfigPath, out var configStream))
-        {
-            return null;
-        }
-
-        using var configReader = new StreamReader(configStream, EncodingHelpers.UTF8);
-        return configReader.ReadToEnd().Replace(Environment.NewLine, "\n");
+        var cache = dependencies.Resolve<GeneratedParallaxCache>();
+        cache.Unload(Identifier);
     }
 }
 
index dc514c1304bfbb49c471adbcf6b9a69eca6619bb..990b74a4101a61b6f027daa21fd12f1a32efc258 100644 (file)
@@ -1,7 +1,6 @@
 using System.Threading;
 using System.Threading.Tasks;
 using Robust.Client.Graphics;
-using Robust.Shared.Graphics;
 
 namespace Content.Client.Parallax.Data
 {
@@ -13,6 +12,13 @@ namespace Content.Client.Parallax.Data
         /// Note that this should be cached, but not necessarily *here*.
         /// </summary>
         Task<Texture> GenerateTexture(CancellationToken cancel = default);
+
+        /// <summary>
+        /// Called when the parallax texture is no longer necessary, and may be unloaded.
+        /// </summary>
+        void Unload(IDependencyCollection dependencies)
+        {
+        }
     }
 }
 
diff --git a/Content.Client/Parallax/Managers/GeneratedParallaxCache.cs b/Content.Client/Parallax/Managers/GeneratedParallaxCache.cs
new file mode 100644 (file)
index 0000000..845f631
--- /dev/null
@@ -0,0 +1,202 @@
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Content.Client.Parallax.Data;
+using Content.Shared.CCVar;
+using Nett;
+using Robust.Client.Graphics;
+using Robust.Shared.Collections;
+using Robust.Shared.Configuration;
+using Robust.Shared.ContentPack;
+using Robust.Shared.Utility;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace Content.Client.Parallax.Managers;
+
+/// <summary>
+/// Caches the textures generated by <see cref="GeneratedParallaxTextureSource"/>
+/// </summary>
+public sealed class GeneratedParallaxCache : IPostInjectInit
+{
+    [Dependency] private readonly IConfigurationManager _cfg = null!;
+    [Dependency] private readonly IResourceManager _res = null!;
+    [Dependency] private readonly ILogManager _logManager = null!;
+
+    private readonly Dictionary<string, CacheDatum> _data = new();
+
+    private ISawmill _sawmill = null!;
+
+    public Task<Texture> Load(string id, ResPath configPath, CancellationToken cancel = default)
+    {
+        if (!_data.TryGetValue(id, out var datum))
+        {
+            _sawmill.Verbose($"Loading new generated layer {id} with config path {configPath}");
+
+            var cts = new CancellationTokenSource();
+
+            var loadTask = LoadTask(id, configPath, cts.Token);
+            datum = new CacheDatum
+            {
+                CancellationSource = cts,
+                ConfigPath = configPath,
+                LoadTask = loadTask,
+            };
+
+            _data.Add(id, datum);
+        }
+        else
+        {
+            if (datum.ConfigPath != configPath)
+                throw new InvalidOperationException("Generated parallax layers with the same ID must have the same config path!");
+        }
+
+        datum.RefCount += 1;
+
+        if (!datum.LoadTask.IsCompleted)
+            cancel.Register(() => Unload(id));
+
+        return datum.LoadTask;
+    }
+
+    public void Unload(string id)
+    {
+        if (!_data.TryGetValue(id, out var datum))
+            throw new InvalidOperationException("Layer is not cached!");
+
+        DebugTools.Assert(datum.RefCount >= 1);
+
+        datum.RefCount -= 1;
+        if (datum.RefCount == 0)
+        {
+            _sawmill.Verbose($"Unloading generated layer {id}");
+
+            // If we're still loading, cancel the active load.
+            datum.CancellationSource.Cancel();
+
+            // We should probably be unloading the texture here forcibly,
+            // but the previous code didn't so I won't either.
+            _data.Remove(id);
+        }
+    }
+
+    private async Task<Texture> LoadTask(string id, ResPath configPath, CancellationToken cancel)
+    {
+        return await GenerateTexture(id, configPath, cancel);
+    }
+
+    private async Task<Texture> GenerateTexture(string id, ResPath configPath, CancellationToken cancel)
+    {
+        var parallaxConfig = GetParallaxConfig(configPath);
+        if (parallaxConfig == null)
+        {
+            _sawmill.Error($"Parallax config not found or unreadable: {configPath}");
+            // The show must go on.
+            return Texture.Transparent;
+        }
+
+        var debugParallax = _cfg.GetCVar(CCVars.ParallaxDebug);
+
+        if (debugParallax
+            || !_res.UserData.TryReadAllText(PreviousConfigPath(id), out var previousParallaxConfig)
+            || previousParallaxConfig != parallaxConfig)
+        {
+            var table = Toml.ReadString(parallaxConfig);
+            await UpdateCachedTexture(id, table, debugParallax, cancel);
+
+            //Update the previous config
+            using var writer = _res.UserData.OpenWriteText(PreviousConfigPath(id));
+            writer.Write(parallaxConfig);
+        }
+
+        try
+        {
+            return GetCachedTexture(id);
+        }
+        catch (Exception ex)
+        {
+            _sawmill.Error($"Couldn't retrieve parallax cached texture: {ex}");
+
+            try
+            {
+                // Also try to at least sort of fix this if we've been fooled by a config backup
+                _res.UserData.Delete(PreviousConfigPath(id));
+            }
+            catch (Exception)
+            {
+                // The show must go on.
+            }
+
+            return Texture.Transparent;
+        }
+    }
+
+    private async Task UpdateCachedTexture(string id, TomlTable config, bool saveDebugLayers, CancellationToken cancel)
+    {
+        var debugImages = saveDebugLayers ? new List<Image<Rgba32>>() : null;
+
+        // Generate the parallax in the thread pool.
+        using var newParallexImage = await Task.Run(() =>
+                ParallaxGenerator.GenerateParallax(config, new Size(1920, 1080), _sawmill, debugImages, cancel),
+            cancel);
+
+        // And load it in the main thread for safety reasons.
+        // But before spending time saving it, make sure to exit out early if it's not wanted.
+        cancel.ThrowIfCancellationRequested();
+
+        // Store it and CRC so further game starts don't need to regenerate it.
+        await using var imageStream = _res.UserData.OpenWrite(CachedImagePath(id));
+        await newParallexImage.SaveAsPngAsync(imageStream, cancel);
+
+        if (saveDebugLayers)
+        {
+            for (var i = 0; i < debugImages!.Count; i++)
+            {
+                var debugImage = debugImages[i];
+                await using var debugImageStream =
+                    _res.UserData.OpenWrite(new ResPath($"/parallax_{id}debug_{i}.png"));
+                await debugImage.SaveAsPngAsync(debugImageStream, cancel);
+            }
+        }
+    }
+
+    private Texture GetCachedTexture(string id)
+    {
+        using var imageStream = _res.UserData.OpenRead(CachedImagePath(id));
+        return Texture.LoadFromPNGStream(imageStream, $"Parallax {id}");
+    }
+
+    private string? GetParallaxConfig(ResPath configPath)
+    {
+        if (!_res.TryContentFileRead(configPath, out var configStream))
+            return null;
+
+        using var configReader = new StreamReader(configStream, EncodingHelpers.UTF8);
+        return configReader.ReadToEnd().Replace(Environment.NewLine, "\n");
+    }
+
+    private static ResPath CachedImagePath(string identifier)
+    {
+        return new ResPath($"/parallax_{identifier}cache.png");
+    }
+
+    private static ResPath PreviousConfigPath(string identifier)
+    {
+        return new ResPath($"/parallax_{identifier}config_old");
+    }
+
+    void IPostInjectInit.PostInject()
+    {
+        _sawmill = _logManager.GetSawmill("parallax.generated");
+    }
+
+    private sealed class CacheDatum
+    {
+        public required ResPath ConfigPath;
+        public required Task<Texture> LoadTask;
+        public required CancellationTokenSource CancellationSource;
+        public ValueList<CancellationTokenRegistration> CancelRegistrations;
+
+        public int RefCount;
+    }
+}
index 83e7febe27c2afbac0d1288e844f56e814410f28..bc7d7d60d681dfd58f0fecac437feee8dc97fc9c 100644 (file)
@@ -1,4 +1,3 @@
-using System.Collections.Concurrent;
 using System.Numerics;
 using System.Threading;
 using System.Threading.Tasks;
@@ -6,7 +5,6 @@ using Content.Client.Parallax.Data;
 using Content.Shared.CCVar;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Configuration;
-using Robust.Shared.Utility;
 
 namespace Content.Client.Parallax.Managers;
 
@@ -14,6 +12,7 @@ public sealed class ParallaxManager : IParallaxManager
 {
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IConfigurationManager _configurationManager = default!;
+    [Dependency] private readonly IDependencyCollection _deps = null!;
 
     private ISawmill _sawmill = Logger.GetSawmill("parallax");
 
@@ -40,14 +39,29 @@ public sealed class ParallaxManager : IParallaxManager
     {
         if (_loadingParallaxes.TryGetValue(name, out var loading))
         {
+            _sawmill.Debug($"Cancelling loading parallax {name}");
             loading.Cancel();
             _loadingParallaxes.Remove(name, out _);
             return;
         }
 
-        if (!_parallaxesLQ.ContainsKey(name)) return;
-        _parallaxesLQ.Remove(name);
-        _parallaxesHQ.Remove(name);
+        _sawmill.Debug($"Unloading parallax {name}");
+
+        if (_parallaxesLQ.Remove(name, out var layers))
+        {
+            foreach (var layer in layers)
+            {
+                layer.Config.Texture.Unload(_deps);
+            }
+        }
+
+        if (_parallaxesHQ.Remove(name, out layers))
+        {
+            foreach (var layer in layers)
+            {
+                layer.Config.Texture.Unload(_deps);
+            }
+        }
     }
 
     public async void LoadDefaultParallax()
@@ -68,6 +82,9 @@ public sealed class ParallaxManager : IParallaxManager
         // Begin (for real)
         _sawmill.Debug($"Loading parallax {name}");
 
+        // Keep a list of layers we did successfully load, in case we have to cancel the load.
+        var loadedLayers = new List<ParallaxLayerPrepared>();
+
         try
         {
             var parallaxPrototype = _prototypeManager.Index<ParallaxPrototype>(name);
@@ -77,23 +94,33 @@ public sealed class ParallaxManager : IParallaxManager
             if (parallaxPrototype.LayersLQUseHQ)
             {
                 layers = new ParallaxLayerPrepared[2][];
-                layers[0] = layers[1] = await LoadParallaxLayers(parallaxPrototype.Layers, cancel);
+                layers[0] = layers[1] = await LoadParallaxLayers(parallaxPrototype.Layers, loadedLayers, cancel);
             }
             else
             {
                 layers = await Task.WhenAll(
-                    LoadParallaxLayers(parallaxPrototype.Layers, cancel),
-                    LoadParallaxLayers(parallaxPrototype.LayersLQ, cancel)
+                    LoadParallaxLayers(parallaxPrototype.Layers, loadedLayers, cancel),
+                    LoadParallaxLayers(parallaxPrototype.LayersLQ, loadedLayers, cancel)
                 );
             }
 
-            _loadingParallaxes.Remove(name, out _);
+            cancel.ThrowIfCancellationRequested();
 
-            if (token.Token.IsCancellationRequested) return;
+            _loadingParallaxes.Remove(name);
 
             _parallaxesLQ[name] = layers[1];
             _parallaxesHQ[name] = layers[0];
 
+            _sawmill.Verbose($"Loading parallax {name} completed");
+        }
+        catch (OperationCanceledException)
+        {
+            _sawmill.Verbose($"Loading parallax {name} cancelled");
+
+            foreach (var loadedLayer in loadedLayers)
+            {
+                loadedLayer.Config.Texture.Unload(_deps);
+            }
         }
         catch (Exception ex)
         {
@@ -101,25 +128,35 @@ public sealed class ParallaxManager : IParallaxManager
         }
     }
 
-    private async Task<ParallaxLayerPrepared[]> LoadParallaxLayers(List<ParallaxLayerConfig> layersIn, CancellationToken cancel = default)
+    private async Task<ParallaxLayerPrepared[]> LoadParallaxLayers(
+        List<ParallaxLayerConfig> layersIn,
+        List<ParallaxLayerPrepared> loadedLayers,
+        CancellationToken cancel = default)
     {
         // Because this is async, make sure it doesn't change (prototype reloads could muck this up)
         // Since the tasks aren't awaited until the end, this should be fine
         var tasks = new Task<ParallaxLayerPrepared>[layersIn.Count];
         for (var i = 0; i < layersIn.Count; i++)
         {
-            tasks[i] = LoadParallaxLayer(layersIn[i], cancel);
+            tasks[i] = LoadParallaxLayer(layersIn[i], loadedLayers, cancel);
         }
         return await Task.WhenAll(tasks);
     }
 
-    private async Task<ParallaxLayerPrepared> LoadParallaxLayer(ParallaxLayerConfig config, CancellationToken cancel = default)
+    private async Task<ParallaxLayerPrepared> LoadParallaxLayer(
+        ParallaxLayerConfig config,
+        List<ParallaxLayerPrepared> loadedLayers,
+        CancellationToken cancel = default)
     {
-        return new ParallaxLayerPrepared()
+        var prepared = new ParallaxLayerPrepared()
         {
             Texture = await config.Texture.GenerateTexture(cancel),
             Config = config
         };
+
+        loadedLayers.Add(prepared);
+
+        return prepared;
     }
 }
 
diff --git a/Resources/Textures/Parallaxes/AspidParallaxBG.png.yml b/Resources/Textures/Parallaxes/AspidParallaxBG.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/AspidParallaxNeb.png.yml b/Resources/Textures/Parallaxes/AspidParallaxNeb.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/Asteroids.png.yml b/Resources/Textures/Parallaxes/Asteroids.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/KettleParallaxBG.png.yml b/Resources/Textures/Parallaxes/KettleParallaxBG.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/KettleParallaxNeb.png.yml b/Resources/Textures/Parallaxes/KettleParallaxNeb.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/core_planet.png.yml b/Resources/Textures/Parallaxes/core_planet.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/debris_large.png.yml b/Resources/Textures/Parallaxes/debris_large.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/debris_small.png.yml b/Resources/Textures/Parallaxes/debris_small.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/gas_giant.png.yml b/Resources/Textures/Parallaxes/gas_giant.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/land.png.yml b/Resources/Textures/Parallaxes/land.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/layer1.png.yml b/Resources/Textures/Parallaxes/layer1.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/noise.png.yml b/Resources/Textures/Parallaxes/noise.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/planet.png.yml b/Resources/Textures/Parallaxes/planet.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false
diff --git a/Resources/Textures/Parallaxes/space_map2.png.yml b/Resources/Textures/Parallaxes/space_map2.png.yml
new file mode 100644 (file)
index 0000000..a2cfb0a
--- /dev/null
@@ -0,0 +1 @@
+preload: false