Skip to content

Backends: Opengl3: Support GLSL 410 shader when GLSL version is auto-detected.#9427

Open
perminovVS wants to merge 1 commit into
ocornut:masterfrom
perminovVS:fix-opengl3-correct-use-shader-glsl-410
Open

Backends: Opengl3: Support GLSL 410 shader when GLSL version is auto-detected.#9427
perminovVS wants to merge 1 commit into
ocornut:masterfrom
perminovVS:fix-opengl3-correct-use-shader-glsl-410

Conversation

@perminovVS

Copy link
Copy Markdown
Contributor

Add the GLSL 410 shader and ensure it is selected when the GLSL version is auto-detected (i.e. when glsl_version is nullptr). Previously the GLSL 410 shader was only used if a GLSL version string was passed manually to ImGui_ImplOpenGL3_Init. Now the backend detects the GL/GLSL version at runtime and will pick the GLSL 410 shader when the context supports it.

fc737d2

…detected.

Add the GLSL 410 shader and ensure it is selected when the GLSL version is auto-detected (i.e. when glsl_version is nullptr).
Previously the GLSL 410 shader was only used if a GLSL version string was passed manually to ImGui_ImplOpenGL3_Init. Now the backend detects the GL/GLSL version at runtime and will pick the GLSL 410 shader when the context supports it.

ocornut@fc737d2
@perminovVS

Copy link
Copy Markdown
Contributor Author

Fixes #6577
#6577

ocornut pushed a commit that referenced this pull request Jun 3, 2026
…text is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577)

Amend fc737d2
@ocornut

ocornut commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Thank you very much Vladimir.
This was merged as 7950c96.

Can you suggest how to amend your examples/xxxx_opengl3/main.cpp file?

As current code is the example does:

#elif defined(__APPLE__)
    // GL 3.2 + GLSL 150
    const char* glsl_version = "#version 150";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // Required on Mac
#else
    // GL 3.0 + GLSL 130
    const char* glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only
#endif

Therefore your code path won't run.

Can you report the detected GlVersion

  • with this example code, under macOS
  • with this example code compiled for Windows, under macOS
  • with your code (specify init details), under macOS
  • with your code (specify init details) compiled for Windows, under macOS

Thank you.

@perminovVS

Copy link
Copy Markdown
Contributor Author

Thank you very much Vladimir. This was merged as 7950c96.

Can you suggest how to amend your examples/xxxx_opengl3/main.cpp file?

As current code is the example does:

#elif defined(__APPLE__)
    // GL 3.2 + GLSL 150
    const char* glsl_version = "#version 150";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // Required on Mac
#else
    // GL 3.0 + GLSL 130
    const char* glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only
#endif

Therefore your code path won't run.

Can you report the detected GlVersion

  • with this example code, under macOS
  • with this example code compiled for Windows, under macOS
  • with your code (specify init details), under macOS
  • with your code (specify init details) compiled for Windows, under macOS

Thank you.

Thank you — glad to see the change merged (7950c96).

A bit of context about my environment and how I initialize GL in production:

  • I use cocos2d-x as a cross platform layer. ImGui/OpenGL is embedded inside that engine layer, so I sometimes need to request the highest available desktop GL context (rather than the conservative example defaults) — especially when running under translation layers (Wine/ANGLE) or on Apple hardware where the maximum supported desktop GL is 4.1.
  • On modern macOS Apple’s OpenGL implementation is stuck at OpenGL 4.1 (wrapper over Metal). See: https://stackoverflow.com/questions/65802625/develop-using-opengl-4-x-on-osx-big-sur

What I do in production (relevant snippet)

// For cocos2d-x: GLViewImpl::initWithRect used to create the highest available GL context on macOS/Wine

if (IsRunWine())
{
    // Minimum target is OpenGL 4.1
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    Configuration::getInstance()->setCoreProfile(true);
}

_mainWindow = glfwCreateWindow(neededWidth, neededHeight, _viewName.c_str(), _monitor, nullptr);

if (_mainWindow == nullptr && IsRunWine())
{
    Configuration::getInstance()->setCoreProfile(false);

    // Create default fallback
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
    _mainWindow = glfwCreateWindow(neededWidth, neededHeight, _viewName.c_str(), _monitor, nullptr);
}

Why this: on macOS (Intel or Apple Silicon) the system GL implementation exposes up to GL 4.1. When running under Wine I try to request the highest desktop profile available (4.1 core) so the runtime and drivers give me the best feature set possible. If that fails I fall back to a very conservative context for auto select max in driver.

As far as I recall, I experienced initialization issues on Apple Silicon, so I explicitly request an OpenGL 4.1 core context; if that fails, I fall back to the default (more conservative) context.

@perminovVS

Copy link
Copy Markdown
Contributor Author

I tested my app by requesting a GL 3.0 context (the branch shown in the example). The problem remained and several of my 3D shaders would not compile under that context, which indicates the runtime/driver on macOS (under Wine on macOS) does not provide the features I need when only GL 3.0 is requested. For that reason GLViewImpl::initWithRect first requests an OpenGL 4.1 core context (the maximum desktop GL Apple exposes); the driver/runtime ultimately decides the exact version returned. If creating a 4.1 context fails, the code falls back to a conservative default context.

@ocornut

ocornut commented Jun 3, 2026

Copy link
Copy Markdown
Owner

If your app explicitly try to request varying GL context version, then surely you can select a GLSL version manually too?

So to clarify, this fix doesn't strictly fix #6577 because the example have explicit GL version.
Can you test our vanilla examples and suggest how to get them working in a maximum of scenario?
When requesting a 3.0 request how can the example be made to work?

@perminovVS

perminovVS commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

If, for work need set glsl_version = nullptr

I build example_glfw_opengl3

no change:
const char* glsl_version = "#version 130";
image

set nullptr:
const char* glsl_version = nullptr;

image

Now need remove const char* glsl_version

    // Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
    // GL ES 2.0 + GLSL 100 (WebGL 1.0)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(IMGUI_IMPL_OPENGL_ES3)
    // GL ES 3.0 + GLSL 300 es (WebGL 2.0)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
    // GL 3.2 + GLSL 150
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // Required on Mac
#else
    // GL 3.0 + GLSL 130
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only
#endif

// And call as nullptr or empty

ImGui_ImplOpenGL3_Init(nullptr);  // set glsl_version auto

@perminovVS

Copy link
Copy Markdown
Contributor Author

For real PC Windows 11

no change:
const char* glsl_version = "#version 130";
image

set nullptr:
const char* glsl_version = nullptr;
image

@perminovVS

perminovVS commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

What I tested
I ran example_win32_opengl3 under Wine on macOS using the example’s default Win32 WGL path.

Observed behavior

  • The example calls ImGui_ImplOpenGL3_Init(nullptr) (auto-detect GLSL).
  • The example’s Win32 path uses wglCreateContext and that produced a GL context below 3.0 under Wine/macOS.
  • Because the created context is < 3.0, the backend did not worked.
image

Please consider one of the following changes to the example:

  • Attempt to create a modern context: create a temporary legacy context, query GL version, then try to recreate the context with wglCreateContextAttribsARB (3.0+ core) and fall back to the legacy context if that fails. This allows ImGui_ImplOpenGL3_Init(nullptr) auto-detection to work in more environments (including Wine on macOS).
  • Document the limitation: add a short note in the example explaining that wglCreateContext may return a legacy context under Wine/macOS and that users who need modern GLSL should request a 3.0+ core context explicitly.

Additionally, I tested modifying the example to create a modern context (create a temporary legacy context, load wglCreateContextAttribsARB, then request a 3.0+ core context with a fallback to the legacy context). That change resolves the issue I observed (which is unrelated to this PR); if you’d like, I can submit a separate PR implementing this fix.

bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data)
{
    HDC hDc = ::GetDC(hWnd);
    PIXELFORMATDESCRIPTOR pfd = { 0 };
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;

    const int pf = ::ChoosePixelFormat(hDc, &pfd);
    if (pf == 0)
        return false;
    if (::SetPixelFormat(hDc, pf, &pfd) == FALSE)
        return false;
    ::ReleaseDC(hWnd, hDc);

    data->hDC = ::GetDC(hWnd);
    if (!g_hRC)
    {
        HGLRC tempRC = wglCreateContext(data->hDC);
        if (!tempRC) { ::ReleaseDC(hWnd, data->hDC); return false; }
        if (!wglMakeCurrent(data->hDC, tempRC))
        {
            wglDeleteContext(tempRC);
            ::ReleaseDC(hWnd, data->hDC);
            return false;
        }

        // get version context

        GLint major = 0;
        GLint minor = 0;
        glGetIntegerv(0x821B, &major); // GL_MAJOR_VERSION
        glGetIntegerv(0x821C, &minor); // GL_MINOR_VERSION
        const char* gl_version_str = (const char*)glGetString(GL_VERSION);
        if (major == 0 && minor == 0)
            sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
        GLuint GlVersion = (GLuint)(major * 100 + minor * 10);

        if (GlVersion < 300)
        {
            typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
            PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
                (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");

            HGLRC newRC = nullptr;
            if (wglCreateContextAttribsARB)
            {
                // GL 3.0
                int attribs[] = {
                    0x2091, 3, // WGL_CONTEXT_MAJOR_VERSION_ARB
                    0x2092, 0, // WGL_CONTEXT_MINOR_VERSION_ARB
                    0x9126, 0x00000001, // WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB
                    0
                };
                newRC = wglCreateContextAttribsARB(data->hDC, 0, attribs);
            }

            if (newRC)
            {
                wglMakeCurrent(nullptr, nullptr);
                wglDeleteContext(tempRC);
                g_hRC = newRC;
                wglMakeCurrent(data->hDC, g_hRC);
            }
            else
            {
                // Could not create a 3.0+ context: keep the temporary OpenGL 2.x compatibility context as fallback.
                g_hRC = tempRC;
            }
        }
        else
        {
            // Keep temporary context: already OpenGL 3.0+.
            g_hRC = tempRC;
        }
    }
    return true;
}
image

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.

2 participants