Text Box Speed Issue

Started by MoLAoS, 07 July 2015, 05:58:09

MoLAoS

I am having an issue where textboxes displaying any more than a trivial amount of information are taking a long time to load. They also take a longer time to move the scroll bar, thus making it all jittery and basically useless. Can you think of why this might be? I've used a custom wxwidgets GUI that had tool tips and text boxes loaded with vastly more text than the stuff causing my current issue, so it seems like something specific to TGUI or at least SFML.

texus

The TextBox is indeed way too slow in tgui 0.6.
Rewriting the class was one of the first things I did in tgui 0.7-dev, the performance problems should be solved there.

I once wrote this on my blog, to give you an idea how much better it is now:
QuoteI am almost done with rewriting TextBox, so it is time to do some performance tests. The new code is 1000 lines shorter (1600 instead of 2600), supports word wrap and fixes all performance problems.

With 100.000 characters, there was still no visible delay when inserting text (but the fps dropped to 30 while typing). Going over 250.000 characters started showing visible performance issues.

So in normal situations (a few hundreds or even thousands of characters) you should have absolutely no performance problems.

Just as a comparison: the old TextBox didn't handle more than 500 characters very well.

MoLAoS

So I guess the real question then is how much of a hassle it will be to switch to 0.7. I don't foresee cracking 100k characters so hopefully the issue will be resolved permanently. Then I'll just have to wait for Tooltips.

texus

There is at least one big breaking change still coming in v0.7-dev, the whole loading system is being rewritten. So if you wait on that you only have to change your code once instead of twice. But it is hard to foresee how long it will take before the change is finished (currently expected to be finished before the end of this month).

If I change widgets then the changes are usually pretty small, so the operations you do on the widgets probably won't have to change much. The way you create the widget and add it to the gui however is something that is very different in 0.7 (and will be different once more after the new loading system is done), so this requires changing every widget. Also the entire callback system is different in v0.7-dev as well (so all bindCallback lines have to be changed and callbacks can't be polled anymore).

I only have short-term plans (the changes I want to make up till v0.7-alpha), so I don't even know myself which changes will be made between alpha and final release. So technically many more breaking changes might be made before reaching beta phase (it is only after this point that I start actively recommending tgui 0.7 over 0.6). Although I doubt there will be many really big changes after this new loading system is done.

So changing to v0.7-dev might take some effort, you should decide for yourself if the new features in 0.7-dev are worth the effort. A better textbox and a tooltip class are just a few of the many small improvements.

MoLAoS

Quote from: texus on 07 July 2015, 15:54:21
There is at least one big breaking change still coming in v0.7-dev, the whole loading system is being rewritten. So if you wait on that you only have to change your code once instead of twice. But it is hard to foresee how long it will take before the change is finished (currently expected to be finished before the end of this month).

If I change widgets then the changes are usually pretty small, so the operations you do on the widgets probably won't have to change much. The way you create the widget and add it to the gui however is something that is very different in 0.7 (and will be different once more after the new loading system is done), so this requires changing every widget. Also the entire callback system is different in v0.7-dev as well (so all bindCallback lines have to be changed and callbacks can't be polled anymore).

I only have short-term plans (the changes I want to make up till v0.7-alpha), so I don't even know myself which changes will be made between alpha and final release. So technically many more breaking changes might be made before reaching beta phase (it is only after this point that I start actively recommending tgui 0.7 over 0.6). Although I doubt there will be many really big changes after this new loading system is done.

So changing to v0.7-dev might take some effort, you should decide for yourself if the new features in 0.7-dev are worth the effort. A better textbox and a tooltip class are just a few of the many small improvements.

I can't afford to mess with the tiny capacity textboxes in v0.6. They are soul crushingly painful to handle and I'm barely putting 1/10 of the expected characters in them as it is.

One thing I would like to know though is, is there an actual tutorial on the new callbacks? The documentation doesn't seem to have it. All the rest of the errors I got after switching appear to be relatively easy to fix, mostly ctrl+r stuff after searching my files with TextCrawler.

Also, do you know what kind of change the loading system will have compared to the current 0.7?

texus

Quoteis there an actual tutorial on the new callbacks?
Yep, all v0.7-dev tuturials can be found here (although there currently aren't many tutorials).
The tutorial for the callback system is split in three parts:
Introduction to signals
Unbound parameters in signals (limited compiler support)
connectEx function (alternative to unbound parameters)

The new loading system uses theme classes. So you first have to create a Theme object and then use that to load your widget. This allows widgets to be connected by the theme to easily make changes that appear on all widgets or even completely reload all the widgets with a different skin.
Code (cpp) Select
tgui::Theme::Ptr theme = tgui::Theme::create("TGUI/widgets/Black.txt");
tgui::Button::Ptr button = theme->load("Button");
gui.add(button);

MoLAoS

Quote from: texus on 07 July 2015, 17:46:04
Quoteis there an actual tutorial on the new callbacks?
Yep, all v0.7-dev tuturials can be found here (although there currently aren't many tutorials).
The tutorial for the callback system is split in three parts:
Introduction to signals
Unbound parameters in signals (limited compiler support)
connectEx function (alternative to unbound parameters)

The new loading system uses theme classes. So you first have to create a Theme object and then use that to load your widget. This allows widgets to be connected by the theme to easily make changes that appear on all widgets or even completely reload all the widgets with a different skin.
Code (cpp) Select
tgui::Theme::Ptr theme = tgui::Theme::create("TGUI/widgets/Black.txt");
tgui::Button::Ptr button = theme->load("Button");
gui.add(button);


Well somewhat annoying that all those load functions I ctrl+r to create need to go back, but thank god I don't have to do them manually one by one. The theme part is probably barely noticeable for me. So the new loading system is basically a non issue. I guess I now have to learn how to use Signal based GUIs now. Probably the new callback stuff is the most painful part. I had my something like 400 lines of callbacks all set up :'( Well that size is gonna double or triple, so if the new system requires less lines it might be a good thing in the end.

MoLAoS

My game is currently returning Inferior 1 (process 8688) exited with code 03; This is not something my program itself would return, it seems it must come from TGUi or SFML. Have you ever gotten any times when you returned 03?

texus

#8
No, but you should just try to debug it and see on which line it returns exactly.

Edit: Possibly because tgui couldn't find something. TGUI v0.7-dev uses exceptions for error handling, you should try putting a try-catch block around your code in main like this. Normally you see the contents of the exception in your terminal when you don't put any try-catch, but perhaps it isn't printing it on certain systems.
Code (cpp) Select
int main()
{
    try {
        /* code */
    }
    catch (tgui::Exception& e) {
        std::cerr << "Exception caught: " << e << std::endl;
    }
}

MoLAoS

Quote from: texus on 07 July 2015, 18:57:39
No, but you should just try to debug it and see on which line it returns exactly.

Edit: Possibly because tgui couldn't find something. TGUI v0.7-dev uses exceptions for error handling, you should try putting a try-catch block around your code in main like this. Normally you see the contents of the exception in your terminal when you don't put any try-catch, but perhaps it isn't printing it on certain systems.
Code (cpp) Select
int main()
{
    try {
        /* code */
    }
    catch (tgui::Exception& e) {
        std::cerr << "Exception caught: " << e << std::endl;
    }
}


It appears that the function causing the issue is the GUI's ::add(); function. I commented shit out until it worked, create() on a panel worked, but as soon as I uncommented ::add(); suddenly the program exits with 3.

The try catch you posted complain: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'.

texus

#10
Yeah, I made a typo. It shouldn't print "e", but "e.what()".
Perhaps change "tgui::Exception" into "std::exception" to catch any exception since I don't think the add function throws any tgui exceptions.

Edit: Are you sure you aren't passing a nullptr to gui.add?

MoLAoS

Quote from: texus on 07 July 2015, 19:17:08
Yeah, I made a typo. It shouldn't print "e", but "e.what()".
Perhaps change "tgui::Exception" into "std::exception" to catch any exception since I don't think the add function throws any tgui exceptions.

Edit: Are you sure you aren't passing a nullptr to gui.add?

Apparently, I was using widget->create() instead of widget = tgui::WidgetType::create(); The second option allows the program to progress while the first causes the problem of the program terminating.

Also neither tgui::Exception nor std::exception caught anything from the function. Presumably cause it was a null pointer.

texus

Since 'widget' is an uninitialized pointer before the static create function creates one, you are indeed calling a function on a nullptr. This is undefined behavior and normally leads to an immediate crash. But it seems that since the create function doesn't access any member variables it doesn't access this nullptr so it silently works (but it crashes later on in this case since it doesn't initializes the widget, it just returns a newly created one).

MoLAoS

Quote from: texus on 07 July 2015, 19:33:37
Since 'widget' is an uninitialized pointer before the static create function creates one, you are indeed calling a function on a nullptr. This is undefined behavior and normally leads to an immediate crash. But it seems that since the create function doesn't access any member variables it doesn't access this nullptr so it silently works (but it crashes later on in this case since it doesn't initializes the widget, it just returns a newly created one).

Well, I was just used to the old system with constructors. In any case everything works fine now except I misplaced a couple widgets and I have to redo stuff for the new callback system. Well and my tabs seem to have the wrong text size. Other widgets have proper sizes.

texus

Quotemy tabs seem to have the wrong text size
The tab class has gone through several internal changes in the last year. If you can't figure out the problem yourself then you should try to provide some minimal code that has this problem.

MoLAoS

Quote from: texus on 07 July 2015, 20:30:21
Quotemy tabs seem to have the wrong text size
The tab class has gone through several internal changes in the last year. If you can't figure out the problem yourself then you should try to provide some minimal code that has this problem.

Not important. The real issue I have is the signals thing. I wrote:
countryPicture->connect("pressed", mapManager->setPlayerNation());

However the function wants either an int or a Nation*. I tried:
countryPicture->connect("pressed", mapManager->setPlayerNation(), mapManager->getNation(i)));

But the function always says it needs an argument. I also tried a few things google popped up but didn't help much. If you put the argument in the braces it says invalid use of void function.

texus

What you are doing is call setPlayerNation and pass the return value of the function (void in this case) as parameter to the connect function.

It should be like this (assuming mapManager is an object of type MapManager)
Code (cpp) Select
countryPicture->connect("pressed", &MapManager::setPlayerNation, mapManager);

Since the function takes an int you actually have to do this:
Code (cpp) Select
countryPicture->connect("pressed", &MapManager::setPlayerNation, mapManager, mapManager->getNation(i));

But this will call getNation immediately and call setPlayerNation with a copy of that int. So if the nation changes after calling the connect function then the value passed as parameter isn't changed. So instead you could bind that function call so that getNation gets called when the setPlayerNation is being called.
Code (cpp) Select
countryPicture->connect("pressed", &MapManager::setPlayerNation, mapManager, std::bind(&MapManager::getNation, mapManager, i));

You should read the "Connecting member functions" section on this page for a good explanation on how to bind member functions.

You might also want to look up how std::bind works. If you hesitate how the parameters of the connect function are supposed to be, all the parameters after the first string are just directly passed to std::bind so if you know how it works then you also know what to pass to the connect function. With the exception that you can pass less parameters to the connect function which leads to trying to bind them internally.

MoLAoS

#17
Okay, its working now.

MoLAoS

Quote from: texus on 07 July 2015, 11:45:29
The TextBox is indeed way too slow in tgui 0.6.
Rewriting the class was one of the first things I did in tgui 0.7-dev, the performance problems should be solved there.

I once wrote this on my blog, to give you an idea how much better it is now:
QuoteI am almost done with rewriting TextBox, so it is time to do some performance tests. The new code is 1000 lines shorter (1600 instead of 2600), supports word wrap and fixes all performance problems.

With 100.000 characters, there was still no visible delay when inserting text (but the fps dropped to 30 while typing). Going over 250.000 characters started showing visible performance issues.

So in normal situations (a few hundreds or even thousands of characters) you should have absolutely no performance problems.

Just as a comparison: the old TextBox didn't handle more than 500 characters very well.

I just want to say that the new textbox is working like magic. Thank you so much. I hate having to spend my day off redoing callback stuff but in the end the superior textbox performance is worth it. The v0.6 textbox performance was a showstopper.