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

Partially re-rendering the UI, is that possible? #1398

Open
valeriansaliou opened this issue Nov 17, 2020 · 2 comments
Open

Partially re-rendering the UI, is that possible? #1398

valeriansaliou opened this issue Nov 17, 2020 · 2 comments
Labels

Comments

@valeriansaliou
Copy link

valeriansaliou commented Nov 17, 2020

Hello,

First of all, many thanks for Conrod. We're using it to build the MakAir open-source medical ventilator user interface. Our ventilator is currently being tested in an hospital on human patients, and Conrod helps doctors visualize and configure the ventilation from a touchscreen UI. Project link: https://github.com/makers-for-life/makair-control-ui

We're running Conrod on a RPi 4, at 30 FPS. We're drawing 2 ventilation graphs, updating them at 30 FPS (they slide from right to left as time goes on).

Most often (99.9% of the time), only the graph area changes and requires a refresh / redraw, while other parts of the UI (the top, the right side and the bottom side), do not need as frequent of a refresh (see this picture for details).

The 2 graphs are being plotted by plotters, over which I've built a custom Conrod rendering backend library, as plotters-conrod. This means that the 2 graphs are also fully managed by Conrod as a tree of native Conrod widgets.

We have made some measurements and tuning as to reduce our current CPU impact (which is ~40% of 1 ARM core being constantly used on the RPi, at 30 FPS). We've measured that rendering the 2 graphs consumes around 25%, while rendering the rest of the UI consumes approximately 15% of 1 CPU core, all that at 30 FPS with a full redraw at every frame.

This works out well, but is not super efficient, as a lot of "static" widgets still get re-rendered at every frame due to the graphs progressing and forcing a redraw. We could easily cut 15% of CPU usage (not accounting for the GPU usage which we did not measure).

Which gets me to those questions:

  • Would there be a way to re-draw only a widget and its children ? (the graphs widgets in our case)
  • Could it be possible to create a way for the UI to be split in “containers" where each of those containers would hold its individual "needs_redraw" state?
  • Or, would it be possible as an alternative, to initiate 2 Conrod contexts, and render them to the same window / OpenGL context, painting the frequently refreshed Conrod context over the less-frequently refreshed one, and only clearing a rectangular section of the window?

Also, I've noticed that, apart from the CPU time spent re-rendering the Conrod primitives that make up the graph, most of the 15% CPU time spent on redrawing other static elements of our UI is held by Text widgets rendering, and Image widgets rendering. It looks like Canvas and Rectangle widgets consume north to nothing, while Text widgets are noticeably "heavy". That was measured by tracing where did the CPU spent its time using Xcode Instruments on MacOS

Thanks in advance, happy to help / PR anytime if that's needed,

Valerian.

@alvinhochun
Copy link
Collaborator

I don't think Conrod was ever designed with partial redraw in mind. Conrod simply gives you a collection of primitives and a renderer backend produce lists of triangles to be drawn on the GPU. This uses the full widget graph. Maybe with some clever hacking you can get it to work with a partial tree, but I'm guessing it would become a mess that cannot be upstreamed.

If you would like to only redraw your custom stuff on a specific widget rect, I suppose you can always just get its bounds, call glScissor, and just render inside of it without redrawing the rest of the Conrod UI, provided that no other Conrod widgets are overlaid on top of your area.

Regarding CPU usage, you might have noticed that Conrod is using f64 for coordinates, which is overkill really (see also #1113). I wonder if replacing it with f32 would give you much improvements.

Texts are definitely heavier than other primitives because they need to calculate dimensions with the font metrics. Actually rendering them is also hard (the provided renderers uses a glyph cache, and I think they actually use the cache in a suboptimal manner).

@valeriansaliou
Copy link
Author

Thanks for the reply. I'll try out those 2 ways to optimize. Probably starting w/ forking Conrod and changing the scalar type to f32 and see if it is lighter for the FPU in the RPi.

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

No branches or pull requests

2 participants