Open RedKorshun opened 1 year ago
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.
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.
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).
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
@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?
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.
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;
}
}
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;
I have literally never seen this before from C#... When I have a breakpoint, the IsFullScreen changes properly to false which does not cause a crash.
When I make a conditional breakpoint to only trigger when the value is true it shows that GameWindow.IsFullscreen is set to true when it should be false.... https://github.com/Doprez/stride/blob/0e053a3b8873f49e9e0e5450a3dfad368a6ed042/sources/engine/Stride.Games/GameWindow.cs#L196
This seems to stem from my SyncScript class which is attempting to change the window similar to the original post
if (Input.IsKeyPressed(Keys.Tab))
{
Game.Window.IsFullscreen = false
}
Is there a threading issue here or something? I dont understand why the bool would be so defiant lol.
Ok so it seems like the property is being called twice for some weird reason and when it immediately goes from false to true in the same call seems to be where the crash happens.
Its a bit weird to step through, if you have a breakpoint that doesnt check if the property is being set to true then that breakpoint will act as iff the user clicked out of the window which disables fullscreen successfully and doesnt crash.
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:
public class FullScreenToggler : SyncScript { public override void Update() { if (Input.Keyboard.IsKeyDown(Keys.F)) { Game.Window.IsFullscreen = !Game.Window.IsFullscreen; } } }