diff --git a/OpenRA.Game/Graphics/SequenceProvider.cs b/OpenRA.Game/Graphics/SequenceProvider.cs index c2a69b679b..dd250c5fa3 100644 --- a/OpenRA.Game/Graphics/SequenceProvider.cs +++ b/OpenRA.Game/Graphics/SequenceProvider.cs @@ -62,8 +62,10 @@ namespace OpenRA.Graphics public void Preload() { + SpriteCache.SheetBuilder.Current.CreateBuffer(); foreach (var unitSeq in sequences.Value.Values) foreach (var seq in unitSeq.Value.Values) { } + SpriteCache.SheetBuilder.Current.ReleaseBuffer(); } } diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs index e3b4c7ee62..660e4d2ccc 100644 --- a/OpenRA.Game/Graphics/Sheet.cs +++ b/OpenRA.Game/Graphics/Sheet.cs @@ -27,13 +27,7 @@ namespace OpenRA.Graphics public readonly Size Size; public byte[] GetData() { - if (data != null) - return data; - if (texture == null) - data = new byte[4 * Size.Width * Size.Height]; - else - data = texture.GetData(); - releaseBufferOnCommit = false; + CreateBuffer(); return data; } public bool Buffered { get { return data != null || texture == null; } } @@ -144,6 +138,17 @@ namespace OpenRA.Graphics return bitmap; } + public void CreateBuffer() + { + if (data != null) + return; + if (texture == null) + data = new byte[4 * Size.Width * Size.Height]; + else + data = texture.GetData(); + releaseBufferOnCommit = false; + } + public void CommitData() { CommitData(false); diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index 1792eb5115..cf528f1a99 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -28,6 +28,7 @@ namespace OpenRA readonly ModData modData; readonly SheetBuilder sheetBuilder; Thread previewLoaderThread; + bool previewLoaderThreadShutDown = true; object syncRoot = new object(); Queue generateMinimap = new Queue(); @@ -135,13 +136,20 @@ namespace OpenRA var maxKeepAlive = 5000 / emptyDelay; var keepAlive = maxKeepAlive; - while (keepAlive-- > 0) + for (;;) { List todo; lock (syncRoot) { todo = generateMinimap.Where(p => p.GetMinimap() == null).ToList(); generateMinimap.Clear(); + if (keepAlive > 0) + keepAlive--; + if (keepAlive == 0 && todo.Count == 0) + { + previewLoaderThreadShutDown = true; + break; + } } if (todo.Count == 0) { @@ -170,20 +178,38 @@ namespace OpenRA Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5); } } + sheetBuilder.Current.ReleaseBuffer(); + // The buffer is not fully reclaimed until changes are written out to the texture. + // We will access the texture in order to force changes to be written out, allowing the buffer to be freed. + Game.RunAfterTick(() => sheetBuilder.Current.GetTexture()); Log.Write("debug", "MapCache.LoadAsyncInternal ended"); } public void CacheMinimap(MapPreview preview) { + bool launchPreviewLoaderThread; lock (syncRoot) - generateMinimap.Enqueue(preview); - - if (previewLoaderThread == null || !previewLoaderThread.IsAlive) { - previewLoaderThread = new Thread(LoadAsyncInternal); - previewLoaderThread.IsBackground = true; - previewLoaderThread.Start(); + generateMinimap.Enqueue(preview); + launchPreviewLoaderThread = previewLoaderThreadShutDown; + previewLoaderThreadShutDown = false; } + + if (launchPreviewLoaderThread) + Game.RunAfterTick(() => + { + // Wait for any existing thread to exit before starting a new one. + if (previewLoaderThread != null) + previewLoaderThread.Join(); + + sheetBuilder.Current.CreateBuffer(); + previewLoaderThread = new Thread(LoadAsyncInternal) + { + Name = "Map Preview Loader", + IsBackground = true + }; + previewLoaderThread.Start(); + }); } public MapPreview this[string key]