andykorth / Pencil.Gaming

An open-source, cross-platform gaming library for C# with bindings for OpenGL, OpenAL, and GLFW.
136 stars 35 forks source link

Toggling to full screen causes SystemAccessViolations #30

Open delaneyj opened 10 years ago

delaneyj commented 10 years ago

Able to create a window in windowed or fullscreen mode with no issue but if I try to port an example of creating then destroying a window to toggle fullscreen getting System.AccessViolationExceptions. I would think the call to Glfw.MakeContextCurrent(window); on the new window would 'fix up' the context to take the GL calls. I'm doing a call to Glfw.PollEvents(); where the toggle should be happening well before the GL.Clear/SwapBuffers calls for that frame. Any ideas on proper toggling of window mode in Pencil?

fin-ger commented 10 years ago

Have a look at my FurryLana repository. In FurryLana/Base/Application/Window.cs is a crossplatform fullscreen toggle example. I created 2 windows. One in fullscreen mode and one in windowed mode and made shared contexts. One of the windows is hidden when the other one is showed. You need to swap between this window after swap buffers otherwise you will get an incomplete or empty frame. This solution IS A HACK and should not be used in production. I'm corrently working on a small c lib that "implements" the IWindow.cs and make direct Xlib calls. With this it is possible to send an XEvent and tell the window manager to set the window to fullscreen. By the way it is bad practise to use the fullscreen window from glfw as it uses XF86VidMode to change display resolution. When your program fails the resolution will not be reset. A better way to do it is to send a fullscreen message to your window manager and control the game/app resolution with the resolution of your framebuffer. Don't know if this is the regular way but it is not as annoying as the XF86VidMode thing when developping a game.

delaneyj commented 10 years ago

I'm going to try out your solution; was hopefully for something more production ready. Trying Pencil because of numerous issues with initialization of the window/context with OpenTK. Ironically toggling VideoMode from windowed to full screen in OpenTK was never an issue. Maybe the author can pipe in on a version of this that would not be a self described hack. However I thank you for your input and will try to implement the stop gap for now.

EDIT: It appears this is not working very well at all on a Windows 7 Pro setup. Unfortunately at this point I wouldn't see this as a resolution to the problem.

andykorth commented 10 years ago

Are you using glfw 2 or 3? And just to double check, this is just an issue on Windows 7 so far?

andykorth commented 10 years ago

So I did some testing on my system, and looked into the docs a bit.

In short, every time you call OpenWindow (glfw 2) or CreateWindow (glfw 3), you are creating a new OpenGL context. When you destroy the window, you destroy that context. If you're able to recreate your context at any point in your application, that's fine, but that's your responsibility. A little bit more information on this here: http://stackoverflow.com/questions/12881049/recreate-window-without-destroying-the-context Realistically, I think that's a lot of work, and it's one reason AAA titles tend to force you to restart when changing certain graphics settings.

You can avoid this difficulty by sharing a context. This is how Cocos2d mac works, Apple provides pretty easy ways to do this.

GLFW 3 does seem to provide some docs on the topic:

http://www.glfw.org/docs/latest/group__window.html#ga5c336fddf2cbb5b92f65f10fb6043344

They aren't super clear, but I hope the share parameter shares the context between the newly created window. Just close without destroying the previous window.

I didn't get a '''System.AccessViolationException''' when running the linked code that closes and reopens a window. I just got a black screen and gl errors like "InvalidFramebufferOperationExt", which makes sense, since the entire gl context was no longer being written to. However, I'm running this project on GLFW 2, which has fewer options.

andykorth commented 10 years ago

It looks like support for window mode switching is on the GLFW roadmap for v 3.2 or "wayland". https://github.com/glfw/glfw/issues/43

andykorth commented 10 years ago

I spoke with some other devs, and they expect simply creating a new window and sharing the context with your old closed (but not destroyed) window will solve your problem.

delaneyj commented 10 years ago

I have been using glfw3, this a non-blocking issue but since it was a non-issue in sfml & opentk I thought it should be brought to your attention (knew it was not a Pencil.Gaming specific problem but maybe you had a clever helper class to get around it). Its great that its being resolved properly in glfw3 and I'll wait for the proper fix. You can close or keep open on hold whichever make the most sense to the project.

delaneyj commented 10 years ago

I was actually already trying to share the context and close the window (though I might have gotten it wrong).

    public void CreateWindow()
        {
            var monitor = isFullscreen ? Glfw.GetPrimaryMonitor() : GlfwMonitorPtr.Null;
            var currentWindow = Glfw.CreateWindow(Width, Height, Title, monitor, window);

            Glfw.SetKeyCallback(currentWindow, new GlfwKeyFun((w, key, scancode, action, modifiers) =>
            {
                var info = new PencilKeyInfo(key, scancode, action, modifiers);
                onKeyboard.Fire(info);
            }));

            Glfw.SetWindowCloseCallback(currentWindow, new GlfwWindowCloseFun(w =>
            {
                Exit();
            }));

            Glfw.SetWindowSizeCallback(currentWindow, new GlfwWindowSizeFun((w, width, height) =>
            {
                this.width = width;
                this.height = height;
                onWindowResized.Fire(this);
            }));

            Glfw.SwapInterval(shouldVsync ? 1 : 0);
            Glfw.MakeContextCurrent(currentWindow);
            if(!firstTime) Glfw.SetWindowShouldClose(window, true);

            window = currentWindow;
            firstTime = false;
        }

However it would get the access violations on the first call to GL.DrawElements.

antonijn commented 7 years ago

Might be fixed with a fix of #40 ?