Core-profile OpenGL context with compatibility-era GLSL shaders: which mixes are actually portable?
0 reputation · 29 Apr 2020, 06:58 UTC
0 reputation · 29 Apr 2020, 06:58 UTC
Our rendering layer loads shaders authored at different times, some declaring #version 330 core and others written against older GLSL that relies on legacy built-ins and compatibility-profile state. We now create the context explicitly with a version and profile mask, but we are unsure how strict we must be at the boundary between the context profile and the shader #version directives.
The constraints: we must run on at least one Mesa stack, one proprietary Windows/Linux driver, and possibly macOS, where modern OpenGL is effectively core-profile only and deprecated. We also know context creation may silently return a different version or profile than requested, and that extension availability must be queried per context rather than assumed from the advertised OpenGL version.
Assume OpenGL 3.3+ as the baseline; exact driver versions are still being verified.
Specifically:
#version guaranteed to fail compilation, or is acceptance driver-dependent?35275 reputation · 29 Apr 2020, 16:33 UTC
None of the mixes you describe are portable. A core-profile context is not guaranteed to reject a shader declaring an older non-core #version — acceptance is driver-dependent — so "it compiled on our test machine" tells you almost nothing. The only portable configuration for your constraints (Mesa, a proprietary Windows/Linux driver, and macOS) is: core-profile context everywhere, all shaders at #version 330 core (or 150 core if you must support older macOS-era code), a real VAO always bound, and zero fixed-function calls. Everything else is luck on a lenient driver.
#version guaranteed to fail in a core context?No. The specification ties shader language validity to the context profile, but enforcement varies widely:
gl_Vertex, gl_ModelViewMatrix, and gl_FragColor fail to compile.Also note that a #version directive without the core keyword defaults to compatibility semantics for versions that support profiles — omitting the keyword is not a request for core. So a green build on an NVIDIA dev box proves nothing; treat any successful legacy compile as non-portable luck, not a contract.
Three, in rough order of how often they bite:
glMatrixMode, glBegin/glEnd, glLight*, texture environment, and client-side vertex arrays are removed in core and generate GL_INVALID_OPERATION/GL_INVALID_ENUM. Any shared code touching these breaks only under core.GLFW_SRGB_CAPABLE, WGL/GLX attributes), not the profile. Code assuming a linear default framebuffer produces washed-out output when the window system hands you an sRGB one, and this varies by platform. Verify by rendering a known mid-gray gradient on each target.Necessary, not sufficient. Querying GL_CONTEXT_PROFILE_MASK and GL_CONTEXT_FLAGS (forward-compatible bit) immediately after creation tells you what you actually got — drivers may return a different version or profile than requested — but it says nothing about how lenient that driver's shader compiler is. A core context on NVIDIA still compiles shaders Mesa and macOS reject.
So you need a small per-driver validation pass, but it can be cheap:
GL_VERSION, GL_CONTEXT_PROFILE_MASK, GL_CONTEXT_FLAGS, and GL_SHADING_LANGUAGE_VERSION on every target stack at startup.gl_FragColor, no core keyword) under the core context on each driver to map which stacks reject it; treat the strictest result as your baseline.glDebugMessageCallback via GL_KHR_debug or core 4.3+) in development builds to catch missing VAO binds and removed-state usage at runtime.glGetStringi/GL_NUM_EXTENSIONS — never glGetString(GL_EXTENSIONS) in core, and never infer extensions from the advertised version.Standardize on #version 330 core for every shader, always bind a VAO, strip fixed-function calls, and gate optional features behind runtime extension queries. That gives you one draw path that behaves identically on Mesa, proprietary drivers, and macOS. One caveat worth flagging now: macOS OpenGL is deprecated and frozen at 4.1 core, so if macOS is a long-term hard requirement, plan for a Metal/ANGLE/MoltenVK backend rather than expanding your GL investment there.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.