rust-windowing/glutin

Unable to create a OpenGL 2.1 context on macOS

Closed this issue · 2 comments

Hello! I had an application which was previously using some SDL2 Rust bindings and was later rewritten to use winit + glutin, which happens to use a legacy OpenGL 2.1 context on macOS. The code that creates the context looks roughly like this:

let gl_display = gl_config.display();

let context_attributes = ContextAttributesBuilder::new()
    .with_context_api(ContextApi::OpenGl(Some(Version::new(
        self.gl_version_major,
        self.gl_version_minor,
    ))))
    .with_profile(GlProfile::Compatibility) // <--- I'm requesting a compatibility context
    .build(raw_window_handle);

let gl_context = unsafe {
    gl_display
        .create_context(&gl_config, &context_attributes)
        .expect("failed to create context")
};

However, I end up with an OpenGL 4.1 core context, with all legacy OpenGL features disabled.

I had a look through the cgl module and found this piece of code, which seems to indicate that we will always try to create an OpenGL context with the latest version of OpenGL regardless of the profile specified in the ContextAttributesBuilder:

// Automatically pick the latest profile.
let raw = [
NSOpenGLProfileVersion4_1Core,
NSOpenGLProfileVersion3_2Core,
NSOpenGLProfileVersionLegacy,
]
.into_iter()
.find_map(|profile| {
attrs[profile_attr_pos] = profile;
// initWithAttributes returns None if the attributes were invalid
unsafe { NSOpenGLPixelFormat::newWithAttributes(&attrs) }
})
.ok_or(ErrorKind::BadConfig)?;

If I change that array locally so that NSOpenGLProfileVersionLegacy is the first element, then the NSOpenGLPixelFormat object gets created with the legacy OpenGL context correctly as expected, and my application works properly.

It seems that we don't have the ContextAttributes object yet when calling Display::find_configs. SDL2's behaviour is to use NSOpenGLProfileVersionLegacy by default unless a core profile is specified, then favour NSOpenGLProfileVersion3_2Core.

I'm not very familiar with glutin's internals, so not sure what the cleanest approach would be here, but I had some potential ideas:

  • Maybe we could fix this by creating two NSOpenGLPixelFormat objects and storing both in cgl's ConfigInner type, one for the "compatibility" profile with NSOpenGLProfileVersionLegacy, and one for the "core" profile using either NSOpenGLProfileVersion4_1Core and NSOpenGLProfileVersion3_2Core (similar to the existing logic)?
  • Maybe a cleaner option would be to defer the creation of the NSOpenGLPixelFormat by instead storing the Vec<NSOpenGLPixelFormatAttribute> directly in cgl's ConfigInner type, then setting NSOpenGLPFAOpenGLProfile correctly and create the NSOpenGLPixelFormat object later when we have access to the ContextAttributes object: https://github.com/rust-windowing/glutin/blob/master/glutin/src/api/cgl/context.rs#L49

Thanks for your time! I'm happy to contribute a PR if any of the above approaches sound reasonable.

I'd say that it was intentionally to not support anything other than latest OpenGL on macOS, because OpenGL 2.1 is really bugged, as in not much really work in it and 4.1 yields better results.

Maybe we could fix this by creating two NSOpenGLPixelFormat objects and storing both in cgl's ConfigInner type, one for the "compatibility" profile with NSOpenGLProfileVersionLegacy, and one for the "core" profile using either NSOpenGLProfileVersion4_1Core and NSOpenGLProfileVersion3_2Core (similar to the existing logic)?

This could work more or less fine. Should profile how fast it all is, but we don't have much options here.

Maybe a cleaner option would be to defer the creation of the NSOpenGLPixelFormat by instead storing the Vec directly in cgl's ConfigInner type, then setting NSOpenGLPFAOpenGLProfile correctly and create the NSOpenGLPixelFormat object later when we have access to the ContextAttributes object: https://github.com/rust-windowing/glutin/blob/master/glutin/src/api/cgl/context.rs#L49

This is not really an option, because it'll mess with the config picking semantics, since the user will think that the pixel format works, but in reality, it's not working.

But all that aside, do we really need legacy profile on macOS given that it's really buggy? Or is it ok-ish buggy, since last time I've tried it, it was failing with really simple ES 2.0 alacritty renderer?

I'd say that it was intentionally to not support anything other than latest OpenGL on macOS, because OpenGL 2.1 is really bugged, as in not much really work in it and 4.1 yields better results.

Fair enough. The only reason we were using OpenGL 2.1 was because it was an old codebase ported from C, but I've just wrapped up a project to finish moving it to OpenGL 4.1 and that's now working great with upstream glutin. I agree that in this case it seems like it would add unneeded complexity to the CGL backend for not much gain at all, so I'll close this.