ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.75k stars 10.17k forks source link

Opportunity to use point sampler in the shader. #3590

Open obfuscate opened 3 years ago

obfuscate commented 3 years ago

Version/Branch of Dear ImGui:

Branch: tables branch (a53ee5ec6374eed149846dd340eb171ca9ddd8ba) merged into the docking branch (3d4af15d1d5f5d3746b69859308949c357e0c21e)

Back-end/Renderer/Compiler/OS

Back-ends: we use custom abstract render interface, but it looks like d3d11 implementation. Compiler: doesn't matter Operating System: doesn't matter

My Issue/Question:

I want to add an opportunity to use point filtering (and save linear filter for usual rendering) for some textures in the imgui's shader, for example, to implement such tools like a magnifier (where is important to see pixels clearly).

To implement it, I have merely extended ImDrawListFlags_ adding a new flag constexpr int ImDrawListFlags_PointFiltration = 1 << 31; in our imgui_integration.hpp file (I did it because we use imgui as the third party and it wasn't comfortable to patch).

After it, in the ImGui_ImplDX11_RenderDrawData I just check a new flag and pass a new constant to the shader, which selects a sampler.

What do you think about this approach? Is it ok and lies in the imgui's logic or may be here exist more right solution?

It seems there is a way to use callbacks, but be honest such approach doesn't look fine some reasons.

Screenshots/Video before: linear filtering magnifier after: point filtering magnifier

ocornut commented 3 years ago

Hello,

Nice looking magnifying glass :)

Using callbacks is totally fine and the intended way to pass custom information to your renderer. What’s the issue with using them?

Moreover to make sense your approach would need to store flags in the ImDrawCmd not ImDrawList otherwise you are enforcing a constraint that those render state cannot be changed within a draw list.

obfuscate commented 3 years ago

Using callbacks is totally fine and the intended way to pass custom information to your renderer. What’s the issue with using them?

The main problem is our implementation of Command Lists (RCC) for render backend. We have many RCCs, which are filled in a parallel way and later parsed in the render thread. It lead us to the right order of submitting these contexts. Unfortunately, the place where we draw (fill ImDrawList) the magnifier hasn't got a RCC. Of course, it is possible to create it, but then we will get a problem how to correctly submit the rcc and don't break the current order.

It seems, that I may use drawList.AddCallback(nullptr, &data);, but then there will be a problem how to interpret this in a general way.

Moreover to make sense your approach would need to store flags in the ImDrawCmd not ImDrawList otherwise you are enforcing a constraint that those render state cannot be changed within a draw list.

Yeah, you are right, but it seems ImGui allows to create an additional draw list and attach it to another draw list.

ocornut commented 3 years ago

It seems, that I may use drawList.AddCallback(nullptr, &data);, but then there will be a problem how to interpret this in a general way.

I don't quite understand your explanation above. What doesn't work with drawList.AddCallback(DrawCallback_SetTextureSampling, &value); ? It's essentially storing data for the render function to interpret, which seems identical in spirit to your solution.

obfuscate commented 3 years ago

What doesn't work with drawList.AddCallback(DrawCallback_SetTextureSampling, &value); ?

So, your documentation says: // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. => DrawCallback_SetTextureSampling will be the same as and usual code pass + set texture sampling. It maybe ok, but the main problem is RCC. Even if value will store a created rcc, there is a problem with submit order. If the created RCC's order is less than main ImGui RCC's order, it will mean that firstly we draw such callback (in our case it will be the magnifier) and after it we will draw the whole imgui (and it will wipe the magnifier). If the created RCC's order is bigger than main ImGui RCC's order, then we will get a situation when the whole ImGui will be rendered and only after it we will draw the magnifier (=> the magnifier will be the topmost over any gui interfaces, like popup and etc).

ocornut commented 3 years ago

DrawCallback_SetTextureSampling will be the same as and usual code pass + set texture sampling.

No! The callback only changes some state in your renderer. You will likely push:

This is the approach many use. In fact, the game I programmed http://www.thedragonstrap.com is 100% rendered using this technique, via ImDrawList using draw callbacks for graphics state change (blending etc.). I don't mind the tools, I mean the actual game.

I don't understand anything about your RCC explanation. Wherever you perform the loop to render ImDrawCmd you can surely alter your GPU render state. The callback mechanism is merely a way to pass data to your render loop.