GraphicDevice.Present() giving me almost no result in async loading

Hi! I’m trying to make LoadingScreen work with no threads UWP policy. It looks like everything works but I dont see anything on screen besides my GraphicDevice.Clear(color) results. I don’t have any more ideas anymore what’s wrong here, trying to make it work for forever.

Load method, everything gets called as intended.
private async void LoadAsync() { while (!done) { long lastTime = Stopwatch.GetTimestamp(); GameTime gameTime = GetGameTime(ref lastTime); DrawLoadAnimation(gameTime); await Task.Delay(10).ConfigureAwait(false); } }

Draw methods
void DrawLoadAnimation(GameTime gameTime) { if ((ScreenManager.GraphicsDevice == null) || ScreenManager.GraphicsDevice.IsDisposed) return; DrawAnim(gameTime); ScreenManager.GraphicsDevice.Present(); }

public int testIncrease = 0; public void DrawAnim(GameTime gameTime) { testIncrease++; ScreenManager.GraphicsDevice.Clear(new Color(testIncrease, testIncrease, testIncrease)); SpriteBatch spriteBatch = ScreenManager.SpriteBatch; spriteBatch.Begin(); //testing with some fresh texture Texture2D blankTexture = new Texture2D(ScreenManager.GraphicsDevice, 1, 1); blankTexture.SetData(new[] { Color.Red }); spriteBatch.Draw(blankTexture, new Rectangle(64, 64, 512, 512), Color.White); //also some text writing code here 100% functional in usual draw loop spriteBatch.End(); }

As you can see in the last method I use testIncrease to change GraphicDevice.Clear color, and it works! Background color gradually changing from black to white while loading, but textures and text are invisible. Do I need to do something else? Prepare spritebatch in some way for Present()?

Also, I did try to swap main thread and async tasks: main thread drawing and async task are loading the next screen. It works, but it is super slow so I really want to make this work (async drawing, main loading).
Any help greatly appreciated!

Hi TheMaxPirate! Here are a few things I notice:

  • The texture data should be created and set only once. I see you’re creating a new Texture each draw without disposing it, leaking resources, which can cause all sorts of issues in addition to being very slow.
  • Since it looks like you’re simply loading data, I don’t see a need to draw the animation in the async load method. Instead, call Draw every frame as per standard and use data obtained from the async method to adjust what is drawn. This is likely why you’re not seeing much, since it’s not drawing anything while the task is waiting to complete.
  • I’m not familiar with your code, but you shouldn’t need to call GraphicsDevice.Present() manually after a SpriteBatch End unless there’s a good reason for it.

Thanks for the answer!

  • The texture data should be created and set only once. I see you’re creating a new Texture each draw without disposing it, leaking resources, which can cause all sorts of issues in addition to being very slow.

Yes, this is just for demonstration, that texture is 100% exist. I didnt want to include too much code, so it will be easier to read. I don’t do that in the real code.

  • Since it looks like you’re simply loading data, I don’t see a need to draw the animation in the async load method. Instead, call Draw every frame as per standard and use data obtained from the async method to adjust what is drawn. This is likely why you’re not seeing much, since it’s not drawing anything while the task is waiting to complete.

It was usual practice in xna days, but we used Threads back then. You can get very smooth loading animations without the hassle of changing every gamescreen LoadContent method (as you will need to load tiny thing at a time and let draw be called and start other). Plus as far as I understand if OS decided so, your thread could be on another core.

  • I’m not familiar with your code, but you shouldn’t need to call GraphicsDevice.Present() manually after a SpriteBatch End unless there’s a good reason for it.

That’s the idea: first main thread going to load very heavy LoadContent, it will take some time like 30 sec and all this time Draw() will never be called as Load is not complete. You make another thread which will use Present() to redraw screen in the meantime. It worked great in xna, but now I’m thinking that maybe monogame did not implement Present() fully? Maybe only for some platforms? It seems async method has nothing to do with it, even if I call Present in anyplace and put a breakpoint right after I will see only GraphicDevice.Clear color and nothing else.

PS
Here is some old post code with the same multi-thread concept on xna http://xboxforums.create.msdn.com/forums/p/45017/468346.aspx#468346

I understand this, but it doesn’t address the concern I had. The sample you showed me was able to do what it did because the draw code was on another thread. Async methods are not run on new threads, so your draw code is not being executed frequently enough while waiting for the data to load. Therefore, I suggest loading the data in the async method and using that data in the main draw method for the loading screen. This way, the loading screen will always be drawn while the content is loading in the background.

Some of the open issues regarding UWP indicate that there are problems which may affect Present().

I does execute frequently enough for my liking (I checked it with debug writelines, It’s just what I need), the only problem is Present().
In other things I agree, thanks for your help!

After another day I can say this: it’s basically impossible right now. Let’s break it down:
1)Main thread load and background thread draw (async on UWP and usual threads on other platforms)
UWP: Present() not working right on any thread, so no.
Android: GraphicDevice methods should be called from UI thread which is main thread, so no.
IOS: At this point I didn’t check, even if it works we need multiplatform solution.

2)Main thread draw and background thread load.
UWP: Works great, but very slow (4-6x slower than usual no animation load, for comparison I got about 2x max with xna multithread on WP)
Android: Same thing, works but super slow.
IOS: Works and very fast for some reason (almost 1 to 1 with no animation load). But again, need multiplatfrom solution.

3)Just chop your load and don’t use multithreads.
I’m afraid this is the only resonable solution at the moment. If you have bad habbit of not only load content in LoadContent() but also initialize and configure stuff, I present to you this solution:
First, we store loading chunks as actions.

           public Action[] loadingChunks;
            public int currentChunkToLoad = 0;
            public bool LoadingIsDone
            {
                get { return currentChunkToLoad >= loadingChunks.Length; }
            }

public void LoadChunk()
        {
            loadingChunks[currentChunkToLoad++].Invoke();
        }

Next, you fill it up:

public GameplayScreen()
{
     loadingChunks = new Action[]
     {
            new Action(() =>
            {
                //SOMETHING
            }),
            new Action(() =>
            {
                //SOMETHING 2
            }),
       };
}

And modify your Update and Draw.

public override void Update(GameTime gameTime)
        {
            if (!LoadingIsDone)
            {
                LoadChunk();
                return;
            }
            //Your update
}

public override void Draw(GameTime gameTime)
        {
            if (!LoadingIsDone)
            {
                //Draw loading graphics here
                return;
            }
            //Your draw
}

Not sure if that’s best way to chop your content code, but that’s my take on it.

Thanks for clarifying; I think I understand the issue more now.

Are you loading XNBs or raw assets? I think what I’m confused about is why a main thread would load content faster than a background thread. I’m not sure how much this will help, but turn off FixedTimeStep and VSync during the loading screen to unthrottle the main game loop, then change them back to the previous settings when its done. It’s possible this can speed up loading.