Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception when switching window from fullscreen to windowed mode #1493

Open
RedKorshun opened this issue Aug 6, 2022 · 8 comments
Open

Exception when switching window from fullscreen to windowed mode #1493

RedKorshun opened this issue Aug 6, 2022 · 8 comments
Labels
bug Something isn't working

Comments

@RedKorshun
Copy link

RedKorshun commented Aug 6, 2022

Release Type: Official Release

Version: 4.1.0.1734

Platform: Windows

Describe the bug
Exception during switching to windowed mode.

To Reproduce
Steps to reproduce the behavior:

  1. Create a new game project using default settings
  2. Add a SyncScript asset with the following code:
using Stride.Engine;
using Stride.Input;

public class FullScreenToggler : SyncScript
{
    public override void Update()
    {
        if (Input.Keyboard.IsKeyDown(Keys.F))
        {
            Game.Window.IsFullscreen = !Game.Window.IsFullscreen;
        }
    }
}
  1. Add a ScriptComponent with the script from step 2 to the Camera (or any other) entity.
  2. Run the game using F5 hotkey (or in any other way).
  3. Toggle fullscreen mode using the "F" or "Alt+Enter" hotkey.
  4. Toggle windowed mode using exactly "F" hotkey (handled by the script from step 2).

Expected behavior
Game window is switched to windowed mode like it was before step 5 execution.

Screenshots
ContentSerializationExceptions

Log and callstacks

Additional context

  1. Using the "Alt+Enter" hotkey in step 6 (for switching back from fullscreen mode to windowed) works as expected.
  2. Even an empty scene with the only empty entity on it which has the ScriptComponent with the script from step 2 works as described.
  3. There are also similar issues, but they all belongs to a different kind of exception.
@RedKorshun RedKorshun added the bug Something isn't working label Aug 6, 2022
@RedKorshun
Copy link
Author

RedKorshun commented Aug 6, 2022

Since "Alt+Enter" is working as expected this may not be a big issue, but there is a common practice to add a fullscreen toggler in game video options and it won't work there.

@manio143
Copy link
Member

manio143 commented Aug 6, 2022

I'll try to repro this later, but the exceptions you're showing are related to serialization which should have nothing to do with changing window mode, which either should be very worrying or there's something else going on here.

@mmujic2
Copy link

mmujic2 commented Aug 6, 2022

I'm not so sure if related, but I get a very similar exception when I try to change window size while in fullscreen mode (different asset but same serializer can't be found).

@manio143
Copy link
Member

manio143 commented Aug 6, 2022

Ok, so I was able to repro this easily. Basically whenever things change for the GraphicsDevice such that it has to recreate everything it calls ResumeManager.OnReload which invokes reloading of all visual assets.

The exception message is thrown in the Reload callback of TextureContentSerializer L45, which performs a Load<Image> on the asset associated to the graphicsResource, but that graphics resource is of type Texture, which causes ContentManager to fail to retrieve it from cache of loaded objects and then try to deserialize it from the raw data, which fails again because there's no serializer compatible for a Texture that would return an Image.

While the underlying serialized data of a texture can be deserialized as an Image it seems that the way Reload callbacks are set up isn't taking all the details into account and would require deeper investigation to understand why this is happening.

The other issue is why this full reload happens in the first place. Looks like there may be an exception thrown during resizing from FullScreen in GraphicsDeviceManager.ChangeOrCreateDevice L1053.
(Error 0x80004005 is a type of unspecified Windows error code)

External component has thrown an exception.
   at System.Runtime.InteropServices.Marshal.Release(IntPtr pUnk)
   at SharpDX.ComObject.SharpDX.IUnknown.Release()
   at SharpDX.ComObject.Dispose(Boolean disposing)
   at SharpDX.DisposeBase.CheckAndDispose(Boolean disposing)
   at Stride.Graphics.SwapChainGraphicsPresenter.OnDestroyed() in C:\stride\sources\engine\Stride.Graphics\Direct3D\SwapChainGraphicsPresenter.Direct3D.cs:line 184
   at Stride.Graphics.SwapChainGraphicsPresenter.set_IsFullScreen(Boolean value) in C:\stride\sources\engine\Stride.Graphics\Direct3D\SwapChainGraphicsPresenter.Direct3D.cs:line 116
   at Stride.Games.GraphicsDeviceManager.ChangeOrCreateDevice(Boolean forceCreate) in C:\stride\sources\engine\Stride.Games\GraphicsDeviceManager.cs:line 1053

@RedKorshun
Copy link
Author

@manio143 , thanks for a quick feedback.
I wonder if the Alt+Enter hotkey uses a different code, because it causes no exceptions. If so, is this the expected behavior?

@manio143
Copy link
Member

manio143 commented Aug 7, 2022

I was able to trace the Alt+Enter behavior to GameForm.cs and seems to be doing the exactly same thing, except in a different moment in the game loop (before calling any of the game's systems, it happens in WindowsMessageLoop that process OS messages before calling Game.Tick() to process another frame) - this may be a better moment to modify the graphics device, but I'm not fully sure why.

@artems37rus
Copy link

artems37rus commented Nov 12, 2023

It'll work if you try it like this.

if (Input.Keyboard.IsKeyDown(Keys.E))
{
    if (Game.Window.IsFullscreen)
    {
        Game.Window.Visible = false;
        Game.Window.IsFullscreen = false;
        Game.Window.Visible = true;
    }
    else
    {
        Game.Window.SetSize(new Int2(1920, 1080));
        Game.Window.PreferredFullscreenSize = new Int2(1920, 1080);
        Game.Window.IsFullscreen = true;
    }
}

@mmujic2
Copy link

mmujic2 commented Dec 2, 2023

It'll work if you try it like this.

if (Input.Keyboard.IsKeyDown(Keys.E))
{
    if (Game.Window.IsFullscreen)
    {
        Game.Window.Visible = false;
        Game.Window.IsFullscreen = false;
        Game.Window.Visible = true;
    }
    else
    {
        Game.Window.SetSize(new Int2(1920, 1080));
        Game.Window.PreferredFullscreenSize = new Int2(1920, 1080);
        Game.Window.IsFullscreen = true;
    }
}

That's a nice workaround, tested it myself and it works like a charm. I'll leave one more note here: when changing resolution in fullscreen, these two ways worked for me:

// First way. I prefer this one because it causes less flickering
Game.Window.Visible = false;

Game.Window.SetSize(resolution);
Game.Window.PreferredFullscreenSize = resolution;

Game.Window.IsFullscreen = true;
Game.Window.Visible = true;

// Second way (switching to windowed and back to fullscreen)
gameSettings.Window.Visible = false;
gameSettings.Window.IsFullscreen = false;
gameSettings.Window.Visible = true;

gameSettings.Window.SetSize(resolution);
gameSettings.Window.PreferredFullscreenSize = resolution;
gameSettings.Window.IsFullscreen = true;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants