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

Multi-Viewports + SDL Renderer? #5835

Open
sam20908 opened this issue Oct 29, 2022 · 27 comments
Open

Multi-Viewports + SDL Renderer? #5835

sam20908 opened this issue Oct 29, 2022 · 27 comments

Comments

@sam20908
Copy link

Version/Branch of Dear ImGui:

Version: 1.88
Branch: docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_sdl.cpp + imgui_impl_sdlrenderer.cpp
Compiler: XXX (if the question is related to building or platform specific features)
Operating System: Windows 11

My Issue/Question:

It seems there's no officially documented way to setup mult-viewports with SDL_Renderer. I am aware that I can enable multi-viewports with SDL + OpenGL3, but I not really good with OpenGL and yet I want the hardware acceleration, so SDL_Renderer API is the best choice for me right now. I also thought about just creating the renderer, but then I wasn't sure how to render the viewports because there isn't any way shown in https://github.com/ocornut/imgui/blob/docking/examples/example_sdl_sdlrenderer/main.cpp.

If there's a way to setup multi-viewports with SDL_Renderer, LMK!

Screenshots/Video

Standalone, minimal, complete and verifiable example:

@PathogenDavid
Copy link
Contributor

You aren't doing anything wrong or missing something, the SDL_render backend does not support multi-viewports.

@ocornut
Copy link
Owner

ocornut commented Oct 30, 2022

It may be a relatively easy PR to work on, if anyone is i interested in investigating it.

@sam20908
Copy link
Author

sam20908 commented Nov 3, 2022

I'd love to see this being addressed, because SDL_Renderer is hardware accelerated and I'd get imgui's (awesome) viewports at the same time!

@PathogenDavid
Copy link
Contributor

PathogenDavid commented Nov 9, 2022

(I originally commented this on #5874 but realized it made more sense here.)

@ocornut

TL;DR: Adding multi-viewport support to imgui_impl_sdlrenderer requires disabling user texture support, dirty hacks, or changes to SDL.

Note that multi-viewport for SDL_Renderer backend is likely to be a relatively easy feature to add.

So I started to look into adding this, and it turns out it actually might not be trivial. I started writing some advice to @Vin789 on how they might do it, then I decided to just do it myself, and then I found what might be a showstopper.

Each SDL_Window must have its own SDL_Renderer (it's a strict 1:1 relationship internally.) It turns out that you cannot share textures between different SDL_Renderer instances, which means you can't share textures between windows. This is enforced by the API, it doesn't matter whether the render drivers match.

If you want a quick copy+pastable smoke test:

// Add this to the initialization of example_sdl_sdlrenderer's main
SDL_Window* window2;
SDL_Renderer* renderer2;
SDL_CreateWindowAndRenderer(300, 300, window_flags, &window2, &renderer2);

// ...

// And this to the end of the main loop
SDL_SetRenderDrawColor(renderer2, 255, 0, 0, 255);
SDL_RenderClear(renderer2);
if (SDL_RenderCopy(renderer2, (SDL_Texture*)io.Fonts->TexID, nullptr, nullptr) != 0)
    SDL_Log("Error rendering texture: %s", SDL_GetError());
SDL_RenderPresent(renderer2);

The second window will be blank red and the log will be spammed with errors about the texture and renderer not matching.


I see the following solutions to this problem:

  • Don't allow user textures when multi-viewports is enabled and clone the font texture for each window.
    • This would be a frustrating limitation
    • Cloning the font texture not ideal for performance. Might cause noticable issues with really large CJK textures.
    • Cloned font textures has the potential to become quite annoying once the dynamic font atlas is introduced.
      • It's already pretty annoying with the public create/destroy functions exposed by the backend because it creates implementations that differ between master and docking.
  • Don't allow user textures on secondary viewports and same font texture cloning.
    • This would be a confusing limitation, especially considering the audience for SDL_Renderer.
  • Transparently download and reupload textures to allow sharing them between windows
    • A dirty hack
    • Would realistically require complex caching and possibly manual invalidation for dynamic textures.
    • SDL_Renderer does not appear to provide the APIs necessary to do this for all types of textures. (As far as I can see there's no way to copy a GPU-only texture to a readback texture, which would be required for SDL_TEXTUREACCESS_STATIC and possibly SDL_TEXTUREACCESS_TARGET textures.)
  • Enforce that users must use SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); to enable secondary viewports and render all secondary viewports using OpenGL directly.
    • Dirty hack, feels like it's asking for trouble.
    • Adds a lot of complexity to the backend.
    • Would require poking at SDL internals to get the texture's ID. (I originally thought we could use SDL_GL_BindTexture for this, but looking at the implementation I don't think it'd actually work because it changes the GL context to the renderer's.)
      • Edit: Or we could ask the SDL developers to expose the OpenGL texture ID.
  • Petition the SDL developers to add (or accept a PR to add) a new SDL_RENDERER_TEXTURESHARING capability flag and allow sharing textures between SDL_Renderer instances of the same driver when supported.
    • This is probably the correct solution but is definitely more effort than I have time for right now. (I only looked into this because I also thought it'd be relatively quick and easy.)
  • Put in the effort to figure out how to properly use imgui_impl_opengl3 with SDL_Renderer
    • Turns out this might be slightly more supported than previously thought (based on the presence of SDL_GL_BindTexture)
    • Would still have issues with user textures because SDL_Texture would not be usable as ImTextureID, user textures would need to be OpenGL textures or we'd have to poke at SDL internals as mentioned above.
  • Accept the limitation and tell people not to use SDL_Renderer if they want multi-viewports.

@sam20908
Copy link
Author

sam20908 commented Nov 9, 2022

Hello @PathogenDavid, I have forwarded your message to the SDL Discord. Let's see what the SDL devs have to say on this matter :)

@PathogenDavid
Copy link
Contributor

PathogenDavid commented Nov 9, 2022

Hey, I kinda wish you hadn't. My message was pretty explicitly intended to share my findings with Omar (and to save someone else time investigating in the future.) I'm capable of reaching out to the SDL developers myself and IMO it is premature to do so at this time.

2023 edit: This was a little excessively grumpy. I was pretty stressed out by life stuff at the time and I think I perceived your sharing as indirectly creating an obligation for me. Sorry about that!

@playmer
Copy link

playmer commented Nov 9, 2022

For clarification, the SDL discord is much more of just a community for learning and using SDL. There's one maintainer there, but they're not particularly active (I'm sure they're incredibly busy!). So don't worry too much about the SDL maintainers getting premature information. Thanks for the write up though! I'm sure this will be interesting to those of us who've delved into the SDL source :)

@ocornut
Copy link
Owner

ocornut commented Nov 10, 2022

Thanks David for investigating and thoroughly reporting those.

I think the best path is to get multiple SDL_Renderer windows to support shared resources.
It's already supported by SDL for OpenGL, and it's easy for all Dear ImGui backends to do it so I would assume SDL could do it as well for all their underlying backends. SDL teams have been very proactive and reactive lately so it might happen fast enough and anyhow the earlier we formally push for it the better?

But I also think "Put in the effort to figure out how to properly use imgui_impl_opengl3 with SDL_Renderer" should be possible to solve, maybe investigating SDL_Renderer sources we can find which states are clashing. imgui_impl_opengl3 aims to set all the states it needs and backup/restore but there are always missing things.

@ocornut
Copy link
Owner

ocornut commented Nov 23, 2022

If SDL_Renderer if using OpenGL, wouldn't calling this after creating the first window be enough?

SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1)

@sam20908
Copy link
Author

How would that work though? AFAIK SDL_Renderer uses DX11 by default,

@Vin789
Copy link

Vin789 commented Nov 25, 2022

@ocornut nice catch. Calling this before SDL_CreateWindow/SDL_CreateRenderer/SDL_GL_CreateContext:

// 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);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); // Here
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync

Seems to works (not working after SDL_GL_CreateContext however):

image

@Vin789
Copy link

Vin789 commented Nov 25, 2022

Oups sorry I must precise it's the OpenGL3 example not the SDL_Renderer example. But at least it's working fine with the additional line (mixing SDL image and ImGui + viewports). I guess for the SDL_Renderer it still need more code.

@Vin789
Copy link

Vin789 commented Nov 25, 2022

Ok I'm stupid sorry for all these comments. My example was indeed the example_sdl_opengl3 but WITH the usage of the SDL_Renderer. So it seems that with:

SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");

@sam20908 to force the usage of opengl

and :

SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);

it's working.

@sam20908
Copy link
Author

@Vin789 Can you provide a complete minimal code of it working? I'm confused on the details like do I need to call ImGui_ImplSDL2_InitForRenderer and ImGui_ImplOpenGL3_Init, and so on...

@Vin789
Copy link

Vin789 commented Nov 25, 2022

Sure. Line 110 you need to set the path to your own image for testing. It's an updated version of main.cpp inside example_sdl_opengl3.

#include "imgui.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <SDL.h>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h>
#else
#include <SDL_opengl.h>
#endif

// Main code
int main(int, char**)
{
    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");

    // Setup SDL
    // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
    // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to the latest version of SDL is recommended!)
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
    {
        printf("Error: %s\n", SDL_GetError());
        return -1;
    }

    // Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
    // GL ES 2.0 + GLSL 100
    const char* glsl_version = "#version 100";
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#elif defined(__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);
    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
    SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
    SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_GLContext gl_context = SDL_GL_CreateContext(window);
    SDL_GL_MakeCurrent(window, gl_context);
    SDL_GL_SetSwapInterval(1); // Enable vsync

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;       // Enable Keyboard Controls
    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;           // Enable Docking
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;         // Enable Multi-Viewport / Platform Windows
    //io.ConfigViewportsNoAutoMerge = true;
    //io.ConfigViewportsNoTaskBarIcon = true;

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsLight();

    // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
    ImGuiStyle& style = ImGui::GetStyle();
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        style.WindowRounding = 0.0f;
        style.Colors[ImGuiCol_WindowBg].w = 1.0f;
    }

    // Setup Platform/Renderer backends
    ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Load Fonts
    // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
    // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
    // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
    // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
    // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
    // - Read 'docs/FONTS.md' for more instructions and details.
    // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
    //io.Fonts->AddFontDefault();
    //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
    //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
    //IM_ASSERT(font != NULL);

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

    SDL_Surface* surface = SDL_LoadBMP("D:/test.bmp");
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

    // Main loop
    bool done = false;
    while (!done)
    {
        // Poll and handle events (inputs, window resize, etc.)
        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            ImGui_ImplSDL2_ProcessEvent(&event);
            if (event.type == SDL_QUIT)
                done = true;
            if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
                done = true;
        }

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL2_NewFrame();
        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 create 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();
        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);

        // SDL_renderer
        SDL_Rect rct2;
        rct2.x = rct2.y = 200;
        rct2.w = rct2.h = 400;
        SDL_RenderCopy(renderer, texture, 0, &rct2);

        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        // Update and Render additional Platform Windows
        // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
        //  For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
            SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
        }

        SDL_GL_SwapWindow(window);
    }

    // Cleanup
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(surface);

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

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

    return 0;
}

@ocornut
Copy link
Owner

ocornut commented Nov 25, 2022

Assuming SDL_Renderer only has this sharing issue when using OpenGL and we can detect that SDL_Renderer is using OpenGL we can do perform the call ourselves; meaning with build that backend.

@sam20908
Copy link
Author

Is it an issue with D3D11? I'm kind of hoping I don't have to use OpenGL + Renderer it just seems bad

@sam20908
Copy link
Author

sam20908 commented Nov 25, 2022

@Vin789 Thanks for that example. How is the performance for you when you use that? I hope it's around 1% CPU usage

@Vin789
Copy link

Vin789 commented Nov 25, 2022

@sam20908 well it's look ok on the task manager (~2%) but I'm not really sure looking at this is really useful. I don't know what's your usage of ImGui but if performance is important to you I guess you should probably use specific tool to monitor Ram/CPU/GPU depending on your case. In my case I'm working on a 2D Game editor so performance in the editor himself are not my top priority. The game running in the viewport window with multi threading on the other hand is my priority, I need to keep good performance for Render Thread / Update thread (but it's not ImGui related).

@sam20908
Copy link
Author

Yes, I understand, I use it to judge whether the program is running in a normal range of resource usage. If it's 10% then something is very wrong.

@sam20908
Copy link
Author

The ideal situation I think still is to have it work for SDL_Renderer without needing to rely on OpenGL 3.

@Vin789
Copy link

Vin789 commented Oct 5, 2023

Hi @PathogenDavid !

It's been nearly one year since the creation of this thread. I found some times to work again on my personal editor. I was wondering if you know if the situation changed with ImGui + SDL + Multi viewport. I'm still able to draw the main window with ImGui + SDL and others windows with ImGui. But I can't draw SDL in an other window than the main one. I guess it still the issue with the texture sharing between SDL_Renderer ?

Do you know if SDL3 (I'm still on 2) improve the issue you mentioned with SDL_Renderer ? Or there is still no proper way to mix severals SDL_Window/SDL_Renderer with ImGui ?

Thx for your time.

Vincent

@PathogenDavid
Copy link
Contributor

Hey @Vin789

I was wondering if you know if the situation changed with ImGui + SDL + Multi viewport.

Sorry to say the situation has not changed.

Do you know if SDL3 (I'm still on 2) improve the issue you mentioned with SDL_Renderer ?

The same check still exists in SDL 3, so I assume the answer is no.

I believe the path forward is someone needs to do a deeper investigation into the various solutions I proposed and determine which are good candidates to propose to the SDL team.


Alternatively though, since SDL 3 is still in flux now might be a good idea to make a more general feature request to allow either allow SDL_Renderer instances to be associated with multiple windows or to allow textures to be shared between multiple renderers.

(At the time I think I was mainly concerned with finding a solution that didn't have too much of an impact on SDL, but that might be less of a concern with SDL 3.)

@Vin789
Copy link

Vin789 commented Oct 5, 2023

I see. Thx a lot for the update.

I was waiting because I had works and others stuffs to do on my project. But one of my 3D programmer friend is pushing me to use GLFW + OpenGL directly instead of the SDL. I saw that ImGui seems to have a nice backend for it (and this time it's works fine with multi viewports). So I may just jump on this.

Thx again for your time.

@ocornut
Copy link
Owner

ocornut commented Oct 5, 2023

I don't imagine it is particularly difficult to add support for multi-window in SDL_Renderer, someone just has to do it...

@ocornut
Copy link
Owner

ocornut commented Oct 5, 2023

My bad I was hasty and have brain-farted, I forgot the crux of discussion was about portably supporting texture sharing across graphical contexts regardless of what backend SDL_Renderer uses. I apologize for confusion. David summed it up well above.

It's mostly a problem of pushing this to SDL developer and I assume it would be a small change for them.
Since SDL3 is in active development they may accept a PR quite easily.

Maybe we can setup a basic impl for them to test?

@ocornut
Copy link
Owner

ocornut commented May 15, 2024

Today I thought I would try to push this a little further, by trying to implement (broken) support in our backend so it would be easier to make missing changes to SDL.

I pushed a branch:
https://github.com/ocornut/imgui/tree/features/sdl_renderer3_multiviewports

It's currently not working, because of two issues which would need work on SDL side:

(1) As discussed, textures are not shared so things appears black.
libsdl-org/SDL#6742
I will post some details in said issues.

(2) Another unexpected issues is that SDL_Renderer doesn't seem to support a projection matrix.
Multi-viewports uses absolute system coordinates for vertices so all rendering is mis-positionned (but ClipRect coordinates are correct). If I dig a little bit internally, I noticed RenderScale is applied on vertices in CPU manually, so I presume it might make sense if it evolve into a full-on projection matrix which can later be supported by GPU/shaders instead of processed on CPU.
Since so much is done on CPU (including SDL_RenderGeometryRaw() calling SDL_RenderGeometryRawFloat()) perhaps we can bite the bullet and perform the offset on our side, that would be a workaround but we're putting even more weight on CPU.

Seeing SDL3 progressing toward more general GPU support, I assumed SDL_Renderer was relying on this base already, but it's not since the earlier is not ready yet. So SDL_Renderer is still an API with a handful of CPU side transforms, checks etc. I would assume the natural path for SDL would be that once better GPU support is in, SDL_Renderer will take natural advantage of it, and then it might become trivial for them to add projection matrix etc. in which case it may make sense for them to extend their renderscale concept and add e.g. renderoffset, or a full blown matrix. I'll poke them about this.

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

No branches or pull requests

5 participants