r/programming • • 2d ago

Rewriting an entire UI in Rust

https://gitcherrytree.com/blog/rewriting-the-ui-in-rust/
1 Upvotes

9 comments sorted by

19

u/chucker23n 2d ago

One would think, that the software known as Windows, would be good at managing windows. One would, of course, be wrong.

This was surprisingly hard!

By default, you get black bars on resize, and issues besides. To fix this, I had to do:

DirectX only. Everything else calls DirectX to do resizing which breaks sync.

I'm confused by this part. It sounds like they're trying to do their own UI framework. If you want DirectX-based, there's already WPF and WinUI.

Black bars on resize sounds like a classic issue double-buffering would solve, but you don't really need that in a modern compositing UI framework.

4

u/SpecialBread_ 2d ago

this may be an issue with winit, which a lot of the rust ecosystem is using for their uis. it provides the window for you and then its your job to write the code to draw a texture into it.

windows terminal, obsidian, and brave browser all have white bars for me, and ive seen this in other non rust apps too, so it seems like you need to do some work to get it right, or at least i did!

there is also this interesting situation where i think it depends on which monitor the window is on, too! it works well on the side monitor but not my main one, crazy!

3

u/danielcw189 2d ago

this may be an issue with winit, which a lot of the rust ecosystem is using for their uis. it provides the window for you and then its your job to write the code to draw a texture into it.

So you aren't really using Windows to manage your Windows? How much does winit abstract away? and how much if the Windows API can you reach? and how much do you have to reach?

windows terminal [...] have white bars for me

which white bars do you mean exactly?

3

u/SpecialBread_ 2d ago

windows does manage the window - i use the windows api, so windows owns the window, drag to move and aero snap go straight to DefWindowProc, minimise and maximise and the taskbar are all windows.

the winit library gives you the handle to the window, and i cut out the bits i didnt need to drive it directly but you can call anything the windows api provides. i think i ended up with a dozen win32 calls or so, and needed to arrange them all very carefully to get something like the window showing up without flickering on launch, which windows explorer flickers like crazy for me.

on the white bars - when you resize a window via drag, you get gaps at the edge. for me this happens on most but not all programs, and interestingly is not present on all my monitors. since this also includes microsoft apps, i assume its not just because im holding it wrong. though i could be!

i solve this issue by making sure i synchronously drive the window resizing process. there are several ingredients i had to get right:
1. set the swapchain's max frame latency to 1, so present blocks until the compositor has taken the previous frame. otherwise the present and the resize can land in different compositor frames, and you get the previous frame stretched to fit, or the gap filled with a default colour - hence the black/white bars
2. use directx since other renderers on windows call directx to get sizes so that latency is enough to break your synchronized code
3. resize the swapchain, draw the new frame at that size, and wait for the gpu to actually finish it
4. present, then tell windows to resize the window, with nothing in between

there are some more parts i missed out here, and i found deleting any of them results in black bars, or ghosting caused by the previous frame being in the buffer

its i guess pretty involved so hopefully that makes sense!

1

u/danielcw189 2d ago

thanks for the reply. somebody else downvoted your comment. I don't want you to think it was I. I think your reply was very interesting and thorough.

Interesting, so you actually drive your window manually the old fashioned way, except you are using directX. I have never done a windows desktop application with directX.

on the white bars - when you resize a window via drag, you get gaps at the edge. for me this happens on most but not all programs, and interestingly is not present on all my monitors. since this also includes microsoft apps, i assume its not just because im holding it wrong. though i could be!

I get what you mean now. No idea how unavoidable it is under WDM and when using directX. Maybe WDM actually has an API function that helps with that.

and interestingly is not present on all my monitors

different GPUs and/or refresh rates? (or different DPI?)

  1. resize the swapchain, draw the new frame at that size, and wait for the gpu to actually finish it

that sounds expensive, and would happen multiple times per second while your window is being resized

1

u/cr1mzen 10h ago

Congratulations, previously in WINUI3 the only advice i could find to mitigate glitches during resizing was “it’s too hard”.

0

u/chucker23n 2d ago

windows terminal, obsidian, and brave browser all have white bars for me, and ive seen this in other non rust apps too, so it seems like you need to do some work to get it right, or at least i did!

there is also this interesting situation where i think it depends on which monitor the window is on, too!

I haven't seen that in Windows Terminal on multiple machines, so I think there's just something wonky with your graphics driver.

6

u/daltorak 2d ago

You didn't cover memory usage, which should always be considered when switching to (or from) a web-based framework to something native. How are things looking on that front?

1

u/SpecialBread_ 2d ago

on memory usage its not too different, i guess its true i forgot to cover that, to me there was not a huge issue with memory though i did have to be careful with it on the react side of things.

With Iced memory usage is lower since I cache some stuff to load it faster the next time. and that is scaled with the repo size, where on a 300k file/40gb repo its a couple hundred mb in total. all that is on the backend though so the ui isnt affected.

the ui is generally memory light though commit and file diffs can get large. there rust is nicer, since js had about 5-10x overhead compared to the file size its viewing. that said, i had reduced that to 1.5x overhead so about 60mb for opening a 40mb file diff (i.e. 1m lines of text)

most files are much smaller than that or binary, so the memory pressure was not something i dealt with.

Since here i was moving from tauri to rust, and half of tauri is rust already i didnt have a huge footprint overall.

so: id say it wasnt a big deal, though with a rust ui i had to think about it less by default.