Loading textures using Texture2D.FromStream on different thread

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();
        }
    }