FNA-XNA / FNA

FNA - Accuracy-focused XNA4 reimplementation for open platforms
https://fna-xna.github.io/
2.64k stars 268 forks source link

IsBorderlessEXT not working as expected. #58

Closed Kleenox closed 8 years ago

Kleenox commented 8 years ago

Hey, I'm moving from Monogame to FNA and it seems that FNA's Window.IsBorderlessEXT doesn't have the same behavior than Monogame's Window.IsBorderless, it seems that it actually switches the game to fullscreen.

In Windows 10, with FNA's version I just get full screen behavior, you can tell because everytime you alt tab there is a flicker, whereas with Monogame this doesn't happen.

I tried to achieve the borderless behavior directly with SDL directly like this, but this exhibits the same issue.

  SDL2.SDL.SDL_SetWindowPosition(this.Window.Handle, 0, 0);
  SDL2.SDL.SDL_SetWindowSize(this.Window.Handle, graphics.GraphicsDevice.DisplayMode.Width, graphics.GraphicsDevice.DisplayMode.Height);
  SDL2.SDL.SDL_SetWindowBordered(this.Window.Handle, SDL2.SDL.SDL_bool.SDL_FALSE);

There is a small difference though, with the SDL way at least I got it to render in from of the taskbar in a Windows 7 test machine, which didn't work with IsBorderless.

flibitijibibo commented 8 years ago

What does your IsBorderlessEXT code actually look like? What resolution are you setting relative to the native display resolution?

Kleenox commented 8 years ago

I'm doing this:

        protected override void Initialize()
        {
            this.IsMouseVisible = true;
            base.Initialize();

            graphics.PreferredBackBufferWidth = graphics.GraphicsDevice.DisplayMode.Width;
            graphics.PreferredBackBufferHeight = graphics.GraphicsDevice.DisplayMode.Height;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();

            this.Window.AllowUserResizing = false;

#if FNA
            this.Window.IsBorderlessEXT = true;
#else //Monogame...
            this.Window.IsBorderless = true;
            this.Window.Position = new Point(0, 0);
#endif
        }
flibitijibibo commented 8 years ago

That might be a little wonky because you're doing about twice as much WM interaction as you think you are. Try this instead:

public YourGame() : base()
{
    graphics = new GraphicsDeviceManager(this);
    DisplayMode native = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode;
    graphics.PreferredBackBufferWidth = native.Width;
    graphics.PreferredBackBufferHeight = native.Height;
    graphics.IsFullScreen = false;
    IsMouseVisible = true;
    Window.AllowUserResizing = false; // Redundant!
}

protected override void Initialize()
{
    base.Initialize();
    Window.IsBorderlessEXT = true;
}

What happens at base.Initialize() is that the GD is made and ApplyChanges is called internally; setting your parameters before Initialize will reduce the number of WM calls before we remove the window border.

That said, if you're just trying to do borderless fullscreen, you can simply use IsFullScreen = true and skip the IsBorderlessEXT call; we use SDL_WINDOW_FULLSCREEN_DESKTOP by default, so you don't have to create it manually. IsBorderlessEXT is only legitimately useful when in windowed mode.

Kleenox commented 8 years ago

Hey, thanks for the tips! Still not behaving like borderless though. The problem seems to be in SDL2, then. I don't think it's a Windows 10 problem because it works with monogame, but in FNA, it's behaving like it's SDL_WINDOW_FULLSCREEN (flickering when you alt+tab and all). I'll post more info if I figure something out.

flibitijibibo commented 8 years ago

It might be a Win10 problem actually; we were fighting something like this in FEZ 1.12:

https://github.com/renaudbedard/fez-1.12-issues/issues/122#issuecomment-237540312

Also keep in mind that for fullscreen we do some extra work to ensure alt-tab works like it should:

https://github.com/FNA-XNA/FNA/blob/master/src/FNAPlatform/SDL2_FNAPlatform.cs#L663

What you want to do is verify that the fullscreen flag is actually unset when you alt-tab your borderless window; I wouldn't expect it to implicitly operate in fullscreen unless you actually ask for it, so an SDL bug would be SDL_GetWindowFlags(window) containing SDL_WINDOW_FULLSCREEN_DESKTOP when we've not applied that setting ourselves.

Kleenox commented 8 years ago

What I don't understand is why any work at all on alt+tab is necessary when in borderless window mode.

My understanding is what you just need for "windowed fullscreen" is a normal window, with no border style, position set to 0 and size set to the desktop size. When Windows detects these conditions, the taskbar is hidden. Am I missing something?

I feel like SDL is doing too much when it isn't necessary in this instance. There is some kind of mode switching when I alt tab in the application and what I need is for SDL and FNA to not do something.

For example, if I set IsFullScreen to false, and just do this:

            SDL2.SDL.SDL_SetWindowPosition(this.Window.Handle, 0, 0);
            SDL2.SDL.SDL_SetWindowSize(this.Window.Handle, graphics.GraphicsDevice.DisplayMode.Width, graphics.GraphicsDevice.DisplayMode.Height);
            SDL2.SDL.SDL_SetWindowBordered(this.Window.Handle, SDL2.SDL.SDL_bool.SDL_TRUE);

And then I disable this block in FNA:

if (false && !osxUseSpaces)
                            {
                                // If we alt-tab away, we lose the 'fullscreen desktop' flag on some WMs
                                SDL.SDL_SetWindowFullscreen(
                                    game.Window.Handle,
                                    game.GraphicsDevice.PresentationParameters.IsFullScreen ?
                                        (uint) SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP :
                                        0
                                );
                            }

I already get the behavior that I want, except that everytime I alt+tab in or out of the application I get the typical "mode switch" flicker. I know it's not a problem with Windows 10 (although it could be a part of it) because this is instantaneous in Monogame. And from experience working with the Win32 API, just by creating a Wndow like this it should be enough. Any idea what's going on and how I can stop it?

flibitijibibo commented 8 years ago

Wait, the flicker is mode-switching? That's impossible, we never touch the display mode at all... I may need to see your full code for this; either you've got something that's not actually XNA4-compliant or you've got WM code that I've not seen yet.

Kleenox commented 8 years ago

Hey so I found a hack tha may illuminate the issue. Set IsFullScreen to false and set the height of the window to 1 extra pixel:

            SDL2.SDL.SDL_SetWindowPosition(this.Window.Handle, 0, 0);
            SDL2.SDL.SDL_SetWindowSize(this.Window.Handle, graphics.GraphicsDevice.DisplayMode.Width,
graphics.GraphicsDevice.DisplayMode.Height+1); //note +1
            SDL2.SDL.SDL_SetWindowBordered(this.Window.Handle, SDL2.SDL.SDL_bool.SDL_FALSE);

This gives me exactly the behavior that I want, I have a fullscreen Window that overlaps the taskbar and alt+tabbing in and out of it is lighting fast. So basically, something is doing some extra work when the dimensions happen to be the same, any ideas?

flibitijibibo commented 8 years ago

Just to check: Are the SDL2.dll version different between fnalibs and MonoGame's Libs/ folder? They should still be using our mirror, but maybe there's a version desync somewhere.

On the note of window position, can you check this block of code out?

https://github.com/FNA-XNA/FNA/blob/master/src/FNAPlatform/SDL2_FNAPlatform.cs#L322

Kleenox commented 8 years ago

I commented out the "if (center)" block and it doesn't change anything.

To describe the flicker a bit better.

What happens when I press alt+tab inside the application is that the game screen goes black for a second, then the game screen will come back along with the alt+tab dialog. And no, at no point is SDL_WINDOW_FULLSCREEN_DESKTOP or SDL_WINDOW_FULLSCREEN set according to SDL.

SDL2.dll is exactly the same file that comes in the fnalibs packages. Is there anything else I should check?

I'll keep doing some testing.

flibitijibibo commented 8 years ago

Took a second look at MG's event handling - basically the only thing that's different is the fullscreen flag caching that shouldn't apply here in the first place! So why it behaves differently, you may just have to alt-tab and break before it's finished minimizing.

As for the Win10 taskbar, ApplyChanges is going to be our only real difference:

https://github.com/FNA-XNA/FNA/blob/master/src/FNAPlatform/SDL2_FNAPlatform.cs#L242

https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/SDL/SDLGameWindow.cs#L236

The only major difference is that we check the window size before actually setting the size:

https://github.com/FNA-XNA/FNA/blob/master/src/FNAPlatform/SDL2_FNAPlatform.cs#L295

flibitijibibo commented 8 years ago

Actually here's one more for you: Add this after our SDL_CreateWindow call:

SDL.SDL_SetHintWithPriority(
    SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
    "0",
    SDL.SDL_HintPriority.SDL_HINT_OVERRIDE
);
Kleenox commented 8 years ago

I'll look into all that and I'll get back to you, but a quick question...

I'm starting to think this is a graphics driver issue, because I just noticed that performance in Windowed mode is really poor in FNA, yet smooth in Monogame. This, for example, with a totally normal window that is 800x600. Could be that Monogame is using DX11 and FNA is using DX9/Opengl and the difference comes from that.

How do I check what accelerated driver is FNA's SDL2 using for rendering? (Assuming FNA uses SDL for rendering at all). I checked your provided SDL2.dll with depends but it doesn't reference either.

flibitijibibo commented 8 years ago

FNA's using OpenGL rather than Direct3D. We print driver info to stdout, so check your Output tab for vendor/version information.

Kleenox commented 8 years ago

Ok! I feel dumb now, I should have researched this better. I did check the documentation and the only reference to API's I found was this: "This allows us to use the original XNB-packed Effects built by XNA and effect binaries built by the DirectX SDK's Effect compiler." But I totally misread that, I took it to mean that you use D3D by default.

I will close this now, as this is most certainly a OpenGL issue. I don't think there's anything wrong with your handling of alt+tabbing, sorry to waste your time!

Ah, before I close this, I don't suppose there's a way to make FNA run with ANGLE? That may do it.

flibitijibibo commented 8 years ago

Possibly! Have a look at the FORCE_ES2 environment variable:

https://github.com/FNA-XNA/FNA/wiki/7:-FNA-Environment-Variables#fna_opengl_force_es2

SDL does support ANGLE, but at the moment it's only supported when your driver does not support GLES (it almost certainly does):

https://github.com/FNA-XNA/SDL-mirror/blob/master/src/video/windows/SDL_windowsopengl.c#L409 https://github.com/FNA-XNA/SDL-mirror/blob/9328b68368628ddc3272c0c27280e12c7116186d/src/video/windows/SDL_windowsopengl.c#L602 https://github.com/FNA-XNA/SDL-mirror/blob/9328b68368628ddc3272c0c27280e12c7116186d/src/video/windows/SDL_windowswindow.c#L308 https://github.com/FNA-XNA/SDL-mirror/blob/master/src/video/windows/SDL_windowsopengles.c

If you can trick it into not loading the native GLES support you should be able to get it to load ANGLE instead. I have no idea how well it'll work though - we're "mostly" compliant with ES2, but I think ANGLE has the ES3 feature set anyway so it should work, in theory...

Kleenox commented 8 years ago

Cool, I'll look into that. Thanks for all the help! Closing this :)