Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: SFGUI (0.4.0 released)  (Read 391661 times)

0 Members and 8 Guests are viewing this topic.

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #135 on: November 10, 2011, 06:31:55 pm »
I'm able to reproduce it and already know where the problem is. Fix will come in some minutes. ;)

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #136 on: November 10, 2011, 06:38:10 pm »
Should work now, get the latest commit.

Naufr4g0

  • Full Member
  • ***
  • Posts: 112
    • View Profile
SFGUI
« Reply #137 on: November 10, 2011, 07:03:36 pm »
Quote from: "Tank"
Should work now, get the latest commit.


That's a very good news! :D

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFGUI
« Reply #138 on: November 10, 2011, 07:30:10 pm »
Sitting on the bus here and saw a problem with threads. This would most certainly happen at the same time:

Code: [Select]
... // logic code
widget.SetPosition(...);
... // moar code

Code: [Select]
... // render code
widget.Expose();
... // moar render code


What I need is to detach the logics, have it export a state object that is transfered to the graphics. Do you think it would take a lot of effort forking SFGUI and implement that?

I can't do everything trough messages as I first thought because the widget will have to send data back.And the architecture I have won't allow that and for good reasons.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #139 on: November 10, 2011, 07:47:23 pm »
I'm not sure if I got you right. What do you mean by "happen at the same time"?

Can you make a little sequence diagram or something to illustrate the process? (hasn't to be graphical, ASCII/text is fine ;))

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFGUI
« Reply #140 on: November 10, 2011, 08:19:45 pm »
Don't know how I would illustrate it... hmmm

Code: [Select]

Logic                                                  renderer
   |                                                       |
   |                                                       |
 Renderer.CreateWidget( widget );  ->  queue               |
   |                                                    process messages
   |                                                              receive ptr to widget
 sometime in the future                                    |
   |                                                       |
   |                                                       |
 widget.SetPosition();                                widget.Expose();
   |                                                       |
   |                                                       |
 restart loop                                         restart loop

Well the SetPosition can be anything really, even several modifications. What I'm trying to say that I can be messing with data the widget is trying to read while it's rendering and eventually mess things up. Let's say I SetPosition to 400,300 and the logics thread manages to write the x position then it's position would be 400,0 and then expose is called and renders to that position. That's a mild error and not so serious. It becomes worse if I delete the widget and then send a message to remove it from the graphics side. Then it would be trying to render an object that does not exist anymore.

And why I can't use messages are because I would need to send back information that a widget has been clicked on, hovered above and stuff like that. I make the renderer the logic threads bitch which simplifies and optimizes the synchronization a lot. And well anyone familiar with Amdahl's law should know why that is necessary.

What I am thinking that I'll modify is that I detach input, logics and data from a widget into a separate class which can export a state class the original widget class can read and then render accordingly.

Code: [Select]

class WidgetState
{
public:
    GDE::AnyType GetParameter( const std::string &aName );

private:
    std::map< std::string, GDE::AnyType > myParameters;
};

class WidgetLogics
{
public:
    virtual const WidgetState *GetState() const;
};

class Widget
{
public:
    virtual WidgetLogics *DeattachLogics();

    virtual void ReadState( const WidgetState *aState );
};


Just a basics of what I'm thinking. The widget itself will still contain the logics so it can function entirely like originally intended but you can also deattach the logics from it and handle it separately and then you transfer the changes with the WidgetState class. When the Deattach function is called then the Widget looses all reference to the logics and will not do anything anymore no matter what. It can only be modified by the state interface after that.

I'm not requesting that you do it! I'm just thinking that I'll fork your project and modify it so that it becomes... well more of a MVC like architecture to the functionality that is already there.

Maybe you got some pointers?
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #141 on: November 10, 2011, 08:32:20 pm »
Quote
I'm not requesting that you do it! I'm just thinking that I'll fork your project and modify it so that it becomes... well more of a MVC like architecture to the functionality that is already there.

Yeah that's how I understood it, too. I just wanted to understand your problem. :)

Don't you think your design is a little bit too complicated? MVC is a popular design pattern, but IMHO it's not always a good idea to separate everything. My suggestion is to take the GUI as a big view unit in terms of MVC, and not separate further. (just suggestions, of course)

Logic in SFGUI is and should keep fixed and mostly internal, that's why a GUI can be mostly understood as being a pure view.

When it comes to multi-threading, you have to pay attention at several things, of course, but there should not be more than one instance managing it. If that's the case, you don't have to bother with sync issues at all.

If you really want to follow your approach, it will be a bunch of work. Can be done, e.g. by creating messages for every type of action the widgets can perform. But again I think it's just adding an unnecessary layer of abstraction with little to no benefit.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFGUI
« Reply #142 on: November 10, 2011, 08:40:56 pm »
Quote from: "Tank"
Don't you think your design is a little bit too complicated?
It probably is but that's the best I could come up with that would let me easily separate input and logic from the rendering.
Correction: I meant work with it easily as two separate things.

Quote from: "Tank"
MVC is a popular design pattern, but IMHO it's not always a good idea to separate everything. My suggestion is to take the GUI as a big view unit in terms of MVC, and not separate further. (just suggestions, of course)
I agree and I'm not doing a MVC pattern over it, I said MVC like because it's the closest resemblance.

Quote from: "Tank"
Logic in SFGUI is and should keep fixed and mostly internal, that's why a GUI can be mostly understood as being a pure view.
The scenario I'm worried about is that I have the logics at the main thread, the rendering of the widget in a separate thread. An event is fired, the user has clicked on the widget and the widget starts handling it and the internal state of the widget or another widget is changed. Before the widget is done with handling this the widget is exposed in the rendering thread. Let's say for instance I have a button I press on and when pressed itself, or any other widget, changes text or any other attribute. That would be very very bad.

I hope that's clear enough what the underlying problem is :D
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #143 on: November 10, 2011, 09:13:02 pm »
Well if that's your only concern, it should be very easy to implement. Just dispatch a message in the signal handlers of the widgets and you're good to go. :)

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFGUI
« Reply #144 on: November 10, 2011, 09:27:14 pm »
Quote from: "Tank"
Just dispatch a message in the signal handlers of the widgets
back to the logic thread? Making my synchronization point more complex is not desirable. I would like to see that as a last resort. The application will only be as fast as it's slowest synchronization point. Serial code is evil :twisted:

I was also thinking that the GUI could be completely on the logic side, be rendered to a double buffered structure of render textures which are swapped at synchronization(which will be a lot faster than messages) and it would let the graphics thread focus more on game graphics. I can only see it as a problem if I become CPU bound but then I can come up with some nifty solutions to parallel the GUI as well along side the logic calculations. Though that would mean that all the game logics would have to wait and depend on the GUI? But it probably would have to do that anyway.

ah trade off's trade off's. Notice how I like to talk to reach solutions? ^^ Sorry if I've bothered you too much with none essentials.

Anyway the library looks great, easy to integrate and stable. Best thing is that I won't have to mess around in the GUI code or reinvent the wheel :D
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Tank

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1486
    • View Profile
    • Blog
    • Email
SFGUI
« Reply #145 on: November 11, 2011, 08:13:01 am »
The biggest problem seems to be that your application is rather complex in its design, so it's hard to follow what you actually want to do in detail. ;)

I don't think you need to move the GUI to a separate thread. The most time-consuming actions in SFGUI are:
  • Size requests lead to recalculations of requisitions (the minimum size required by a widget) and allocations (position and size given to a widget). For example if you resize a window, its allocation is changed and all widgets recalculate their childrens' positions and sizes.
  • Exposing, i.e. rendering the widgets. The most calls happen here (Expose() on ALL visible widgets and, of course, OpenGL calls).
  • Event handling, because events are delegated down the whole hierarchy.


Size requests and allocations only happen if the geometry changes, so this can mostly be ignored for performance issues. Exposing is a must-have, else you won't see anything. ;) However we haven't ran into performance issues yet. Event handling is also a must-have, except you only want visuals. :)

The only thing that could be moved to a separate thread are the position and size operations. Those are mostly triggered through events, therefore you COULD move HandleEvent() to a separate thread.

But I encourage you to try it out serially at first and see if performance is okay for you. The extra load of synchronization and stuff may not be worth.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
SFGUI
« Reply #146 on: November 11, 2011, 03:07:22 pm »
Quote from: "Tank"
The biggest problem seems to be that your application is rather complex in its design, so it's hard to follow what you actually want to do in detail. ;)
It's not that complex, but it might appear complex if you are an outsider and the code is not even available, I have a state stack, a loading thread, a rendering thread and the synchronization point for rendering(loading uses mutexes instead, was easier and acceptable since it's not at runtime it's used).
Quote from: "Tank"
I don't think you need to move the GUI to a separate thread.
I don't think so either, if you remember I said
Quote from: "Groogy"
if I become CPU bound
I never try to do anything optimized without having real numbers from test benchmarks showing that it will really work.

Make it work, Make it right, Make it fast is a very good mantra.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
SFGUI
« Reply #147 on: November 11, 2011, 04:28:42 pm »
Quote from: "Groogy"

Make it work, Make it right, Make it fast is a very good mantra.


Which is how we implement new features in SFGUI too. :)

As Tank said, how it is now I'd say the computation time ratio between HandleEvent() and Expose() is probably <1/99 and both make up almost all the time the library needs. Separating event handling and rendering into 2 different threads won't help much unless you plan on passing many MANY events to the library. In that case I would seek the source of the problem elsewhere ;).

The only way you can make SFGUI less of a bottleneck is therefore by speeding up Expose(). Since I've been optimizing the performance of the library lately, I can tell you that SFGUI isn't even the culprit of the long time spent in Expose(). In fact 1 level down the calltree and you'll only find calls to SFML which is where Expose() lingers for almost all of it's time. Since SFML renders through OpenGL it also wouldn't make sense to try to optimize there. As explained nice and short here: http://www.opengl.org/wiki/OpenGL_and_multithreading if you only have 1 GPU all the calls to GL from multiple threads will end up in 1 queue anyway, thereby wasting any effort to render from different threads.

The #1 bottleneck is therefore SFML and it relies on GL calls which don't make sense to separate into multiple threads. If you want a performance increase with SFGUI I would rather talk to Laurent first than try to parallelise everything you can in SFGUI. If he can reduce the amount of GL calls per shape/text trust me, you won't have performance issues with SFGUI ever again ;).

As always I let numbers speak for themselves. Here is the top 10 list from the flat gprof profile of Test.cpp:
Code: [Select]

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total          
 time   seconds   seconds    calls  ms/call  ms/call  name
  9.08      0.82     0.82 16418394     0.00     0.00  sf::Renderer::ProcessVertex(float, float, float, float, float, float, float, float)
  9.08      1.64     0.82                             tt_cmap4_char_map_binary
  7.25      2.29     0.66   175952     0.00     0.03  sf::Text::Render(sf::RenderTarget&, sf::Renderer&) const
  6.31      2.87     0.57 16418394     0.00     0.00  sf::Matrix3::Transform(sf::Vector2<float> const&) const
  6.09      3.42     0.55                             tt_face_get_kerning
  4.87      3.85     0.44  3419834     0.00     0.00  sf::Texture::GetTexCoords(sf::Rect<int> const&) const
  4.32      4.25     0.39 32168534     0.00     0.00  std::less<unsigned int>::operator()(unsigned int const&, unsigned int const&) const
  3.88      4.59     0.35  3421964     0.00     0.00  std::_Rb_tree(std::_Rb_tree_node<std::pair<unsigned int const, sf::Glyph> >*, std::_Rb_tree_node<std::pair<unsigned int const, sf::Glyph> >*, unsigned int const&)
  3.88      4.95     0.35  3417478     0.00     0.00  sf::Renderer::AddVertex(float, float, sf::Color const&)
  2.77      5.20     0.25 32967353     0.00     0.00  sf::Vector2<float>::Vector2(float, float)


The first SFGUI call ( Expose() ) comes at position 25:
Code: [Select]

0.72      7.03     0.07   374017     0.00     0.02  sfg::Widget::Expose(sf::RenderTarget&)
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

asdatapel

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
SFGUI
« Reply #148 on: November 11, 2011, 04:34:33 pm »
my app is using an sfgui window, and i want to be able to move it anywhere. Unfortunatly, this means that even when the gui is clicked, my program registers  it as a click, so both the gui is affected, and the thying underneath it. Is there a way to cancel out the Event is sfgui does something with it?

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
SFGUI
« Reply #149 on: November 11, 2011, 04:39:26 pm »
Quote from: "asdatapel"
my app is using an sfgui window, and i want to be able to move it anywhere. Unfortunatly, this means that even when the gui is clicked, my program registers  it as a click, so both the gui is affected, and the thying underneath it. Is there a way to cancel out the Event is sfgui does something with it?


http://www.sfml-dev.org/forum/viewtopic.php?p=41132&highlight=#41132
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).