Release sheet buffers in SequenceProvider and MapCache.
The buffers in SequenceProvider can be freed if Preload is called, since we know everything is loaded. A SequenceProvider is created for each TileSet is use so this saves memory for however many tilesets had been used in the game. This will be at least one for the shellmap, and often more. The MapCache loading thread is kept alive for 5 seconds after it last generated a map (in anticipation of more requests). Once this time expires the thread is allowed to die, as it is unlikely there will be more requests in the short term. At this time it is ideal to force the changes to be committed to the texture so we can release the buffer. As well as marking the buffer for release, we must access the texture to force the changes stored in the buffer to be written to the texture, after which the buffer can be reclaimed. Additionally, when starting the MapCache loading thread we must ensure the buffer is created from the main thread since it may query the texture object which has thread affinity. After that the buffer may be modified freely on the loading thread until released.
This commit is contained in:
committed by
RoosterDragon
parent
a6f5a21ed4
commit
c2b7d9ca5b
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA
|
||||
readonly ModData modData;
|
||||
readonly SheetBuilder sheetBuilder;
|
||||
Thread previewLoaderThread;
|
||||
bool previewLoaderThreadShutDown = true;
|
||||
object syncRoot = new object();
|
||||
Queue<MapPreview> generateMinimap = new Queue<MapPreview>();
|
||||
|
||||
@@ -135,13 +136,20 @@ namespace OpenRA
|
||||
var maxKeepAlive = 5000 / emptyDelay;
|
||||
var keepAlive = maxKeepAlive;
|
||||
|
||||
while (keepAlive-- > 0)
|
||||
for (;;)
|
||||
{
|
||||
List<MapPreview> 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]
|
||||
|
||||
Reference in New Issue
Block a user