Hello guys,
is it possible to load Texture2D using Texture2D.FromStream on a different thread? Calling FromStream method using a Task seems to lock everything.
I’m using MonoGame 3.7.1 DesktopGL.
Sample code:
var t = Task.Run(() =>
{
using (Stream fileStream = File.OpenRead(path))
var texture = Texture2D.FromStream(GraphicsDevice, fileStream); // <— it stops here
});
Task.WaitAll(t); <-- this never gets completed
My AssetManager runs perfectly fine on it’s own thead.
It first tries to load from the content system, if that fails it loads from stream.
It also loads shaders, models, sound effects without any issues.
The only difference with my code and yours is I have assigned the asset manager it’s own thread on it’s own core.
It runs all the time.
case AssetRecordType.Texture:
{
int GUID = loadArgs.Path.GetHashCode();
if (!loadedAssets.ContainsKey(GUID))
{
Texture2D tex = null;
try {
tex = Load<Texture2D>(loadArgs.Path);
} catch (Exception)
{
try
{
Stream read = new FileStream(loadArgs.Path, FileMode.Open);
tex = Texture2D.FromStream(Renderer.GetGraphicsDevice(), read);
read.Close();
}
catch (Exception)
{
tex = defaultTexture;
LogHelper.Instance.Error("Missing texture " + loadArgs.Path);
}
}
loadArgs.Asset = tex;
MutableHolder<AssetRecord> ar = new MutableHolder<AssetRecord>(loadArgs);
lock (loadedAssets)
{
loadedAssets.Add(GUID, ar);
}
}
}
break;
I would suggest you change the structure of your code so it doesn’t use Task and see if that helps
Here is my main asset loading code if it helps
/// <summary>
/// Consume the Queue of assets to be loaded then wait
/// </summary>
void LoadingThreadWorker()
{
AssetRecord args;
while (!mCloseRequested)
{
while (loadItemsQueue.Count > 0)
{
// Get next item to process
lock (loadItemsQueue)
{
args = loadItemsQueue.Peek();
}
// Process head queue entry
CallGenericLoad(args);
// Remove processed item. Can't be removed until
// loading complete as new async requests may need
// to add AssetLoaded methods to it's list
lock (loadItemsQueue)
{
loadItemsQueue.Dequeue();
}
}
// Wait until next load call
loadResetEvent.WaitOne();
}
}