Skip to content

New platform: GLFW3! #172

Open
johnmarianhoffman wants to merge 7 commits intoOneLoneCoder:masterfrom
johnmarianhoffman:glfw_conversion
Open

New platform: GLFW3! #172
johnmarianhoffman wants to merge 7 commits intoOneLoneCoder:masterfrom
johnmarianhoffman:glfw_conversion

Conversation

@johnmarianhoffman
Copy link
Copy Markdown

@johnmarianhoffman johnmarianhoffman commented Sep 20, 2020

GLFW OLC PGE Port Notes

Why GLFW?

GLFW is a modern, well-maintained, and simple cross-platform windowing and input system. It could theoretically replace all of the platform-specific windowing code in OLC (although I am not proposing this).

I've made this port because I was running into issues with the GLUT implementation on MacOS and it's handling/integration with the PGE ImGUI integration (https://github.com/dandistine/olcPGEDearImGui which is WONDERFUL by the way). This ended up being a platform-level problem, which also appears in the GLUT examples from ImGUI; the problem appears to be GLUT on MacOS. Although the GLUT implementation on MacOS is maintained, I think that it's a little antiquated in its constructs and design choices compared to GLFW, and thus provided GLFW as a compile option to those wishing to use it (or running into bugs with GLUT) would be a worthwhile addition to the PGE without adding too much complexity.

GLFW implementations could also be made available for Linux and Windows, although at present, that seems unnecessary and would require a fair bit of modification to existing code design.

Finally, GLFW performs better on MacOS. With GLFW3, I am achieving framerates on my Macbook Pro of ~700fps for the olcExampleProgram.cpp. Using GLUT, I only achieve frame rates of 550-600fps.

Why maybe NOT GLFW?

The beauty of OLC PGE is its simplicity, and that it uses platform-specific packages the come preinstalled on the platforms being targeted. PGE has made it so you don't need to be super familiar with the C++ build chain to get graphics in C++, which truly has not existed to date.

GLFW (sort of) violates this design principle, since a user must install GLFW separately and link it into the project. I don't see this as a major hurdle, since linking is still platform specific with the current PGE, however since there is an extra download or build step, it's not quite as simple.

I hope that GLFW will one day become a core platform library, however it is not currently and thus adds slight complexity to the build chain should a user wish to use it.

Scope

  • I have added a new Platform_GLFW that is available to mac users who #define __GLFW__ somewhere in their project (main.cpp is probably best).
  • Minimal other changes as needed to integrate the new platform into the existing structures.

Possible future work

  • Expand availability to Linux and Windows (i.e. offer GLFW as a selectable alternative to the native platforms). I don't want to risk overcomplicating PGE though if this were considered unnecessary.

Quirks (perhaps look like weird design choices)

GLFW + MacOS are pretty stubborn about threading, PGE uses threading

As a result, we have to do most of our GLFW stuff in the main thread and not as part of the engine loop (where it feels more natural). Knock-on effects of this are:

  • All system event polling MUST be done in the StartSystemEventLoop method of the platform, which is called from the main thread. This means event polling is running asynchronously from frame updates. I've added a 1ms delay so that this thread doesn't just spin the CPU completely unecessarily. This can easily be removed if you need faster polling.

  • Unfortunately setting the window title on mac falls under the "things that must be done on the main thread," so I've had to implement a workaround setting an internal state of the platform class, which is then only pushed to the window as part of the main event loop. It feels a little crazy, but without it this way, the app crashes on Mac.

Currently limited to MacOS

Because, at present, there does not seem to be a need for Linux or Windows to support GLFW3, I haven't added the options. I would be happy to extend this work though if desired by the community.

GLFW 3.3.2 is required (updated/added 9/21)

It appears that 3.3.2 is a hard requirement for support on retina displays. I'm guessing that the retina window hint was added in this version (this should be ignored by non-Mac, non-retina systems). Thanks to @MumflrFumperdink and @ Zij-IT for the help in finding this.

Compiling olcExampleProgram on MacOS

(1) Uncomment the "#define __GLFW__" in the olcExampleProgram (or add to the top if missing)

(2) Compile command:
clang++ -std=c++17 olcExampleProgram.cpp -lz -lpng -framework OpenGL -lglfw3 -framework Cocoa -framework IOKit -framework CoreFoundation -o olcExampleProgram

@MumflrFumperdink
Copy link
Copy Markdown

Hey! Nice job on the port!

I tested out the glfw port vs. the glut port on my machine. On the example program, the fps did double, but there is this bug where the image only takes up the bottom left of the window.
Screen Shot 2020-09-20 at 6 59 06 PM

I also tested out the cpu/gpu test javid made:
GLUT:
Screen Shot 2020-09-20 at 6 50 24 PM
GLFW:
Screen Shot 2020-09-20 at 6 55 28 PM
The numbers seem comparable.

Good luck!

@johnmarianhoffman
Copy link
Copy Markdown
Author

@MumflrFumperdink Interesting. Thanks for testing!

I ran into that bug where everything is rendered to the lower quadrant as well, however on my Macbook Pro 13" (macos 10.15.5) it disappeared with the addition of line 4092:

glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER,GLFW_FALSE);

Mind if I ask what hardware/OS you're using?

@MumflrFumperdink
Copy link
Copy Markdown

I'm using MacBook Air 13" (macOS 10.15.6)

@johnmarianhoffman
Copy link
Copy Markdown
Author

Couple more questions, if you don’t mind:

  1. Does your Mac have a Retina display?
  2. Did you install glfw from source or via brew/Macports? (I did it from source, which could be the issue, since I think Brew might still be on glfw 3.2)

At some point tonight I’ll upgrade to 10.5.6 and see if I incur the same issue. Thanks again for your input!

@Zij-IT
Copy link
Copy Markdown

Zij-IT commented Sep 21, 2020

Just to add more data to the pile:

Computer:

  • MacBook Pro 2017 - 13"
  • macOS Catalina 10.15.3
  • LCD Retina display

GLFW:

  • Installed via GLFW via source

Modifications:

  • I did have to reduce the size of the program from the usual to 256x196 as the example when downloaded was too large for my screen

Results:

  • Example took up the entire part of the screen as expected
  • FPS for the example program sitting at 570FPS +- 30

@MumflrFumperdink
Copy link
Copy Markdown

  1. It is Retina
  2. I installed it via brew - looks like it was my mistake! I upgraded glfw from 3.3 to 3.3.2 using brew and the window was normal.

@johnmarianhoffman
Copy link
Copy Markdown
Author

@MumflrFumperdink @Zij-IT Awesome. Thank you guys for the input. Seems like GLFW 3.3.2 is a hard requirement for this to work so I will update the main notes with that detail.

I also had to reduce the resolution on my machine to get the sample code to fit.

Super helpful!

@olc-slav
Copy link
Copy Markdown

Looks great, but I'd appreciate it if you made your back-end not exclusive to Macs. It should be pretty easy to make it available on other platforms and I could actually benefit from it on Linux.

@johnmarianhoffman
Copy link
Copy Markdown
Author

@olc-slav I'd actually love to make it not exclusive to Mac! I'm actually thinking about doing exactly that on a different branch and will PR when done for it to be reviewed (Mac was my immediate need).

I specifically chose to not make this specific contribution a dedicated, "first-class" platform because it would necessitate quite a few changes to the existing code in a way I didn't feel comfortable doing as a first contribution, and as someone new to the community. I think that choice needs to be made by @OneLoneCoder.

After pinging folks on discord and hearing a little bit of feedback here, it seems like there's a very real desire to offer a dedicated, cross-platform GLFW backend, which I'm more than happy to do. Although I can test all three platforms on my end, I'll definitely need some help and input from the community. :D

Copy link
Copy Markdown

@olc-slav olc-slav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed a couple issues. They're pretty small but it'd be good to deal with them.

Comment thread olcPixelGameEngine.h Outdated
Comment thread olcPixelGameEngine.h Outdated
@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 22, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

johnmarianhoffman commented Sep 22, 2020

@olc-slav Which platforms would you have available to test (and would you be interested in testing) if I tried to get a non-Apple-exclusive GLFW port going in the next few days?

I'm currently on vacation right now and all I have is my Mac laptop until Monday 9/28.

@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 22, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

@olc-slav I've created a standalone, fully cross-platform version of the GLFW platform that I've tested in an Ubuntu 20.04 VM and it seems to be working there.

It's building on Windows, but not running for some reason so I'm hesitant to create a legit pull request until I can actually ensure that the code is working. I think it has to do with my linking config in the Windows VM and not necessarily an actual code issue, but the VM is so slow that I just gave up today until I can actually test on real hardware.

Feel free to give it a try if you want and let me know if you run into any issues (linux or windows).

https://github.com/johnmarianhoffman/olcPixelGameEngine/tree/glfw_standalone_platform

@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 26, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

johnmarianhoffman commented Sep 26, 2020

@olc-slav Ah yes. Context switching. I am familiar (although certainly not expert). haha. In my initial bringup of the mac version I did a lot of reading about contexts and GLFW however didn't walk away feeling like I completely grasped it. I agree that the programming model for GLFW really wants you to do anything windowing or OpenGL related the main thread, and the cleanest thing here would be to do away with threading model used by PGE. That being said, I don't think that's especially realistic and would be more suitable for a hard fork.

The cleanest solution to fit GLFW into the existing PGE design pattern would be to migrate all GLFW code to the EngineThread (i.e. ThreadStartUp/ThreadCleanUp/etc.) however my concern is that this will cause the Mac version to fail since:

"Cocoa has an event queue per thread that can only be accessed from that thread, but the main thread event queue is the one that receives window and input events, and most window and view operations may only be performed on the main thread." (https://discourse.glfw.org/t/multithreading-glfw/573/5).

Although I can't confirm that relocating EVERYTHING to the Engine thread won't fix the problem, my general experience is that when they say "main thread" they mean the program's main thread, and no amount of context switching can save you on a mac (edit: no amount can save you when it comes to specific windowing calls. Rendering seems to be OK.)

Now that I understand PGE a bit better, I will try for a "correct" solution (i.e. everything windowing and GL-related on the EngineThread) as well as a "functional" solution that uses threading but with context switching. I think the latter is more likely to ever make it out of experimentation, and also the latter is currently working without errors on Mac and my Linux VM. I think it's very possible that GLFW may just not perfectly fit into the current design of PGE.

You mentioned some "errors on the GLFW side." I have not encountered any on Mac or Linux. Can you pass those along as you encounter them?

@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 26, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

johnmarianhoffman commented Sep 26, 2020

@olc-slav Seems to me that anything wrapped in a

glfwMakeContextCurrent(olc_Window);
...
glfwMakeContextCurrent(nullptr);

should be mutexed. Otherwise the separate threads could attempt to steal the context before the other has relinquished it. I can't gather from the docs whether or not they'll respect one another. Thoughts?

@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 26, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

@olc-slav It actually occurs to me that we didn't even need to pull the context for the CreateWindowPane; we can cede all control of the context to the engine thread, and no other calls that we use require the context. I've removed it and tested it and seems to run fine on linux and mac. Let me know if you run into issues.

P.S. Have you been testing/able to test on Wayland?

@olc-slav
Copy link
Copy Markdown

olc-slav commented Sep 26, 2020 via email

@johnmarianhoffman
Copy link
Copy Markdown
Author

@olc-slav Just pushed a fix so it should be resolved. X11 was include-order sensitive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants