Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL2 SDL_Renderer + OpenGL context issues with example code #1116

Open
maluramichael opened this issue Apr 26, 2017 · 33 comments

Comments

Projects
None yet
8 participants
@maluramichael
Copy link

commented Apr 26, 2017

Environment: sdl2, sdlgfx, glew 2.0.0, OpenGL 4.1 INTEL-10.14.73, GLSL 4.10

I almost integrated imgui in my project but got one little problem. I use the 2 source file out of the examples/sdl_opengl2_example directory As long as i only use imgui methods everything works fine.

mosaic capture 2017-04-26 at 16 45 40

Without imgui my project works too.

mosaic capture 2017-04-26 at 16 48 43

When i call SDL_RenderCopyEx or something else from sdl_gfx to draw rectangles my ui looks like this.

mosaic capture 2017-04-26 at 16 45 26

The code for my rendering looks like this

 // the painter just wraps the sdl functions
void render() override {
    painter->clear(100, 100, 100, 255);  // SDL_RenderClear(renderer);
//        player->render(*painter); // SDL_RenderCopyEx(this->renderer, texture...);
    renderUI();
}

void renderUI() {
    ImGui_ImplSdl_NewFrame(window);

    ImGui::Begin("My window");
    ImGui::Text("Hello, world!");
    ImGui::Text("Hello, world!");

    static float f = 0.0f;
    ImGui::Text("Hello, world!");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);

    ImGui::End();
    ImGui::Render();
}
@ocornut

This comment has been minimized.

Copy link
Owner

commented Apr 26, 2017

Perhaps something about current active, aka glActiveTexture(). Will investigate. Try calling glActiveTexture(GL_TEXTURE0);

Maybe related to this PR:
#1087
(which was an incorrect fix, but linking for reference)

ocornut added a commit that referenced this issue Apr 26, 2017

@ocornut

This comment has been minimized.

Copy link
Owner

commented Apr 26, 2017

Hello @maluramichael,
Please use the sdl_opengl3_example code as a base. Mixing GL2 style code with newer GL3 isn't well supported by all drivers. You may also want to get the version with the latest fix I have just made.

@maluramichael

This comment has been minimized.

Copy link
Author

commented Apr 26, 2017

Ill try this later and report back.

ocornut added a commit that referenced this issue Apr 26, 2017

@maluramichael

This comment has been minimized.

Copy link
Author

commented Apr 26, 2017

Ok now i know how to recreate this error. I used the latest examples/sdl_opengl3_example code. Imgui works as long as i leave the example as it is. But when i create a SDL_Renderer it does not work anymore and i really need the renderer.

int main(int, char**) {
    // .......
    SDL_Window* window = SDL_CreateWindow("ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                          1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    SDL_GLContext glcontext = SDL_GL_CreateContext(window);
    gl3wInit();

    // This line breaks the ui
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (renderer == 0) {
        SDL_Quit();
    }

    // Setup ImGui binding
    ImGui_ImplSdlGL3_Init(window);
    // .......

``
@ocornut

This comment has been minimized.

Copy link
Owner

commented Apr 26, 2017

Check those references:
https://github.com/ocornut/imgui/search?q=SDL_Renderer&type=Issues&utf8=%E2%9C%93

I am sure there might be a fix but not using SDL myself I can't tell. Maybe I'll try to repro with your code later if I have time.

@maluramichael

This comment has been minimized.

Copy link
Author

commented Apr 27, 2017

There is something wrong with the SDL_Renderer. In your sdl2_opengl3 the following line,

printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION));

prints OpenGL 4.1 INTEL-10.14.73, GLSL 4.10 and everything works.

When i create the renderer with

SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

the line above prints OpenGL 2.1 INTEL-10.14.73, GLSL 1.20 and no ui is rendered.

@maluramichael

This comment has been minimized.

Copy link
Author

commented Apr 27, 2017

Ok this is crazy. Your example works in this case when i split the SetAttribute calls. It has something to do with this link: http://stackoverflow.com/a/23858884/1407823

int main(int, char**)
{
    // Setup SDL
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0)
    {
        printf("Error: %s\n", SDL_GetError());
        return -1;
    }

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

    // Setup window
    SDL_Window *window = SDL_CreateWindow("ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    SDL_DisplayMode current;
    SDL_GetCurrentDisplayMode(0, &current);

    SDL_GLContext glcontext = SDL_GL_CreateContext(window);
    
    gl3wInit();

    printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), 
    glGetString(GL_SHADING_LANGUAGE_VERSION));
@ocornut

This comment has been minimized.

Copy link
Owner

commented May 1, 2017

Adding reference to #935

@ocornut

This comment has been minimized.

Copy link
Owner

commented May 1, 2017

I am looking at those three issues, #1116, #935, #1110, they seem all related and incredibly confusing for someone not running Linux/OSX (I cannot repro issues on Windows) and not using SDL_Renderer.
Closing the 2 other issues and merging it. Please also refer to them they contains useful information.

@ebachard @maluramichael @slidingboar @kuhaut

There is an issue related to OpenGL context versions, the imgui example renderer codes and SDL_Renderer.

This is the OpenGL SDL_Renderer code in SDL:
http://hg.libsdl.org/SDL/file/d49da5f38a14/src/render/opengl/SDL_render_gl.c

And basically it does this:

#define RENDERER_CONTEXT_MAJOR 2
#define RENDERER_CONTEXT_MINOR 1

    SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
    SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
    
    window_flags = SDL_GetWindowFlags(window);
    if (!(window_flags & SDL_WINDOW_OPENGL) ||
        profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {

        changed_window = SDL_TRUE;
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR);

        if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
            goto error;
        }
    }

So basically SDL_Renderer enforces a 2.1 context and recreate if needed.
I don't know why it does that, it looks like a limitation of SDL_Renderer.

So the old style OpenGL code in sdl_opengl2_example works better with it.

According to Michael latest post (just above, #1116 (comment)) he is being successful resetting the render context version AFTER creating the SDL_Renderer. This is rather dubious but it may work for you.

It would be nice if you Linux/OSX users could experiment further with small repro being posted, while providing exact OS type + SDL version. So we can decide what to do on with sdl_opengl2_example/ and sdl_opengl3_example. If we should add comments to them etc.

@ocornut

This comment has been minimized.

Copy link
Owner

commented May 1, 2017

As SDL_Renderer tries to be its own platform (wrapping OpenGL, DirectX, etc.) it would also make sense to render imgui only with SDL_Renderer calls, but it doesn't seem to provide many useful calls. At least it doesn't seem possible to render textures triangles with it. Looking from the outside, I don't really understand what SDL_Renderer is for or is trying to provide, it seems like a very poor/outdated library for modern 3D era.

@ocornut ocornut changed the title SDL2 Render methods destroy ui SDL2 SDL_Renderer OpenGL context issues with example code May 1, 2017

@paulsapps

This comment has been minimized.

Copy link

commented May 1, 2017

I think I've said this before in other issues, but yeah @ocornut you are exactly right. Mixing SDL render and GL/DX anything else goes wrong. I've attempted this in the past and the upshot is that it is not supported. Change everything to GL.

@ocornut

This comment has been minimized.

Copy link
Owner

commented May 1, 2017

@paulsapps This is not what I'm saying and this is not what is written above!! What's written is that SDL_Renderer enforces an OpenGL 2.1 context. We have to be more cautious with our wording and assumptions to not make this issue more confusing that it is. There are various possible actions to take, maybe the workaround of changing context version after creating the SDL_Renderer works perfectly well. Maybe we can add more examples to direct users of SDL_Renderer to the old-GL style example etc.

@paulsapps

This comment has been minimized.

Copy link

commented May 1, 2017

Thing is though it might not even be OpenGL, it can be any of these:

https://wiki.libsdl.org/SDL_HINT_RENDER_DRIVER

direct3d
opengl
opengles2
opengles
software

Which is why its just a bad idea in general.

@ocornut ocornut changed the title SDL2 SDL_Renderer OpenGL context issues with example code SDL2 SDL_Renderer + OpenGL context issues with example code May 1, 2017

@ocornut

This comment has been minimized.

Copy link
Owner

commented May 1, 2017

It's a bit clunky, but it's a not a bad idea if you are targeting OpenGL, it's similar to just writing an GL application. That said, with the small number of features SDL_Renderer supports I don't quite understand why people would want to use that at all instead of OpenGL.
( If SDL_Renderer is in active development, may I suggest its users to push toward it getting enough features implemented so that SDL_Renderer API can render imgui )

@maluramichael

This comment has been minimized.

Copy link
Author

commented May 1, 2017

The thing with the renderer is that you can easily render stuff like textures and primitives (sdl_gfx) without wrapping shader and vertex buffer.

@Svenny

This comment has been minimized.

Copy link

commented Jul 20, 2017

This is probably caused by SDL's shaders not being unbound after rendering. Try calling glUseProgramObjectARB (0) before ImGui::Render(). That fixed the problem for me.

@ocornut

This comment has been minimized.

Copy link
Owner

commented Jul 20, 2017

@Svennny Are you using the SDL+GL2 or SDL+GL3 example?
AFAIK glUseProgramObjectARB is a super old function and got replaced by glUseProgram().
We already called glUseProgram in the GL3 example.

In the GL2 examples there is a comment in the render function that says:

//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context

May include this comment in the main.cpp file of the example as well.

@Svenny

This comment has been minimized.

Copy link

commented Jul 20, 2017

I am using SDL+GL2 example. Uncommenting the line with glUseProgram(0) works too. I use GLEW instead of gl3w, but I don't think that makes any difference.
This code based on GL2 example works properly:

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <stdio.h>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_sdl.h"

int main (int argc, char **argv)
{
    // Setup SDL
    if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0)
    {
        printf("Error: %s\n", SDL_GetError());
        return -1;
    }

    // Setup window
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    SDL_DisplayMode current;
    SDL_GetCurrentDisplayMode(0, &current);
    SDL_Window *window = SDL_CreateWindow("ImGui SDL2+OpenGL+SDL_Render example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);

    int oglIdx = -1;
    int nRD = SDL_GetNumRenderDrivers();
    for(int i=0; i<nRD; i++)
    {
        SDL_RendererInfo info;
        if(!SDL_GetRenderDriverInfo(i, &info))
        {
            if(!strcmp(info.name, "opengl"))
            {
                oglIdx = i;
            }
        }
    }
    SDL_Renderer * renderer = SDL_CreateRenderer(window, oglIdx, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 

    // Setup ImGui binding
    ImGui_ImplSdl_Init(window);

    glewExperimental = true;
    glewInit ();

    bool show_test_window = true;
    bool show_another_window = false;
    ImVec4 clear_color = ImColor(114, 144, 154);

    SDL_Surface *bitmapSurface = SDL_LoadBMP ("test.bmp");
    SDL_Texture *bitmapTex = SDL_CreateTextureFromSurface (renderer, bitmapSurface);
    SDL_FreeSurface (bitmapSurface);

    // Main loop
    bool done = false;
    while (!done)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            ImGui_ImplSdl_ProcessEvent(&event);
            if (event.type == SDL_QUIT)
                done = true;
        }

        ImGui_ImplSdl_NewFrame(window);

        // 1. Show a simple window
        // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
        {
            static float f = 0.0f;
            ImGui::Text("Hello, world!");
            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
            ImGui::ColorEdit3("clear color", (float*)&clear_color);
            if (ImGui::Button("Test Window")) show_test_window ^= 1;
            if (ImGui::Button("Another Window")) show_another_window ^= 1;
            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
        }

        // 2. Show another simple window, this time using an explicit Begin/End pair
        if (show_another_window)
        {
            ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver);
            ImGui::Begin("Another Window", &show_another_window);
            ImGui::Text("Hello");
            ImGui::End();
        }

        // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
        if (show_test_window)
        {
            ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver);
            ImGui::ShowTestWindow(&show_test_window);
        }
        
        // Rendering
        SDL_Rect vp;
        vp.x = vp.y = 0;
        vp.w = (int) ImGui::GetIO ().DisplaySize.x;
        vp.h = (int) ImGui::GetIO ().DisplaySize.y;
        SDL_RenderSetViewport (renderer, &vp);
        SDL_SetRenderDrawColor (renderer, clear_color.x * 255.0f, clear_color.y * 255.0f, clear_color.z * 255.0f, clear_color.w * 255.0f);
        SDL_RenderClear (renderer);

        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        SDL_Rect rct;
        rct.x = rct.y = 50 + (SDL_GetTicks () >> 9);
        rct.h = rct.w = 100;
        SDL_Rect rct2;
        rct2.x = rct2.y = 160;
        rct2.w = rct2.h = 256;
        SDL_RenderCopy (renderer, bitmapTex, 0, &rct2);
        SDL_RenderDrawLine(renderer, 0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y);
        SDL_RenderDrawRect (renderer, &rct);

        glUseProgram (0);
        ImGui::Render();
        
        SDL_RenderPresent(renderer);  
    }

    // Cleanup
    ImGui_ImplSdl_Shutdown();
    SDL_DestroyTexture(bitmapTex);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}
@ocornut

This comment has been minimized.

Copy link
Owner

commented Jul 20, 2017

@Svennny Ok so your problem is a different one that the one discussed above in the thread, and you probably should be using the GL3 code anyway (every comments and README suggests so, any reason you used this one?)

I think it would be incredibly useful that I copied the // gluseProgram(0); line with comment also in the main.cpp functions of the GL2 example. Will do that.

@Svenny

This comment has been minimized.

Copy link

commented Jul 20, 2017

I've changed to GL3 code and it still works fine.

ocornut added a commit that referenced this issue Jul 23, 2017

@paladin-t

This comment has been minimized.

Copy link

commented Feb 13, 2018

Environment: ImGui 1.53, SDL2, sdlgfx, gl3w, OpenGL 4.1, macOS 10.13, MacMini Late 2012 (Intel HD Graphics 4000)

Hey, guys, I met exactly the same issue. I really need a GL3 environment, unfortunately maluramichael's trick doesn't work for me.

I figured out that SDL sets the SDL_GLContext automatically when modifying some render states of an SDL_Renderer by calling GL_ActivateRenderer in SDL_render_gl.c. This makes it more difficult to tell when and which context you are working on. So my current solution is:

  1. Still create GL3 context for ImGui, which is the only accelerated context
  2. Create SDL_RENDERER_SOFTWARE renderer instead of SDL_RENDERER_ACCELERATED for other stuff

Until now this works fine for me, except:

  1. Need to write ((SDL_Surface*)sur)->format->Amask = 1; to tell SDL using alpha channel for palette indexed software surface
  2. Need to manually reset any clip area

It won't be a problem for my case, because I only use the renderer to generate low resolution surfaces when loading assets, (pixel style). I'd read the source over to find out if it's possible to use multiple accelerated contexts when I get time. SDL is poor at documenting on some of its dark corners, this is not the first time that I have to read its source for clues :/

@ebachard

This comment has been minimized.

Copy link

commented Feb 13, 2018

For the record, I solved #1110 (see the last comment). If ever the information is not enough, feel free to ask.

@zx64

This comment has been minimized.

Copy link

commented Jul 28, 2018

I ran into a related issue with making SDL2's SDL_Textures work nicely with ImGui.
Turns out SDL's abstraction is a little too rigid that you can't get the underlying GLuint (or LPDIRECT3DTEXTURE9) but SDL_GL_BindTexture does the right thing if you're willing to use/edit imgui_impl_opengl2.cpp:

-                    glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
+                    if (g_FontTexture == (GLuint)(intptr_t)pcmd->TextureId)
+                    {
+                        glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
+                    }
+                    else
+                    {
+                        SDL_GL_BindTexture((SDL_Texture*)pcmd->TextureId, nullptr, nullptr);
+                    }

This is obviously a hacky fix and would benefit from converting the font texture management to remove that if but I'd rather not spend time on that unless it was worth having an imgui_impl_sdlrenderer.

Frustratingly, SDL2's D3D9 backend could also implement SDL_GL_BindTexture with the equivalent forwarding onto d3dDevice->SetTexture but it doesn't.
Admittedly the API name would be misleading in a D3D context but it would allow a hypothetical impl_sdlrenderer to use either the GL2 or D3D9 ImGui backends depending on which driver was used.
(Ignoring the bigger problem of potentially encouraging continued use of either backends)

@ocornut

This comment has been minimized.

Copy link
Owner

commented Jul 28, 2018

This is tricky.

I don't think it is even possible to implement a imgui_impl_sdlrenderer without poking in either DX9/GL, SDL_Renderer doesn't seem to expose nearly enough functions. I may be wrong but every time I look at the SDL_Renderer I felt it was a very lacking API.. I'm not sure I understand to what purpose it can be used.

Would using SDL_Texture be typically tied to using SDL_Renderer or does it have uses even without SDL_Renderer? How and why you are using it?

The texture binding is the part that is more likely to need customization, so I was thinking perhaps we should make it a standard thing in renderer code that we can override the texture binding function?
And user would be responsible with overriding the font atlas TexId as well if the type they use doesn't match the default renderer type. This is just a rough idea, haven't come up with a fuller design for that yet.

@zx64

This comment has been minimized.

Copy link

commented Jul 28, 2018

An SDL_Texture is tied to a specific instance of SDL_Renderer, it's roughly a cross-backend abstraction for the underlying device texture managed by a specific SDL_Renderer.
Generally you create a new renderer for a given SDL_Window and SDL picks a suitable backend (but you can override with the SDL_Hint system).

These notes on updating from SDL1 to SDL2 might provide some better context: https://wiki.libsdl.org/MigrationGuide#If_your_game_just_wants_to_get_fully-rendered_frames_to_the_screen

In the code I've been using this hack, the usage looks something like ImGui::Image((ImTextureID)screenTexture, size); which is quite pleasant.

Here's a couple of examples of how SDL manages textures on the backends:
See how the GL backend unpacks the internal GLuint to emit the relevant bind call: https://hg.libsdl.org/SDL/file/5b6f649b6488/src/render/opengl/SDL_render_gl.c#l1630

Here's a like for like comparison of a texture operation implemented by both backends:
https://hg.libsdl.org/SDL/file/5b6f649b6488/src/render/direct3d/SDL_render_d3d.c#l1462
https://hg.libsdl.org/SDL/file/5b6f649b6488/src/render/opengl/SDL_render_gl.c#l1377

I would definitely agree that SDL's rendering API leaves a lot to be desired, I imagine most complex projects only use SDL for its input and window management and entirely do their own thing with GL3/4/D3D11 etc.

@ryancheung

This comment has been minimized.

Copy link

commented Oct 23, 2018

OS: Ubuntu 18.04
Example code: examples/sdl_opengl3_example
OpenGL loader: default gl3w

Damn it. After about 2 hours of trying, I finally got a workable code mix usage of sdl2 and img-ui with opengl3 exmaple code:

const char* Game::SetupImGui()
{
    // Decide GL+GLSL versions
#if __APPLE__
    // GL 3.2 Core + GLSL 150
    const char* glsl_version = "#version 150";
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
#else
    // GL 3.0 + GLSL 130
    const char* glsl_version = "#version 130";
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif

    // Create window with graphics context
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

    return glsl_version;
}

int Game::StartLoop()
{
    SDL_Window* window = SDL_CreateWindow("ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                          1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    ///---Start ImGUI---///

    const char* glsl_version = SetupImGui();

    SDL_DisplayMode current;
    SDL_GetCurrentDisplayMode(0, &current);
    SDL_GLContext gl_context = SDL_GL_CreateContext(window);
    SDL_GL_SetSwapInterval(1); // Enable vsync

    // Initialize OpenGL loader
    bool err = gl3wInit() != 0;

    if (err)
    {
        fprintf(stderr, "Failed to initialize OpenGL loader!\n");
        return 1;
    }

    // Setup Dear ImGui binding
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls

    ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Setup style
    ImGui::StyleColorsDark();

    bool show_demo_window = true;
    bool show_another_window = false;
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    ///---End ImGUI---///

    while (!Stopped)
    {
        // Process input
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT)
            {
                Stop();
                return 0;
            }

            if (!Stopped)
            {
                ///---Start ImGUI---///
                ImGui_ImplSDL2_ProcessEvent(&event);
                ///---End ImGUI---///
            }

            if (Stopped)
                return 0;
        }

        // Draw your graphics here using sdl render, must draw before ImGUI

        ///---Start ImGUI---///

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL2_NewFrame(window);
        ImGui::NewFrame();

        // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
        if (show_demo_window)
            ImGui::ShowDemoWindow(&show_demo_window);

        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
        {
            static float f = 0.0f;
            static int counter = 0;

            ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.

            ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
            ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window", &show_another_window);

            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f    
            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

            if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);

            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            ImGui::End();
        }

        // 3. Show another simple window.
        if (show_another_window)
        {
            ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
            ImGui::Text("Hello from another window!");
            if (ImGui::Button("Close Me"))
                show_another_window = false;
            ImGui::End();
        }

        // Rendering
        ImGui::Render();
        //SDL_GL_MakeCurrent(window, gl_context);
        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        //glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        //glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        SDL_GL_SwapWindow(window);

        ///---End ImGUI---///

        SDL_RenderPresent(renderer);  
    }

    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplSDL2_Shutdown();
    ImGui::DestroyContext();

    SDL_GL_DeleteContext(gl_context);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Note theres lines:

        //SDL_GL_MakeCurrent(window, gl_context);
        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        //glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        //glClear(GL_COLOR_BUFFER_BIT);

These four lines are from the sdl openg3 exmaple. To make mix sdl renderer and imgui work correct, I have to comment the three lines, or imgui will not show or keep blinking.

And most importantly, sdl renderer graphic draws must come before imgui draw.
And SDL_RenderPresent(renderer); must be called after ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

Hope these help anyone want to use imgui in their sdl2 game.

@ryancheung

This comment has been minimized.

Copy link

commented Oct 26, 2018

I've created a full runnable example here: https://github.com/ryancheung/imgui-mix-sdl2

@ebachard

This comment has been minimized.

Copy link

commented Oct 29, 2018

@ryancheung : thanks a lot for sharing your code. Indeed, it works on Linux, but there is a strange issue I have no clue on how to solve it ...

More precisely, your code (mixing SDL_Renderer AND ImGui) is working successfuly using:

  • OpenGL 3.0, 3.2, 3.3, 4.1, ... , 4.5 associated to glsl version 130 only

The error is either "missing main" in fragment shader, or both Pixel and Fragment cannot be compiled.

Test have been made with a Linux Intel machine able to use GLSL 450 core (x86_64 Intel HD620 + i7 8550 ). The software is the one I checked out for the repository you mentionned above.

In fact, I cannot expain to myself why #version 150 (same for 330, 330 core, and superior), refuses to work with SDL_Renderer ? Is it an SDL2 limitation ?

Without using the SDL_Renderer, glsl versions until 450 work very well so far (you can e.g. test using : https://github.com/willis7/OpenGL-SDL ).

@ryancheung

This comment has been minimized.

Copy link

commented Oct 31, 2018

@ebachard I have not tested the glsl shader yet. And I found the glsl version init code is from the imgui example: https://github.com/ocornut/imgui/blob/master/examples/example_sdl_opengl3/main.cpp#L43

I don't know if imgui with sdl2 limit the glsl version to 130 only. In the example code, it is.

Or the issue you put can be related the three lines of code from the example I commented. You could put back the three commented code lines, which disable the mix, and test if the glsl shader work correctly.

Actually, I don't know much about opengl or glsl, I may not be able to help you a lot.

@paulsapps

This comment has been minimized.

Copy link

commented Nov 24, 2018

This seems like tons of effort and hacks to get something working that isn't really going to continue to work well with future SDL2 updates. Also consider the back-end can be software implementation too.

Even if you only allow DX9 or GL2/3 then it seems odd to use library that abstracts the backend but your goal is the smash down the abstraction.. there are other libs that abstract DX/GL/VK and do allow lower level access which seems to be the goal here?

@ebachard

This comment has been minimized.

Copy link

commented Dec 5, 2018

@ocornut

Today, I was testing SDL 2.0.9 with my software, to verify nothing is broken, and I had the idea to do the following changes:

#define RENDERER_CONTEXT_MAJOR X
#define RENDERER_CONTEXT_MINOR Y

In $SDL2_ROOT_DIR/src/render/opengl/SDL_render_gl.c

And rebuilding the SDL2 libs + linking again everytime, I tested X=2,Y=1 then X=3,Y=0, and finaly X=3,Y=1 with @ryancheung code.

The result is : using OpenGL 2.1 and OpenGL 3.0 contexts, it works as expected, but when using 3,1 it stopped working (SDL2 objects are no longer rendered e.g.)

IMHO, the issue is definitely an SDL2 limitation, unable to enforce a 3.1 or superior OpenGL context, and this could explain the issues with glsl limited to version 130.

I'll try to find the time to ask on libsdl forum. Waiting I'll try to understand in the SDL2 source code why we are stuck with 3.0

@ebachard

This comment has been minimized.

Copy link

commented Feb 23, 2019

Update: I was able to make glsl 3.30 version + OpenGL 4.5 work on Linux using both SDL2 renderer AND imgui OpenGL context ! Still searching for further information, but this is probably the current max we can reach on Linux (with open drivers I mean).

The trick was to define some environment variables, e.g. in your ~/.bashrc file, as wrtten below:

MESA_GL_VERSION_OVERRIDE=3.3
export MESA_GL_VERSION_OVERRIDE

# if the previous env var does not work, try the one below
#MESA_GLSL_VERSION_OVERRIDE=330

Reference link: https://old.reddit.com/r/archlinux/comments/8stpmt/how_can_i_get_opengl_33_with_glsl_33_support/e128v1f/

For the complete explanation, read mesa/src/mesa/main/version.c file in mesa sources (https://gitlab.freedesktop.org/mesa/mesa)

Or in C++ code (don't forget to #include <stdlib.h>), and as example, what I did on my Linux box, using @ryancheung imgui-mix-sdl2 code:

diff --git a/Main.cpp b/Main.cpp
index 6dea975..fb22462 100644
--- a/Main.cpp
+++ b/Main.cpp
@@ -15,6 +15,8 @@ const int SCREEN_HEIGHT = 768;
 const int SCREEN_FPS = 60;
 const int SCREEN_TICK_PER_FRAME = 1000 / SCREEN_FPS;
 
+const char* env_var = "MESA_GL_VERSION_OVERRIDE=4.1";
+
 const char* SetupImGui()
 {
     // Decide GL+GLSL versions
@@ -26,12 +28,24 @@ const char* SetupImGui()
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
 #else
+
+  #ifdef IS_LINUX_AND_YOUR_HARDWARE_CAN_DO_IT
+    // GL 4.5 + GLSL 410, adapt to your case
+    putenv((char*)env_var);
+    const char* glsl_version = "#version 410";
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
+    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
+  #else
     // GL 3.0 + GLSL 130
     const char* glsl_version = "#version 130";
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+  #endif
 #endif
 
     // Create window with graphics context

@ryancheung or any other tester:

Using the change above, the two triangles + the imgui winow appear together in the SDL2 window, as expected. Can you confirm it works for you too ?

Second update: got GLSL version working until 4.50, using the right value in the .bashrc (got MESA_GL_VERSION_OVERRIDE=4.5 in my ~/.bashrc).

Means the environment variables seems to work very well. Disclaimer : I'm using mesa 19.1.0 dev, and maybe it will not work with an older version.

Verification : glxinfo -B now reports :

eric@my_machine ~ $ glxinfo -B
name of display: :0
display: :0  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel Open Source Technology Center (0x8086)
    Device: Mesa DRI Intel(R) UHD Graphics 620 (Kabylake GT2)  (0x5917)
    Version: 19.1.0
    Accelerated: yes
    Video memory: 3072MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 4.5
    Max compat profile version: 4.5
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.2
OpenGL vendor string: Intel Open Source Technology Center
OpenGL renderer string: Mesa DRI Intel(R) UHD Graphics 620 (Kabylake GT2) 
OpenGL core profile version string: 4.5 (Core Profile) Mesa 19.1.0-devel (git-3090c6b9e9)
OpenGL core profile shading language version string: 4.50
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

OpenGL version string: 4.5 (Compatibility Profile) Mesa 19.1.0-devel (git-3090c6b9e9)
OpenGL shading language version string: 4.50
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile

OpenGL ES profile version string: OpenGL ES 3.2 Mesa 19.1.0-devel (git-3090c6b9e9)
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
@ebachard

This comment has been minimized.

Copy link

commented Feb 28, 2019

Tested on Linux x86_64 + Intel GPU + OpenGL 3.1 (from 3.1 to 4.5 work)

To confirm my previous post, watching at the recent mesa commits, I've learned that the issue is known since a while, and the same workaround is proposed i965: Fix allow_higher_compat_version workaround limited by OpenGL 3.0
The link is : https://bugs.freedesktop.org/show_bug.cgi?id=107052

Back to the issue : it seems to be tricky, but with some precautions, it seems to be possible to mix SDL2 renderer + OpenGL3+ + glsl version > 130 on Linux (Intel GPU at least)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.