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

Improving performance under Windows #180

Merged
merged 2 commits into from
Apr 10, 2023

Conversation

nptr
Copy link
Contributor

@nptr nptr commented Mar 27, 2023

Improving performance under Windows by dropping support for arbitrary backgrounds.

I was asked to open a PR for my patch i offered in issue #161.

libui has a container control that is (seemingly) used to provide the basic layout mechanisms. It is supposed to be transparent.
Unfortunately GDI doesn't support real transparency and things get really hacky because of this. The Win32 controls way to achieve a similar effect is to ask the parent control for the appropriate background brush (WM_CTLCOLORSTATIC) or ask to the parent to render the background for it (WM_PRINTCLIENT).

The original author chose the second route, double buffered too. This works with every background (images, gradients etc.). It hurts performance pretty hard however.

Note: I am not 100% sure if there isn't another reason why rendering is so slow. There seems to be some overdraw for example but I don't have the time to dig deeper.

The WM_CTLCOLORSTATIC route only supports solid color backgrounds. Since Microsoft doesn't use themed backgrounds since XP and most user themes also don't use gradients etc, the first approach seems to be a sufficient. This is what this PR is about. Performance is much better and there is no visual difference under the common Windows themes (Classic, Aero Basic, Aero Win7, Aero Win10).

Please have a look and let me know if it works for you just as good. I can also post some screenshots in the next few days.

  • nptr

@cody271 cody271 linked an issue Mar 29, 2023 that may be closed by this pull request
@nptr
Copy link
Contributor Author

nptr commented Mar 30, 2023

Here are the screenshots i offered. Solid backgrounds work fine and theme colors are respected.

Win 7 Aero Theme

patch_w7_aero

Win 7 Classic Theme

patch_w7_classic

Win 7 High Contrast Theme

patch_w7_highcontrast

Win 7 with Custom Theme

win7_themed

@szanni
Copy link
Contributor

szanni commented Mar 30, 2023

Very happy to see some solutions popping up here.
Loosing full transparency would be a bummer... according to the original discussions there may be other ways of fixing the performance without losing transparency (flattening hierarchy for example). But this may be a good fix for the time being.
Thanks for actually putting that into a clean and applyable patch with actually useful comments!

One quick question about the last screen shot: is the label font color not white due to the theme? Looks kind of weird as the forms elements are white.

@nptr
Copy link
Contributor Author

nptr commented Mar 30, 2023

Good catch! I'll see what's up with the label text. There is a chance I messed the WM_CTLCOLORSTATIC up.

@nptr nptr force-pushed the container_performance branch 2 times, most recently from bdd953b to cd1c95b Compare March 30, 2023 15:00
@nptr
Copy link
Contributor Author

nptr commented Mar 30, 2023

Seems like there is an expectation that the text color is set directly to the controls device context in the WM_CTLCOLORSTATIC handler. MSDN doesn't really say that this is important but only portraits it as an option in my opinion.

I added the SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT)); call and then squashed my commits, including a new commit message that more closely matches the existing ones.

Its better now:
grafik

@cody271
Copy link
Contributor

cody271 commented Mar 31, 2023

Win11 Light Theme

image

@@ -50,25 +69,46 @@ static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LP
mmi->ptMinTrackSize.x = minwid;
mmi->ptMinTrackSize.y = minht;
return lResult;

// GDI doesn't support transparency. The Win32 controls way to achieve a similar effect
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: trailing whitespace here and below (GitHub UI doesn't detect this currently)

180.patch:57: trailing whitespace.
	// GDI doesn't support transparency. The Win32 controls way to achieve a similar effect 
180.patch:62: trailing whitespace.
	// other containers. So we have to dynamically find the next control that is not a 
warning: 2 lines add whitespace errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it

Copy link
Contributor

@szanni szanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very clean to me. More lines removed than added - that's how I like things.

I tested things on my Windows 7 VM. I did not notice any regressions. Painting is a lot faster. Sadly still not instant, I guess that has to do with the delay of all the parent traversal and individual painting of controls?

Wine seems to work too.

A few things I noted that should probably be addressed in another PR but that are related and important enough to mention here:

  • The windowClassOf looks kind of wrong to me, as L"button" is used for many controls besides uiGroup, like for example actual buttons. This seemingly doesn't seem to matter though? Which makes me wonder: how much of this code is actually needed at all?
  • Another existing problem that seems to persist with these patches is the uiCombobox not getting drawn off the bat. Page4 and 16 highlight this quite nicely. It only happens when you first open the application and gets drawn once you move the mouse over it, resize the window, etc.
    screenshot

r = ps.rcPaint;
paintContainerBackground(hwnd, dc, &r);
EndPaint(hwnd, &ps);
if(!dc) break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(!dc) break;
if(dc == NULL)
break;

For consistency

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I squashed the changes with the previous whitespace fixes.

Copy link
Contributor Author

@nptr nptr Apr 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the uiCombobox: I was hoping it vanishes too but it didn't. Possibly a bad combination of window styles that result in bad ordering of the draw calls? On a second glance, it could also be a Z-ordering problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the uiCombobox: I was hoping it vanishes too but it didn't. Possibly a bad combination of window styles that result in bad ordering of the draw calls? On a second glance, it could also be a Z-ordering problem.

I've tracked this issue down somewhat.. nothing to do with uiCombobox specifcally.
Its an existing bug in uiTab page control impl: tab pages are implemented as reparented dialogs on Windows.
See the old issue with test case to reproduce: andlabs/ui#380 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything left before this PR can be merged?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope I think its ready to go, thanks @nptr

parent = parentOf(parent);
// skip groupboxes; they're (supposed to be) transparent
// skip uiContainers; they don't draw anything
cls = windowClassOf(parent, L"button", containerClass, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is from existing code and doesn't seem to affect things but L"button" is used for a lot more than uiGroup and looks wrong to me. No need for action.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be pushbuttons, radiobuttons, checkbox, commandlink and groupbox if I am not mistaken. Only groupboxes can be parents in libui and possibly in general. I also had to look at this code quite a bit, but its fine i think. Just Win32 common controls madness.

Copy link
Contributor

@cody271 cody271 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cody271 cody271 merged commit f199cd3 into libui-ng:master Apr 10, 2023
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

fix windows bad performace?
3 participants