Imgui: Multiple instances of Dear ImGui in the same program

Created on 13 Apr 2016  ·  69Comments  ·  Source: ocornut/imgui

It's not a bug report but more like a question/discussion topic.

So, I have this engine of mine where I have a rendering thread which runs C++ code and scripting environment which runs C# code. They talk to each other via queue and triple buffers to pass rendering lists. Of course I want ImGui to be available on both sides and I can't really just lock it with a mutex, because it will block quite a lot. So what I did:

Converted GImGui to a thread local variable, initialize ImGui from main thread before running mono scripts, also force creation of a font atlas via GetTexDataAsRGBA32 and... it kind of works. Mono renders stuff when it wants to, passes the contents of ImDrawData via triple buffer to the rendering thread, rendering thread renders both GUIs, its own and the one from mono scripting environment.

But I've noticed there are a few places where functions don't look reentrant, for example ImHash function has a static LUT which is initialized on first access. Perhaps there are some other places where implicit global state is used?

In general what do you think about that kind of usage (or should I say abusage :D)?

enhancement multi contexts

Most helpful comment

I am doing multi context in my apps as well as multi-thread and I'm now using locks to avoid undefined behaviour/data races.
I am also trying to do some fancy experiments with multiple concurrent UI "Sessions", one for each user connected through the browser ...
My preference is to make everything ctx.Method(...) or at the very minimum ImGui::Method(&ctx,...)

I don't see so much of a value to save any casual newbie programmer from thinking where he should declare this state/context variable to access where he needs it.
Any real c++ coder will know where to declare it :laughing:

You can also expose the "default static context" as global variable from imgui.h
If you call this variable "ImGui" and you transform ImGui namespace to a struct ImGuiContext,

in imgui.cpp

ImGuiContext ImGui;

in imgui.h

extern ImGuiContext ImGui

everything that the casual programmer will need to do is to replace

ImGui::Button()

with

ImGui.Button()

Would that be acceptable as a minimal search&replace update to a potential 2.0 Api?

All 69 comments

Yeah, it segfaults somewhere. I guess my other option is to just copy & paste imgui into two translation units, maybe wrap them into different namespaces and use it this way. After all I need only 2 instances of it.

I can't really just lock it with a mutex, because it will block quite a lot.

Depending on how/where you use it it may not be that bad.

Perhaps there are some other places where implicit global state is used?

I don't know! You'd have to list them and we can see if it is reasonable or out of reach to fix all of them and maintain it. I would suppose there aren't so many.

Yeah, it segfaults somewhere.

Where/what?
A very quick skimming shows one for the CRC32 lut, one static const array in RoundScalar (const may not be a problem?), and one in the default clipboard implementation for Win32. Off-hand I don't think there's anything else?

In general what do you think about that kind of usage (or should I say abusage :D)?

If it works for you I don't mind :) I have never tried to do that.
Locking mixed with SetInternalState() so far.

Yeah, sorry, this segfault was actually my fault. But anyways I decided to split imgui into two translation units. This way I'm 100% sure the instances have nothing shared and it does work well.

Thanks for awesome lib.

Some discussions about this on twitter today. Adding copies here for reference.

https://twitter.com/Donzanoid/status/720548646601797633

Don Williamson ‏@Donzanoid 11h11 hours ago
@ocornut @andrewwillmott @daniel_collin worth checking out how CUDA API handles this without explicit context param http://docs.nvidia.com/cuda/cuda-c-programming-guide/#context

https://twitter.com/Donzanoid/status/720552966957199360

Rest of the discussion was about the possibility of having an explicit state API (e.g. c-style first parameter passed as state) which could be handled by a script generating code. I have no issue with that as long as it doesn't have pollute or add noise to the basic API, so it should be invisible to the casual user (different file/folder?).

Frankly I don't feel we need a stack but I would like to modify the code to allow the user to make the global pointer a TLS variable.

Also naming needs to be fixed see https://github.com/ocornut/imgui/issues/269

What is the problem with having a ImGui object? The instance can keep
track of it's own IO etc.

On Thu, 14 Apr 2016 at 17:06 omar [email protected] wrote:

Some discussions about this on twitter today. Adding copies here for
reference.

https://twitter.com/Donzanoid/status/720548646601797633

Don Williamson ‏@Donzanoid 11h11 hours ago
@ocornut https://github.com/ocornut @andrewwillmott
https://github.com/andrewwillmott @daniel_collin worth checking out how
CUDA API handles this without explicit context param
http://docs.nvidia.com/cuda/cuda-c-programming-guide/#context

https://twitter.com/Donzanoid/status/720552966957199360

Rest of the discussion was about the possibility of having an explicit
state API (e.g. c-style first parameter passed as state) which could be
handled by a script generating code. I have no issue with that as long as
it doesn't have pollute or add noise to the basic API, so it should be
invisible to the casual user (different file/folder?).

Frankly I don't feel we need a stack but I would like to modify the code
to allow the user to make the global pointer a TLS variable.

Also naming needs to be fixed see #269
https://github.com/ocornut/imgui/issues/269


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
https://github.com/ocornut/imgui/issues/586#issuecomment-210148960

Well, if you ask me, I would definitely prefer explicit context variable. But when it comes to having both APIs, global style and the one with context variable, it's a tricky question.

Maybe you can even do that with macros, i.e. make it a compile-time feature. But not sure if you would like that solution or not.

Something like:

IMGUI_API bool          RadioButton(IMGUI_CONTEXT const char* label, bool active);

And in implementation:

GImGui *g = IMGUI_USE_CONTEXT;

Probably pretty ugly though. So one can leave IMGUI_CONTEXT empty and say that IMGUI_USE_CONTEXT simply refers to global var. Or fill it with the right content.

Or the same, but wrap all the API into a class conditionally with a macro. But again some macro pressure on the implementation side, because funcs/methods look different: void X::Foo() vs void Foo().

Whatever works I'm happy with all variants. I don't like much TLS usage though. On my side it was a quickest hack possible.

That's actually a neat solution from a technical perspective, would save us a lot of work.
It's mainly ugly because of the missing comma, but it also mean that within functions the parameter has to be passed around which adds another layer of missing-comma-fugliness inside the functions themselves.

I really don't know what's the best solution. Ultimately it isn't a much desired feature, people sort of prefer if it was there but nobody absolutely needs it so I may put that in the backburner until someone comes up with a better idea. I'd really love it if some macro trick could save us from that missing comma.

Should still fix that CRC32 static table too.

_EDIT_ Not helping much, but another solution for an alternative reality would be to always have context pointer and allow 0/NULL as a shortcut for global state pointer. ImGui::Button(0, "blah").

For me personally I would rather have this:

void RadioButton(context, ...)

(or, like talked about in the twitter thread)

void RadioButton(...); // Global Edition

void RadioButton(...)
{ 
  RadioButton(g_context, ...); // defaults to global context, defined in imgui_context.h or such
}

I know this would result in lots of cut'n'paste of all the functions but I really think it's the cleanest way to do it. Also as @nsf points out I really don't like the TLS stuff. I would personally see that dear imgui only deals with a context and and let the application deal with anything threading.

As always threading is a data issue and not a code one so as long as dear imgui would only play with a given context (and global in the causal use-case) everything would be fine.

TLS is the crap workaround obviously but as long as it's not enabled by default (because of performance) it's probably a 2-lines source change (probably some optional macro in imconfig.h) and not causing harm.

Now on discussing proper solution. There's about 330 functions in imgui.h
Potentially the "no-context" versions could be inlined in a header file (If the global pointer can be declared extern there?) meaning the overhead would be 1 line per function and in a single place.
@nsf how did you "split imgui into two translation units" without duplicates at link time?

They would perhaps need to be in different namespace in order to avoid end-user seeing 2 versions of each.

@ocornut wrapped the second copy into a different namespace

Yes all of the non-context functions would be inlined as you say so there wouldn't be any extra overhead to the change. Also the TLS change doesn't help if you want multiple instances on the same thread (I haven't used TLS much but is it possible to have more instances per thread? Then it would work also)

No, with TLS - one instance per thread, unless you do that push/pop trick from cuda API. Also TLS is bad for coroutine-like situation where your jobs can be scheduled onto different threads over time. Whether it's bad or not is a different topic, but it's possible. E.g. languages like Go and coroutines will come into C++ sooner or later.

@emoon In that case the thread could always call e.g. SetCurrentContext() or some equivalent Push/Pop to change context.

Looks like adding the non-context inline function sounds fairly reasonable, just need to swallow the bullet of making imgui.h less good looking with extra arg everywhere. Or, I replace namespace ImGui by struct ImGuiContext for the context version and make them method? Would that be any less friendly, have subtle side-effects?

Struct is okay, but the main problem with structs is that even private methods have to be in the header file. Or you'll have to pass the context around as an argument for private functions.

probably for migrating code, search and replace on ImGUi:: to imguiCtx. (or however one calls their local context) is a bit easier than adding a parameter on every call?

Yeah for my use-case I think I will be fine with SetCurrentContext as I don't run my UI stuff multi-threaded (yet)

I assume you still want to keep your namespace ImGui::Function(...) syntax? Otherwise the other approach would be to actually use a struct/class like g_imgui->Function(...) I much prefer the current style though.

@ocornut remember that you can still keep the current layout exactly as in the header file. All you need is to include a "some.inl" that actually does the inline implementation of the non-context functions.

Struct is okay, but the main problem with structs is that even private methods have to be in the header file. Or you'll have to pass the context around as an argument for private functions.

I hate this, but tempted to still do it if I cold. I was mainly wondering if using method would make a slight difference to people working on bindings or other languages. Perhaps explicit parameters can be easier to bind to other languages without adding another set of wrapper functions? In term of how mangled names can be accessed?

(..Second paragraph completely backtracking on the first one..)

However, if there is an actual struct + methods now we need to also shove members into header OR have an additional indirection (bad) OR have a private derived type and cast this in the private code. None of those solution are exciting. Any better idea that doesn't suck?

I don't actually care the ImGui:: namespace too much (personally mostly because of the two uppercase letters :) tho changing it may be more of a v2.0 thing? DanielGibson has a point that at least it could be search-and-replaced safely, so it's not out of consideration and may be part of solution.

Now clearly:
ctx.Button()
is shorter than
ImGui::Button(ctx)

But later also feels a little less C++, perhaps more bindings-friendly, more search-and-replace friendly, and I can't find a satisfactory solution to use member functions/variables (paragraph above).

Well, you can pass context as an argument to private functions. I agree there is no pretty solution in C++. As for bindings, I don't think any C++ solution works there. Name mangling is already bad enough and if you have it, only brave people use C++ .so/.dll directly. So, one way or another there will be a C wrapper also and it's typically easier to use for bindings. As for me, for my C# bindings I use wrapper functions, so the C++ API isn't a big deal.

I would say that passing context argument explicitly is a true procedural way, but also it's not pretty at all. But that's the only way how C api will look like at the end. So, eh, I don't know what's the best solution here.

I would definitely prefer the ctx.Button() way that ImGui::Button(ctx). I
don't agree with bindings-friendly as every scripting language generally
deals with C++ object bindings. It would get rid of the SetInternalState()
calls that I am currently doing to support multiple instances (on the same
thread) of ImGui. It would also solve the multi-threaded issue too.

On Thu, 14 Apr 2016 at 19:00 nsf [email protected] wrote:

Well, you can pass context as an argument to private functions. I agree
there is no pretty solution in C++. As for bindings, I don't think any C++
solution works there. Name mangling is already bad enough and if you have
it, only brave people use C++ .so/.dll directly. So, one way or another
there will be a C wrapper also and it's typically easier to use for
bindings. As for me, for my C# bindings I use wrapper functions, so the C++
API isn't a big deal.

I would say that passing context argument explicitly is a true procedural
way, but also it's not pretty at all. But that's the only way how C api
will look like at the end. So, eh, I don't know what's the best solution
here.


You are receiving this because you commented.

Reply to this email directly or view it on GitHub
https://github.com/ocornut/imgui/issues/586#issuecomment-210194622

I do all my wrapping in C++ to a C API in the end also so I really don't care that much how the context is being sent. Regarding the data in the header. I would just go with

struct PrivateData;

struct ImGui {
  void RadioButton(...);
  ...
  PrivateData* private_data;
}

And have the PrivateData declared in the C++ code. If you really want to hide it you have can of course have a void pointer here but then you would need to do more casting inside you other code to use it.

Problem with this approach is if the user wants to modify/get data from the private struct it has to be done using functions which may be a bit annoying. Of course the private data can be stuffed in another header also to keep the regular header a bit clear.

I am doing multi context in my apps as well as multi-thread and I'm now using locks to avoid undefined behaviour/data races.
I am also trying to do some fancy experiments with multiple concurrent UI "Sessions", one for each user connected through the browser ...
My preference is to make everything ctx.Method(...) or at the very minimum ImGui::Method(&ctx,...)

I don't see so much of a value to save any casual newbie programmer from thinking where he should declare this state/context variable to access where he needs it.
Any real c++ coder will know where to declare it :laughing:

You can also expose the "default static context" as global variable from imgui.h
If you call this variable "ImGui" and you transform ImGui namespace to a struct ImGuiContext,

in imgui.cpp

ImGuiContext ImGui;

in imgui.h

extern ImGuiContext ImGui

everything that the casual programmer will need to do is to replace

ImGui::Button()

with

ImGui.Button()

Would that be acceptable as a minimal search&replace update to a potential 2.0 Api?

Another vote for context->Blah() and so on here, rather than Blah(context). If there's a backwards compatibility header with inline wrappers, it's not going to affect users who don't change their code either way, and I think that's a cleaner more C++ approach. (Though sadly the meaning of 'more C++ approach' has degenerated into insanity these days so maybe ignore that comment :P.)

The changes on the ImGui side can be pretty minimal, thanks to the state already being well encapsulated. Daniel's already alluded to this but

struct ImGuiContext
{
    void NewFrame();
    // ...


    ImGuiContext();
    ~ImGuiContext();
protected:
    ImGuiState& g;
};

would reduce changes in many cases to just taking out the dereference lines:

void ImGui::NewFrame()
{
    ImGuiState& g = *GImGui;

    if (!g.Initialized)
    {
    }
}

// Becomes

void ImGuiContext::NewFrame()
{
    if (!g.Initialized)
    {
    }
}

The constructor/destructor is just

ImGuiContext::ImGuiContext() : g(*new ImGuiState)
{
}
ImGuiContext::~ImGuiContext()
{
    delete &g;
}

// or better

ImGuiContext::ImGuiContext() : g(*new(MemAlloc(sizeof(ImGuiState))) ImGuiState)
{
}
ImGuiContext::~ImGuiContext()
{
    g.~ImGuiState();
    MemFree(&g);
}

// or even better avoid the double-alloc by having CreateContext()/DestroyContext() that allocate one block.

One thing that would need thinking about is memory allocation. This either has to be separated out of the context, or the code needs to be updated to call per-context allocs rather than MemAlloc(), and pass the memory allocator into the context constructor or creation function.

Some of the functions don't reference the context internally at all of course. I guess the easiest thing would be for these to remain as ImGui::ColorConvertRGBtoHSV (say) and hence not needed in the optional backwards compat. header.

Some extra ideas

  • Would break cases of people adding their own functions in ImGui namespace, which is a rather convenient feature to extend the library in a way that feels natural. I'll have to look into some big codebases using ImGui so gauge the side-effects. If you can't add to an existing namespace one workaround would be to allocate your own derived instance but it is nowhere are convenient.
  • May need to move MemAlloc etc. function pointers, perhaps to be define or use another system?

or even better avoid the double-alloc by having CreateContext()/DestroyContext() that allocate one block.

This is desirable to avoid be touching 1 extra cache line on every call accessing the context. Will probably use a scheme like that. That and perhaps changing the way allocators are specified might lead us to require an explicit one-liner Initialization of ImGui.

I will let those ideas simmer for a bit, afaik there is not urgency.
I would like to point out that it is a topic where everyone would naturally want to say "of course it is better if there is an explicitly context" because obviously it is better, but it's not a requirement, it has a cost of change, and I don't think it is blocking many people to not have it soon.

1-thread 1-context : not affected by change. (most common)
1-thread 2-contexts : that change will help to avoid calling SetInternalState/SetContext so code will be a little nicer, but it's not total a deal-breaker to not have it.
N-threads 1-context : that change won't help at all, user still need a lock.
N-threads 1-context per-thread : that change will allow that situation. note that the TLS workaround also allows it, albeit with extra cost of TLS access.

In other words, there's no situation that's 100% blocked right now.
I want to do this but I don't think it is urgent.

(Note that for a known number of instances,e.g. 2, the namespacing trick with 2 copies of ImGui code in different namespaces also works)

Soonish tasks:

  • [x] Move alloc handlers to macros and out of context so we can have a function that actually allocates a context.
  • [x] Rename existing context functions to use sane names/patterns #269

Cleaned up the messy/confusing Set/GetInternalState functions, and added

ImGuiContext* CreateContext(void* (*malloc_fn)(size_t) = NULL, void (*free_fn)(void*) = NULL);
void          DestroyContext(ImGuiContext* ctx);
ImGuiContext* GetCurrentContext();
void          SetCurrentContext(ImGuiContext* ctx);

Decided against changing io.MemAllocFn etc. to imconfig.h IM_MALLOC because editing anything in imconfig.h has big mental and practical barrier cost for many. Instead, to solve the fact that CreateContext() needs to do an allocation the functions are passed here and stored immediately within the context.

This is breaking API for users who were using SetInternalState GetInternalState but they are very rare and those users are expert users so they will figure it out. Added the information in the API Breaking Changes section of the documentation.

I also also renamed the internal ImGuIState struct to ImGuiContext.

I'll take the compliment!

On Sat, 7 May 2016 at 13:59 omar [email protected] wrote:

Cleaned up the messy/confusing Set/GetInternalState functions, and added

ImGuiContext* CreateContext(void* (_malloc_fn)(size_t) = NULL, void (_free_fn)(void_) = NULL);
void DestroyContext(ImGuiContext_ ctx);
ImGuiContext* GetCurrentContext();
void SetCurrentContext(ImGuiContext* ctx);

Decided against changing io.MemAllocFn etc. to imconfig.h IM_MALLOC
because editing _anything_ in imconfig.h has big mental and practical
barrier cost for many. Instead, to solve the fact that CreateContext()
needs to do an allocation the functions are passed here and stored
immediately within the context.

This is breaking API for users who were using SetInternalState
GetInternalState but they are very rare and those users are expert users
so they will figure it out. Added the information in the API Breaking
Changes section of the documentation.


You are receiving this because you commented.

Reply to this email directly or view it on GitHub
https://github.com/ocornut/imgui/issues/586#issuecomment-217656384

Oh f...k, I just grabbed the latest version with so much code to change on my side... :(
But, clearly, this is a lot better with this new version (even if it will cost me one night)

Sorry :/ Do a manual rename of ImGuIState to ImGuiContext in your branch BEFORE merging and it may be much easier?

_EDIT_ Did you mean merge issues? Which local changes do you have that weren't pushed as PR? I wonder which local changes you actually need.

Not any issues for the moment, I didn't start the merge.
This won't be very painful, that's a mechanic job keeping my mind in automatic mode... and that's for a better meaning of ImGuIState as ImGuiContext.

EDIT: in my private engine, I use 2 imgui instances, a first one for my own "simulator" of iOS, and second one for the editor. That's why I use 2 ImGuIStates.

I am SO lucky :) This change came just in time for me :) Many thanks!

I've just updated ImGuIState to ImGuiContext and it looks good so far.

I've tried to render two windows with the new context API modifying opengl3_example. I observed two problems: (1) the ImGui widgets in the first window don't respond to mouse actions and (2) the second window doesn't render the ImGui widgets.

Here is my test code. I would appreciate if someone could point out what I'm doing wrong here.

Edit: I modified the while statement only.

From #688

Currently, a lot of functions access the ImGuiState (aka context) in that way:

ImGuiState& g = *GImGui;

That's fine for a single context, or multiple context (windows) updating on the same thread changing it with ImGui::SetInternalState, but that doesn't work well if we have different windows on different threads. Changing the entire interface to require a ImGuiState* as a parameter for every function is madness, it not only implies functions that directly access to state but functions that also call those, which means the entire imgui interface. So, a solution could be just replacing the *GImGui; (~245) access with a call to GetInternalState() .

This way the user (programmer) can modify GetInternalState function to manage how to access the context and use a unique thread id like the c++11 one http://en.cppreference.com/w/cpp/thread/get_id, to access a per-thread ImGuiState, just think in a std::map<std::thread_id, ImGuiState*>. Ok, it asumes that every imgui call is performed in the thread that holds the ImGuiState where it wants to draw something, but makes sense, and it doesn't mean that a thread can only hold one ImGuiState, It can even be mixed with threads that hold multiple context just modifying GetInternalState to work that way with those threads, similar to how we are currently working calling SetInternalState to change it.

For some functions (mainly little functions used internally) where a call to a complex version of GetInternalState may suppose a performance impact, well, maybe for those there is no better solution than passing the context as a parameter...

What do you think about this possible solution for multi-threaded/windows applications?

@Galloman Your solution can already be implemented by setting GImGui to be a thread-local-storage variable, which would be a 1 line modification locally.

PS: Note that following discussion in this thread, one month ago the GetInternalState etc function have been changed to GetCurrentContext() with various modification to enable context creation.

This thread still entertain the idea that we could make the context an implicit this and change existing functions to this-call methods, which wouldn't be so hard to implement but break a few things.

@ocornut I was trying to set the GImGui as local storage but Apple doesn't want it... http://stackoverflow.com/a/29929949/2484187 So, it's a good solution when you are not using the Apple LLVM compiler :(

I'm thinking about using ImGui for audio plugin guis. The key difficulty is around having multiple contexts, because you could have many plugin instances in a single host process, and you don't have any control over which threads own which plugins etc, so you need to be able to scope separate gui instances quite tightly.

You can check how I'm doing it in a single thread for GTF here: https://github.com/Galloman/GTF/tree/master/src/gtf/iosys

Couldn't all this be managed making ImGUI a class?
The class would have the imgui context as a member so we dont have to overwrite the global with SetCurrentContext. Multiple windows and multiple threads also.

That's also what's discussed here and rather probable it'll go this route. Creates a few issues a) for backward compatibility (it will break everyones code everywhere but can be Search&Replaced) and b) populating ImGui:: with new functions which is the thing I'm the most annoyed with.

Which new functions you mean?

It is currently convenient to add functions to the ImGui namespace (overloads for own types etc.) which c++ allows for namespace but not for class unless inheriting or hackery

Perhaps the TLS way should tried before as less code intrusive. Did anyone experimented with it?

Just tried TLS with the GLF3 implementation in https://github.com/sonoro1234/cimgui/tree/lua_build/extras/impl_glfw3 for switching ImGuiContext.

Fonts appear strange in one of the two threads
But only if I add a font from file with ImFontAtlas_AddFontFromFileTTF and previous AddFontDefault

Hi everyone,

I've been working with ImGui for a while now (awesome job @ocornut btw). I managed to do compose a simple bezier curve editor, node editor and other gadgets, but now I am at a turning point and got stuck. What I want to do is to create a new independant floating window. This secondary window will contain a texture reference and just be drawn as it is (with resizing) - the drawList tricks.

I've also read plenty of forums here, but still got stuck.

The whole idea: main application has a node editor where you set float value which then sets radius value for a red circle and draws everything to a fbo. I got it working in the main window and now I want to display this (updating) texture in this new window.

Many thanks!

I just published my experiments for N-threads 1-context per-thread with TSL access.
Not ideal but for the moment 3 lines of code change and seems to work.

https://github.com/matteomandelli/ssb

To everybody using overload for malloc/free,
I would like to fix the bug discussed in #992, but here seems like the thread where I'd get better feedback.

Basically:
__Will remove MemAllocFn/MemFreeFn OUT of the context structure.__

(I think it was a mistake I had it there, was hoping it would allow different allocators to be affected to different imgui instances, but I don't think anybody care for that, it mostly causes problems e.g. at destruction time, and helpers that aren't tied to an imgui instance and often allocated inside tools are sitting in the middle of this and most affected by those problems, it makes it harder to have a simple ImGuiTextFilter declared static in a function because it tends to crash on destruction if you don't keep an ImGui instance alive.)

This will break the build for _only_ the people reassigning those (which is good, most people won't be affected).

Looking for feedback on those two possibilities:

1) Expose defines (documented in imconfig.h), e.g. #define IMGUI_MALLOC malloc, #define IMGUI_FREE free.
Pros: User can avoid linking with malloc/free altogether if they wish so.
Cons: A little harder to setup, user needs to modify imconfig.h (probably ok for the the sorts of people who don't use malloc/free).

2) Expose two globals, e.g. ImGui::SetAllocators(xxx,xxx),
Pros: Easier to setup, no need to touch imconfig.h
Cons: Enforce linking with malloc/free (but we can also solve that with another layer of defines).
(edit TO CLARIFY THOSE GLOBALS WOULD NOT BE STORED IN AN IMGUICONTEXT)

Anything else? Suggestions?

From my point of view problem with allocator functions is aftermath of having global contex/atlas instance. I added a define allowing me to disable default instances of context and font atlas. Problem vanished since construction and destruction time was explicitly managed.

As to choice of API I do not have strong preference. Either will work. First one will be harder to break at run-time.

From my point of view problem with allocator functions is aftermath of having global contex/atlas instance.

It also makes it trickier for code that tries to manage multiple contexts to ever use those functions, making such code harder to share as an extension.

Anyone else, feedback on my post above? (#define IMGUI_MALLOC vs off-context ImGui::SetAllocators() setting globals).

I've been monitoring this thread for quite some time because because memory allocation and global state prevent me from using imgui.

Global context
This is a problem because I might want to "draw" the UI in thread A and "render" it in thread B.

Memory allocation
IMHO the 2nd solution is better but it should be more fine grained. I'm not sure how imgui works internally but there might be a need for more allocators. You may need an allocator that matches the context's lifetime and another allocator that is per frame. The motivation for a per-frame alocator is to have a super fast linear allocator that is reset and reused at the beginning of the frame.

Other objects like the font atlas might need their own allocator because their lifetime might be different.

Also the allocator callbacks should accept some user data:

using AllocCallback = void* (*)(void* userData, size_t size, unsigned alignment);
using FreeCallback = void (*)(void* userData, void* ptr);

Final thoughts
Removing a global stuff and adding a more fine grained allocator scheme will provide much more flexibility to the existing scheme. The context change will break the interfaces but the memory allocators can be optional.

This is a problem because I might want to "draw" the UI in thread A and "render" it in thread B

Can't thread A just store the data for thread B to use?
Thread A calls EndFrame()/Render() without rendering, then store the ImDrawData contents? You'd only have one mutex and for a short period of time.

I have to admit that this was a bad example on my part. What I have in mind is to have some threads that construct parts of the UI in parallel (per panel for example). Then render the command lists in other threads.

Imagine I have a game level with a number of computer screens and I want to use imgui to render stuff on them. Every computer screen is a scene node. On my scene graph update (which is parallel) I populate the UI for each screen. Then the renderer will take that UI contexts and render them. And because this is a vulkan engine I might also do that in parallel as well. At the end of the day I populate UI widgets in thread A and render them in thread B. In the next frame I may switch threads. It's chaotic.

Another example (that requires custom memory allocators as well) is to create a context per frame, draw the UI, render it and then destroy the context by freeing the whole memory at once. If I use a linear allocator (every allocation is just a ++offset) then the allocation cost is almost zero.

BTW I don't want to sound that I'm imposing something here. My only goal is to share a different view towards more flexibility. Continue the great work!

Imagine I have a game level with a number of computer screens and I want to use imgui to render stuff on them. Every computer screen is a scene node. On my scene graph update (which is parallel) I populate the UI for each screen. Then the renderer will take that UI contexts and render them.

For now you can make GImGui a thread-local-stored variable if you want to achieve that without a lock, but it'll probably be simpler and just as fast with a lock if you don't have many of such renders.

Memory allocation

Dear ImGui doesn't reallocate every frame, it only allocate when things are growing then stays at zero allocations for a typical frame. Aaside from rare circumstance it doesn't allocates something that it would free during the same frame (and when that happens it's only one or a few). So using a linear/throwaway allocator shouldn't be needed and likewise I don't imagine more fine-grained allocation options would be useful.?

For now you can make GImGui a thread-local-stored variable if you want to achieve that without a lock, but it'll probably be simpler and just as fast with a lock if you don't have many of such renders.

I see you have CreateContext() and SetCurrentContext(). I missed those two. Then yes thread_local might actually work work. The downside is that the perf wont as great as passing the context around.

Dear ImGui doesn't reallocate every frame, it only allocate when things are growing then stays at zero allocations for a typical frame. Aaside from rare circumstance it doesn't allocates something that it would free during the same frame (and when that happens it's only one or a few). So using a linear/throwaway allocator shouldn't be needed and likewise I don't imagine more fine-grained allocation options would be useful.?

In that case a more fine-grained allocator might not needed indeed. So I guess the only thing that is missing is to pass a void* in the MemAllocFn and MemFreeFn so I can use my linear allocator?

I see you have CreateContext() and SetCurrentContext(). I missed those two. Then yes thread_local might actually work work. The downside is that the perf wont as great as passing the context around.

That's correct. I think changing the context will be a 2.0 thing. Not being able to add methods to a class the same way you can add functions to a namespace make this change rather unsatisfactory. People have been using the GImGui as TLS (you can #define GImGui in imconfig.h for that) so it works.

So I guess the only thing that is missing is to pass a void* in the MemAllocFn and MemFreeFn so I can use my linear allocator?

But you can't use a linear allocator for the general allocations it does.Sorry my sentence earlier "it only allocate when things are growing then stays at zero allocations for a typical frame" may be misleading but imgui uses realloc patterns (alloc new, copy old data, free old). It looks like you are trying to optimizing things out of habits but imgui likely doesn't need those optimizations, at least not for allocations.

But you can't use a linear allocator for the general allocations it does.Sorry my sentence earlier "it only allocate when things are growing then stays at zero allocations for a typical frame" may be misleading but imgui uses realloc patterns (alloc new, copy old data, free old). It looks like you are trying to optimizing things out of habits but imgui likely doesn't need those optimizations, at least not for allocations.

I'll explain my rationale for that using an example. Imagine I have an level editor. Every panel is a different imgui context (because of parallel building blah blah). I'm drawing each of those panels to different textures and then I compose them to a final result. In the following frames I update only the panels that have been changed. So what I want is to use the imgui contexts as a throwaway data structure. I create a new one only when I the UI needs updating and I immediately throw it away.

This example is a bit too extreme but it depicts another use case (throwaway contexts) that might be useful in some cases.

I do believe though that this problem can also be workaround (by me and some minimum hackery) by having the "allocator" as thread_local.

Thanks for your answers! Food for thought for imgui 2.0 (any timeframe for that?)

Note that both of my proposed changes implied removing per-context allocators. Your use case it fairly unusual and between the possibility of using TLS, or fully single-threading your imgui rendering (process them in a thread separate from your scene graph update), or mutex them their use, it looks like you have enough margin.

No timeframe for anything, sorry. I am currently focusing on dear imgui but I don't know how long I will be able to do so. Even thinking about those features or edge cases is derailing me a little from focusing on the more important short-term features.

+1 for a non-global context of some sort. (Either as an arg or object, don't really care.)

I fall into the one context per thread camp. In my game I have the client and server running in the same process on different threads to make network debugging easier. TLS seems to be mostly working, though it crashes when calling the context destructor. I read somewhere that font atlases are shared?

I read somewhere that font atlases are shared?

ImFontAtlas is shared by default (and read-only after Initialization).

Basically ImGuiContext constructor does:
Fonts = &GImDefaultFontAtlas;

You may create your own font atlas and reassign in your ImGuiContext. I'll clean all that up and probably will end up requiring at least an explicit Initialization call to create default contexts in the future.

I'd like to share my point of view / use case, this is by no means a feature suggestion or similar, I just want to share some thoughts:

This design with the contexts is interesting (and will be very useful for me), but for my use case there is a drawback:
The implementation assumes that the IO and the Render happen on the same context.

My use case is as follows:
1) IO happens on the main thread = window message pump thread
2) Actual rendering can (and usually does) happen on an other thread.
(This is the way it currently is in Valve's CS:GO for example and similar Source engine games).

In my case there can be multiple contexts waiting to be actually rendered on the render job thread, while only one is in IO / main thread at a time.

So I am left with one or two okay solutions afaik (if I don't count modfiying ImGUI core files too much as a solution for now, since that would probably cut me off from future ImGui updates or make them at least notably more cumbersome):

1) Somehow sync relevant IO state between different contexts on the window message pump thread (this will loose the MetricsRender... info of course, since when the next frame is begun, the Render thread doesn't have to have run yet. (Meaning only call ImGui::Render on a dedicated context on the render thread and everything else happens on the main thread.)
Pros: No Render data duplication needed.
Cons: Metrics lost (hopefully not that much of a problem), also need to take care about everything that I want synced between the contexts.

2) Another soultion would be to off-load the drawing data inside RenderDrawListsFn and buffers ("copying" them) for the Rendering thread.
Pros: No need to sync IO state between contexts
Cons: Potentially huge render data copying overhead.

I'll probably go for solution 1 for now :-)

Edit: Actually went for solution 2 for now.

My game is client/server, and both get their own thread to run their main loops. My rendering is also threaded, so I'm using both solutions 1 and 2. There isn't really that much I/O to buffer on the main thread (mouse, keys, chars), so it's really not that much work. I mean it's a couple dozen lines of code to gather all the input either way, and another dozen to consume it on the other thread. My rendering uses memory mapped GL buffers, so there is no (additional) duplication of rendering data. Admittedly, that part is much more involved if you haven't already implemented it.

Everyone: the changes discussed in #1565 have been merged to master.
Just to clarify, those changes DO NOT address the multi-threading issues discussed here, they however address various issues related to creating/maintaining multiple contexts, sharing font atlas and setting up memory allocators. The multi-threading issues though an explicit context->Function() will possibly be addressed in 2.0.

Copying text from that issue:


The purpose of those changes is:

  • To address issues with multiple context management being confusing for anyone trying to use them.
  • To address issues with people using DLL hot-reloading, which the statically created instances made more difficult.
  • To address issues with memory allocators being stored inside the context. The statically created instances made it worse, but generally it feels more healthy to have a shared allocator that helper classes such as ImVector<> can use.

Changes:

  • Context creation is explicit. YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
  • Removed the statically constructed global context and font atlas instances, which were confusing for users of DLL reloading and users of multiple contexts.
  • Removed Shutdown() function, as DestroyContext() serve this purpose.
  • You may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance and destroy it on DestroyContext().
  • Removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. Added a void* user_data to allocators function.
  • Added a IMGUI_DISABLE_DEFAULT_ALLOCATORS imconfig.h directive for people who don't want to link with malloc/free at all.

Existing codebase will be broken:

  • The user needs to call ImGui::CreateContext(), and possibly ImGui::DestroyContext()
  • Previously the imgui_impl_xxx binding were calling ImGui::Shutdown(), this was removed and the function doesn't exist as a public function any more. DestroyContext() calls the internal Shutdown() and delete the instance.
  • If you used multiple context and allocators there's a few more things to rewire but they should be fairly obvious.

Note that on-going work on virtual viewports (#1542) with reduce the need/usefulness of using multiple context as one context will be able to handle multiple windows.

I'm in a situation where I have an update thread and a render thread. I have essentially triple-buffered a lot of my state so that I can render and update simultaneously without stepping on each other. The ideal for me with ImGui would be an easy way to have separate context per triple-buffered state. That way I could begin a frame in the update thread, and end the same frame in the render thread.

I suppose I could do that with the multiple namespaces/translation units solution, though it seems a bit awkward.

The other way would be to create separate contexts for each state.
Is it safe right now to have three separate ImGui contexts right now and use them in the way I'm hoping? Is it seriously messing with performance to do so?

I know I could just try it and see, but sometimes things are more subtle or complicated than they first appear so I thought it couldn't hurt to ask.

I'm in a situation where I have an update thread and a render thread. I have essentially triple-buffered a lot of my state so that I can render and update simultaneously without stepping on each other. T

It's not clear in your description if you want to _use_ imgui in your render thread, or only _render_ the imgui output from the update phase of the previous frame. If what you are aiming at is the later, you absolutely don't need multiple contexts. You can clone the ImDrawData/ImDrawList (there's a CloneOutput helper) and give ownership of that data to the render thread which will render it later.

Cloning is not as efficient as an hypothetical "flipping" of resources, but you are only going to copy your 200~400 KB worth of mostly contiguous data around and that cost should be fairly negligible. In the future we could add support for N-buffers in ImDrawList but that'll be more work.

Is it safe right now to have three separate ImGui contexts right now and use them in the way I'm hoping? Is it seriously messing with performance to do so?

It won't necessarily mess with performances but inputs/interaction will likely be all broken and hard to fix as each of the 3 context will maintain themselves with slightly time-offset inputs, those are not going to magically sync up.

You can clone the ImDrawData/ImDrawList (there's a CloneOutput helper) and give ownership of that data to the render thread which will render it later.

Cloning is not as efficient as an hypothetical "flipping" of resources, but you are only going to copy your 200~400 KB worth of mostly contiguous data around and that cost should be fairly negligible.

What I do in my threaded renderer is to have a mapped buffer available to my main thread. At the end of the frame, that buffer gets flipped to the render thread to be drawn or to have more stuff appended to it. This way you don't need to copy the imGUI buffer, then later copy it to GPU memory.

If anything, the only change I'd make to imGUI is setter for the internal buffer pointer or pass it into the render function. That way it could be buffered however the user wanted, possibly even directly into mapped memory. Maybe a bit overkill though, and puts the onus on imGUI to play nicely with write combined memory.

If anything, the only change I'd make to imGUI is setter for the internal buffer pointer or pass it into the render function. That way it could be buffered however the user wanted, possibly even directly into mapped memory. Maybe a bit overkill though, and puts the onus on imGUI to play nicely with write combined memory.

Could you elaborate on this because I don't clearly understand this paragraph, thanks.

As I understand it, imGUI has one big vertex/index buffer internally that it uses.

Roughly speaking now you do:

ImGui::Render();
for(cmd_list in ImGui::GetDrawData()->CmdLists){
  // cmd_list->VtxBuffer.Data, etc to copy into another buffer or GPU memory.
  // Make draw calls
}

Instead you could do something like:

ImGui::SetBuffer(vertex_buffer, vertex_buffer_size, index_buffer, index_buffer_size);
// These pointers could be directly into mapped GPU memory to avoid an extra memcpy().

ImGui::Render();
for(cmd_list in ImGui::GetDrawData()->CmdLists){
  // Data already in your buffers (or GPU mem), can calculate bind offsets using the pointers.
  // Make draw calls.
}

Though honestly I'm not sure I'd bother with it since ImGui is generally a debug API so the extra buffering/copying doesn't really matter...

@slembcke

As I understand it, imGUI has one big vertex/index buffer internally that it uses.

That's not the case, we have multiple buffers because they are being appended into out-of-order, then the buffers are themselves based on z-order of the windows. We also need the multiple meshes to support 16-bit indices. We could in theory have a single vertex buffer and multiple index-buffer if we enforced 32-bits indices.

Though honestly I'm not sure I'd bother with it since ImGui is generally a debug API so the extra buffering/copying doesn't really matter...

If we are talking 200~300 KB worth of data yes it doesn't matter.
Dense and large (hi-dpi) UI with rounding and border enabled can be bigger but an incoming patch will reduce the vertex cost of rounding and borders.

_EDIT_
The most approachable and realistic improvement would be for imgui to hold N-buffers (where N is specified by user) so user doesn't need to do a RAM>RAM>GPU copy in the case of multi-frame pipeline, only RAM->GPU.

This thread hasn't seen any activity in a while, but I want to also vote for having a C++ approach of the type context.Button(...) and it seems to me that from the point of refactoring the code to have this would be easier than passing the context as an argument. The reason being that, roughly speaking, one can substitute class ImGui for namespace ImGui and the GImGui global variable becomes a member of the class and compilation goes on without trouble for all the functions that have been neatly defined with a fully qualified name ImGui::function(...). Mostly a few issues exist. All the static functions will have to be declared in the include file and the word static removed. They can be declared as private methods.

For context, I am new to ImGui, but I have a scientific computing app where it is the perfect type of quick-to-implement interface to the visualization. I do need to be able to open multiple windows each with their own GUI attached to the object they contain and not a global object. That is the reason I looked for a thread discussing global variables and found this one.

@ocornut , this is a great and impressive library!

For my immediate use, I will create my own branch where I will make a class.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

noche-x picture noche-x  ·  3Comments

bogdaNNNN1 picture bogdaNNNN1  ·  3Comments

KaungZawHtet picture KaungZawHtet  ·  3Comments

dowit picture dowit  ·  3Comments

ILoveImgui picture ILoveImgui  ·  3Comments