Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] ideas on how to handle timers/user events/expose events in a widget class.

Credits go to Matthew Leverton for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
[A5] ideas on how to handle timers/user events/expose events in a widget class.
axilmar
Member #1,204
April 2001

hi all.

In my gui library, I'd like to allow widgets to start timers, put user events in an event queue, and put custom expose events in the associated display's event queue.

In order to allow widgets to start timers, widgets must have an ALLEGRO_EVENT_QUEUE* member in order to register the timer's event source to the queue.

In order to allow widgets to send user events, widgets must have an ALLEGRO_EVENT_SOURCE* member in order to use the function 'al_emit_user_event'.

In order to allow widgets to put custom expose events, widgets must have an ALLEGRO_DISPLAY* member (according to this thread).

Now my question is this: how to avoid having all these members in my widgets? is there a way in Allegro 5 to have a single pointer to <something> in a widget and do all the above? if so, what is this <something>? a queue? an event source?

How do you handle relevant cases in your GUI libraries?

Thomas Fjellstrom
Member #476
June 2000
avatar

I didn't like passing allegro events directly to my object based framework. Instead I have a bunch of methods that handle different events. The event objects themselves do take an ALLEGRO_EVENT to populate itself though.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Matthew Leverton
Supreme Loser
January 1999
avatar

axilmar said:

is there a way in Allegro 5 to have a single pointer to <something> in a widget and do all the above? if so, what is this <something>? a queue? an event source?

No, I'm not really sure how you expect that it would work in C. Or maybe I don't even understand what you're asking.

I haven't done much with Allegro events in my GUI. I don't use them internally because I use my own function-based event system. However, externally, I will probably give the programmer an option to use Allegro events.

Regarding a display pointer, I don't associate widgets directly with displays. If I really needed to know what display a widget was on, I'd have to travel up the parent nodes until I got to the root object, and then check which display owned it by a display/root pair I maintain.

For example, on a mouse move event, I cycle through each root widget owned by the display. Each widget asks itself "what widget is at X,Y" recursively until it finds its top most widget. So I always know what the display is without explicitly storing it per widget.

But I haven't implemented any optimization. If I ever get to that point, I may rethink a few things.

axilmar
Member #1,204
April 2001

Matthew, how does your GUI library handle redrawing? do you redraw the whole GUI at each frame update?

If I wanted to use your GUI not for a game, but for an application, I would not like to have my GUI being redrawn at every frame. So, in order to achieve this, I would have to manage expose events. But, in order to send expose events from widgets, I need to have a pointer to a display in each widget (or an association between a widget and a display, like the one you describe).

Now, normally, this isn't a problem. But, when I want to handle timers in widgets, each widget should also have a pointer to the event queue that will be associated with the timer.

Finally, if I want my widget to send events to an event queue, each widget must have a pointer to an event source.

Let me repeat the above in short form:

  • if I want my widgets to send expose events, each widget must have access to an ALLEGRO_DISPLAY pointer.


  • if I want my widgets to handle timer events, each widget must have access to an ALLEGRO_EVENT_QUEUE pointer, so as that the timer that is created by the widget is registered to the event queue.


  • if i want my widgets to send user events, each widget must have access to an ALLEGRO_EVENT_SOURCE pointer.

I want to avoid all the above. I want to avoid this:

#SelectExpand
1class Widget { 2public: 3 ALLEGRO_DISPLAY *getDisplay() const; 4 5 void setDisplay(ALLEGRO_DISPLAY *d); 6 7 ALLEGRO_EVENT_QUEUE *getEventQueue() const; 8 9 void setEventQueue(ALLEGRO_EVENT_QUEUE *q); 10 11 ALLEGRO_EVENT_SOURCE *getEventSource() const; 12 13 void setEventSource(ALLEGRO_EVENT_SOURCE *s); 14 15private: 16 ALLEGRO_DISPLAY *m_display; 17 ALLEGRO_EVENT_QUEUE *m_queue; 18 ALLEGRO_EVENT_SOURCE *m_event_source; 19};

So, my question is how do you handle this problem.

By the way, the above problem leads me to think that the Allegro 5 event system is not designed correctly. The core of the problem is al_emit_user_event. What is wrong with it is that user events can only be emitted on an event source. The right approach would be to put events in the event queue. If A5 was like that, I would only need this:

class Widget {
public:
     ALLEGRO_EVENT_QUEUE *getEventQueue() const;
     void setEventQueue(ALLEGRO_EVENT_QUEUE *q);

private:
    ALLEGRO_EVENT_QUEUE *m_queue;
};

But perhaps I am wrong in this; perhaps there is a way to do what I ask, and that's why I am asking for insight on this.

Matthew Leverton
Supreme Loser
January 1999
avatar

What if you want to send events to multiple queues? That's why Allegro is designed the way it is, so I wouldn't call it incorrect. Essentially, Allegro is providing the convenience layer to the owner of the event source, such that it simply has to emit an event into its source and not worry if anybody is listening.

However, I don't think it would be hard to add al_push_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *event); to A5's internals as an alternative way to populate a queue.

I redraw the entire GUI double buffered, without optimization, on every frame. This is mostly because I'm too lazy to do anything else, as opposed to any master plan. I cannot imagine that my GUI would ever end up being useful for high speed, full screen games. It is primarily designed for tool building and not real time games, so I don't really care.

axilmar
Member #1,204
April 2001

What if you want to send events to multiple queues?

Is there a use case for such a feature?

Quote:

such that it simply has to emit an event into its source

So widgets need to be aware of one or more event sources, if they want to send events themselves.

But widgets also need to know of a queue to register timers to, and I think the Allegro 5's event source abstraction breaks at this point, at least for the GUI.

Quote:

I cannot imagine that my GUI would ever end up being useful for high speed, full screen games. It is primarily designed for tool building

Actually, it is the tools that need the expose optimization, not games. Full screen games will need to redraw the whole GUI at every frame anyway.

Matthew Leverton
Supreme Loser
January 1999
avatar

axilmar said:

Is there a use case for such a feature?

I have made use of multiple things listening to the same event source on Allegro, if that's what you mean. And with HTML/JS, I do it a lot.

Could you simply pass an event source to the widget? i.e., void Widget::setEventSource(ALLEGRO_EVENT_SOURCE *s); If it is 1:1 with an event queue, it's the same thing, from the widget's perspective. If you build your source like:

then your widget can push into the event source and your listener can just use the queue.

I don't see why you think it breaks down. You need an extra object somewhere, of course, but conceptually it isn't a limitation.

axilmar
Member #1,204
April 2001

Widgets also need to know the queue, because they need to create timers. Knowing the event source is not enough.

Furthermore, there is also the case of expose events: the widget needs to know the display's event source as well.

Matthew Leverton
Supreme Loser
January 1999
avatar

axilmar said:

Widgets also need to know the queue, because they need to create timers. Knowing the event source is not enough.

You can reverse responsibilities:
al_register_event_source(widget->getTimerEventSource(), queue);

But to be honest, I'm not really sure who is creating the timer and who is listening...

Quote:

Furthermore, there is also the case of expose events: the widget needs to know the display's event source as well.

Well, really you just need the display pointer. And that's true no matter how you want to implement it.

Anyway, see if this patch helps:


Index: include/allegro5/events.h
===================================================================
--- include/allegro5/events.h	(revision 15029)
+++ include/allegro5/events.h	(working copy)
@@ -260,6 +260,8 @@
 AL_FUNC(bool, al_wait_for_event_until, (ALLEGRO_EVENT_QUEUE *queue,
                                         ALLEGRO_EVENT *ret_event,
                                         ALLEGRO_TIMEOUT *timeout));
+AL_FUNC(void, al_push_event, (ALLEGRO_EVENT_QUEUE *queue,
+                              const ALLEGRO_EVENT *event));
 
 #ifdef __cplusplus
    }
Index: src/events.c
===================================================================
--- src/events.c	(revision 15029)
+++ src/events.c	(working copy)
@@ -565,8 +565,11 @@
    _al_mutex_unlock(&queue->mutex);
 }
 
+void al_push_event(ALLEGRO_EVENT_QUEUE *queue, const ALLEGRO_EVENT *event)
+{
+   _al_event_queue_push_event(queue, event);
+}
 
-
 /* contains_event_of_source:
  *  Return true iff the event queue contains an event from the given source.
  *  The queue must be locked.
Index: examples/ex_user_events.c
===================================================================
--- examples/ex_user_events.c	(revision 15029)
+++ examples/ex_user_events.c	(working copy)
@@ -65,6 +65,13 @@
    al_init_user_event_source(&user_src);
 
    queue = al_create_event_queue();
+
+   user_event.user.type = 666;
+   al_push_event(queue, &user_event);
+   if (al_get_next_event(queue, &event)) {
+      printf("Got an event of type %d\n", event.type);
+   }
+
    al_register_event_source(queue, &user_src);
    al_register_event_source(queue, al_get_timer_event_source(timer));

It adds al_push_event(*queue, *event). Note that it makes a copy of the event, so normal usage would be to declare an ALLEGRO_EVENT on the stack and pass a reference to that.

Peter Wang wrote all the event stuff, so you should probably bring it up on the development forum here if you want to see something like that added. I'm not 100% sure the patch above is correct.

Personally, I would be in favor of having such a function if only for the sake of completeness.

axilmar
Member #1,204
April 2001

Thanks a lot Matthew.

But to be honest, I'm not really sure who is creating the timer and who is listening...

A timer is required when a widget needs to perform a timely action such as:

  • animating a text cursor.

  • scrolling a widget's contents when the mouse is at the edges of the widget.

So, it is a widget that creates the timer, and it is also the widget that responds to the timer events.

EDIT:

After a little bit of thinking, I will implement the above by:

  • using a custom event for expose.

  • creating an internal event source object which will be registered with the queue used by the main loop.

For example:

rootWidget->connect(mainQueue);

A function which puts an event in a queue is not really required. All that is required is a custom event source which is bound to a queue.

When a widget needs to create a timer, it will register the timer with the queue given above.

When a widget needs to emit an expose event, a custom expose event will be emitted to the internal event source registered to the queue given above.

This event source can also be used to put any event to that queue.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I don't think this is the best way to go about it. Why not make a global timer used by the entire GUI? Set it to the monitor's refresh rate and forget it. Have the user pass the delta time into a widget's update function after reading the timer events. The user will most likely create a timer at the refresh rate of the monitor anyway, and then they can just pass the delta time in.

class WidgetBase {
public :
   virtual void Update(double dt) {}
};


if (event.type == ALLEGRO_EVENT_TIMER) {
   gui.Update(SECONDS_PER_TICK);
}

That is so much simpler than making every widget own a timer, and event queue.

As for your expose events, it looks like Matthew's patch should take care of that for you. Wouldn't the display have to be using double buffering to make that work for you though? If it used page flipping, you would be forced to fully redraw everything every frame anyway. My A4 GUI uses a BITMAP buffer for each WidgetHandler, and it uses dirty rectangles, only updating the widgets that need to be redrawn. So it blits its buffer every time you call display, but doesn't necessarily redraw every widget.

Matthew Leverton
Supreme Loser
January 1999
avatar

I guess I have implemented timers for my blinking cursor, but I think I just hacked it internally. Generally, I think I would do something like Edgar is proposing.

axilmar
Member #1,204
April 2001

Why not make a global timer used by the entire GUI?

1) Because Widgets shouldn't have update() functions. Remember, you spoke of clean and organized APIs in another thread.

2) Because I wouldn't want to dispatch the timer event to every widget in a widget tree. I'd like to dispatch it to the widget that created the timer.

3) Because different widgets would have different timer periods, often incompatible between them.

4) because I don't like the user of my library to not get blinking cursors if he/she doesn't handle the timer event in his/her event queue.

Quote:

As for your expose events, it looks like Matthew's patch should take care of that for you.

Well, if it becomes official Allegro 5 code, then maybe I'll use it. But, as I have thought about it, it is not really needed.

Quote:

Wouldn't the display have to be using double buffering to make that work for you though? If it used page flipping, you would be forced to fully redraw everything every frame anyway.

I don't know what A5 currently does internally, but expose events work as they are. So, my code will look like this:

switch (event.type) {
    case ALLEGRO_EVENT_DISPLAY_EXPOSE:
    case MYGUILIB_EVENT_DISPLAY_EXPOSE:
        ...; 
}

Quote:

My A4 GUI uses a BITMAP buffer for each WidgetHandler, and it uses dirty rectangles, only updating the widgets that need to be redrawn. So it blits its buffer every time you call display, but doesn't necessarily redraw every widget.

1) There is no need to use bitmaps in A4 when using a dirty rectangle system. I've done GUIs in A4 with dirty rectangles that simply told widgets to redraw the dirty rectangles.

2) I am not planning to use a dirty rectangle system, it's not required. All I want is to redraw a specific part of the GUI and not the whole GUI.

Here is how I decided to do it: A class GUI will hold the global context of a GUI, including display and queue. Then, the root widget will have to be initialized with this GUI class, like this:

GUI gui(display, queue);
Widget root;
gui.setRoot(root);

The GUI class will contain lots of other globals that a GUI needs.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

axilmar said:

1) Because Widgets shouldn't have update() functions. Remember, you spoke of clean and organized APIs in another thread.

If you want animated widgets, they should have an update function. Having a default base class update function that does nothing adds zero overhead. It is a perfectly clean and organized solution to have only the widgets that need delta time do something with it. If your user is too lazy / brain dead to use a timer and pass SECONDS_PER_TICK to a top level gui widget, that's really pathetic and they deserve for animations not to work.

axilmar said:

2) Because I wouldn't want to dispatch the timer event to every widget in a widget tree. I'd like to dispatch it to the widget that created the timer.

How do you plan to distinguish which widgets get which events? Isn't it better to let them decide whether they want to deal with an event?

axilmar said:

3) Because different widgets would have different timer periods, often incompatible between them.

Are you really going to need widgets that have timers faster than the refresh rate of the monitor?. I imagine widgets like that would be pretty rare and in that case then they should have their own timer built in. You would still need a way to detect widgets like this and have them check their inputs more often than the rest of the widgets.

axilmar said:

4) because I don't like the user of my library to not get blinking cursors if he/she doesn't handle the timer event in his/her event queue.

So instead of asking the user to do one tiny little thing, you would make your library more complicated and bloated by making all of your widgets have their own timers?

axilmar said:

1) There is no need to use bitmaps in A4 when using a dirty rectangle system. I've done GUIs in A4 with dirty rectangles that simply told widgets to redraw the dirty rectangles.

In A4, buffers are quite useful, and prevent the need for an entire panel of widgets to be redrawn at once. Buffers also allow the user to redraw the entire gui at once if part of the screen has been changed.

axilmar said:

2) I am not planning to use a dirty rectangle system, it's not required. All I want is to redraw a specific part of the GUI and not the whole GUI.

What are you going to do if A5 is using page flipping internally? The screen will get out of sync with what it is supposed to be displaying.

axilmar
Member #1,204
April 2001

If you want animated widgets

Animation can be achieved on a per widget basis. There is no need for a global system, because only one widget will be animated at a time.

Quote:

Having a default base class update function that does nothing adds zero overhead.

The update mechanism adds overhead. Having a timer, i.e. a thread, wake up 60 frames per second, i.e. every 16 milliseconds, when all I want is a blinking cursor every one second.

Quote:

It is a perfectly clean and organized solution to have only the widgets that need delta time do something with it.

It is not clean to have a function in the root class that only a few widgets will use.

Quote:

If your user is too lazy / brain dead to use a timer and pass SECONDS_PER_TICK to a top level gui widget, that's really pathetic and they deserve for animations not to work.

The user shouldn't have to initialize a timer in order for his GUI to work. It's better to automate the process.

Quote:

How do you plan to distinguish which widgets get which events? Isn't it better to let them decide whether they want to deal with an event?

Widgets that create timers will register themselves to their GUI object in order to receive timer events.

Quote:

Are you really going to need widgets that have timers faster than the refresh rate of the monitor?.

Not faster, slower. But when I need a blinking cursor with speed = 1000 milliseconds, 1000 is not divided accurately with 60.

Quote:

So instead of asking the user to do one tiny little thing, you would make your library more complicated and bloated by making all of your widgets have their own timers?

I am against making the user do anything except the absolutely necessary required to get his gui going. If that means making the library more complicated for me, then so be it. It will be easier for the user though.

Quote:

In A4, buffers are quite useful, and prevent the need for an entire panel of widgets to be redrawn at once.

Buffering is useless when widgets need to be redrawn. Why waste resources when the screen needs to be updated? drawing onto a buffer and then blitting the buffer to the screen spends resources that wouldn't be spent if the drawing happened directly to the destination bitmap (and then buffers were switched). And if you use memory bitmaps, you lose accelerated drawing.

Quote:

Buffers also allow the user to redraw the entire gui at once if part of the screen has been changed.

The same effect can be achieved by double buffering.

Quote:

What are you going to do if A5 is using page flipping internally? The screen will get out of sync with what it is supposed to be displaying.

Not at all. The event EXPOSE contains the area that is to be updated, and so I will redraw the appropriate widgets inside that area, as needed.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

axilmar said:

Buffering is useless when widgets need to be redrawn. Why waste resources when the screen needs to be updated? drawing onto a buffer and then blitting the buffer to the screen spends resources that wouldn't be spent if the drawing happened directly to the destination bitmap (and then buffers were switched). And if you use memory bitmaps, you lose accelerated drawing.

If you draw directly to the screen, you will have flickering images whenever an object needs to draw over itself or have it's background redrawn. You can use memory or video bitmaps if you like, I never said the user was forced to use one or another.

axilmar said:

Edgar said:

Buffers also allow the user to redraw the entire gui at once if part of the screen has been changed.

The same effect can be achieved by double buffering.

Why would you want to redraw every single widget when you could just blit a stored copy of the gui panel into place as necessary?

axilmar said:

Not at all. The event EXPOSE contains the area that is to be updated, and so I will redraw the appropriate widgets inside that area, as needed.

The EXPOSE event may tell you what part of the screen is dirty, but if A5 is using page flipping and you update one page and flip, that update is lost on the second page.

axilmar said:

The update mechanism adds overhead. Having a timer, i.e. a thread, wake up 60 frames per second, i.e. every 16 milliseconds, when all I want is a blinking cursor every one second.

Premature optimization anyone? The overhead added by an update function is completely negligible. If your timer is running at 60Hz, then you will never be more than 1/60 of a second behind the actual time you wanted. No human can even tell the difference between 60/60 and 61/60 of a second.

axilmar said:

It is not clean to have a function in the root class that only a few widgets will use.

Of course it is. Only the widgets that actually use the update function will ever redefine it. The rest of the widgets don't have to do a single thing with it.

I really just disagree with you on this. This all works perfectly fine in my GUI, and adding in 5-10 lines of timer code is not too much to ask a user to do if they want animations.

Thomas Fjellstrom
Member #476
June 2000
avatar

axilmar said:

Animation can be achieved on a per widget basis. There is no need for a global system, because only one widget will be animated at a time.

Why make the limitation of one animation at a time? Sure you don't need a global animation system, but Qt manages it with Animation classes that you tie to various properties on a widget, and the Animation class handles the animation (which I assume registers a timer event for itself).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

axilmar
Member #1,204
April 2001

If you draw directly to the screen, you will have flickering images whenever an object needs to draw over itself or have it's background redrawn.

You also have flickering if you use per-widget bitmaps - the drawing operation then becomes the blitting of the widget bitmap to the screen.

Buffering widgets does not work like that (i.e. one bitmap per widget). It works with a background bitmap that all widgets are drawn onto, and then the final result is displayed, either via page flipping or blitting.

Quote:

Why would you want to redraw every single widget when you could just blit a stored copy of the gui panel into place as necessary?

Because bitmaps take a lot of memory, and you will usually have to redraw the bitmap anyway.

Quote:

The EXPOSE event may tell you what part of the screen is dirty, but if A5 is using page flipping and you update one page and flip, that update is lost on the second page.

Perhaps. I haven't seen it though, in my current demos. Which means that A5 doesn't use page flipping, it just blits the back buffer to the front buffer.

Quote:

Premature optimization anyone? The overhead added by an update function is completely negligible. If your timer is running at 60Hz, then you will never be more than 1/60 of a second behind the actual time you wanted. No human can even tell the difference between 60/60 and 61/60 of a second.

It's noticeable, because there are other delays too: the thread that implements the timer, the putting of event in the queue, the waking up of the thread etc. These may amount to more than 20 milliseconds, especially on Windows where the default timer accuracy is 10 milliseconds.

The main problem though is that a thread waking up every 16 milliseconds. It's a resource hog.

Quote:

Of course it is. Only the widgets that actually use the update function will ever redefine it. The rest of the widgets don't have to do a single thing with it.

But the whole widget tree will have to be notified every 16 milliseconds of the timer. Isn't that a performance issue?

Quote:

I really just disagree with you on this. This all works perfectly fine in my GUI, and adding in 5-10 lines of timer code is not too much to ask a user to do if they want animations.

Well, it may work for you, but if you try to do a simulation where the simulation state is updated every 100 milliseconds, and you have a thread waking up every 16 milliseconds, you will notice many hickups in the simulation thread.

I want to avoid any possible performance issues in my gui, since I'd like to use it in my simulations. Perhaps your needs are different, but even if they are, I don't see how saving up resources is a bad thing.

Why make the limitation of one animation at a time?

I will not make such a limitation. I was just referring to the most common use cases for timers on a gui, i.e. blinking cursors and automated scrolling views.

EDIT:

According to al_flip_display documentation:

Quote:

Pointers to the special back and front buffer bitmaps remain valid and retain their semantics as back and front buffers respectively, although their contents may have changed.

So the expose event works because the back and front buffers remain back and front buffers after a flip.

Thomas Fjellstrom
Member #476
June 2000
avatar

axilmar said:

Because bitmaps take a lot of memory, and you will usually have to redraw the bitmap anyway.

Nope. Qt4 manages to speed up a lot of stuff using a back buffer for every widget. Turns out that much of the time, most widgets don't change much. And redrawing every complex widget every frame is a massive chunk of overhead. Primitives, especially ones with fancy features (Qt supports a wide range of Vector like drawing features in its primitive drawing api) are slower than you think they are. Even in Allegro 5 primitives are rather slow. Most of it is overhead in the graphics driver.

Using native windows for widgets also speeds things up, so it stopped doing that by default. They do use the platform's native drawing routines when possible to draw those widgets though, so themes tend to work.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

axilmar
Member #1,204
April 2001

Nope. Qt4 manages to speed up a lot of stuff using a back buffer for every widget.

I doubt Qt4 has one bitmap per widget. Most probably, it does some kind of caching, depending on the video card memory size and on the main memory size.

Using bitmaps for caching is ok, as long as the bitmaps are in video memory, or the cache is small. Otherwise, it is a huge drain in resources.

Imagine a desktop of 1650 x 1280 in 32-bit color, with 10 windows open full screen, and one of the browsers having 20 tabs. Not an unusual setup, right?

If each window and each browser tab has one bitmap, we are talking about 30 bitmaps, which will consume 30 x 1650 x 1280 x 4 = 253440000 bytes, i.e. 241 MB.

And, in the above example, I am not counting bitmaps of controls.

Thomas Fjellstrom
Member #476
June 2000
avatar

If a web browser doesn't have a backbuffer for each tab, switching tabs would be hella slow.

axilmar said:

If each window and each browser tab has one bitmap, we are talking about 30 bitmaps, which will consume 30 x 1650 x 1280 x 4 = 253440000 bytes, i.e. 241 MB.

Guess how much memory firefox and chrome use? many hundreds of MB. Even several GB if you let it get that far. I've seen both chrome and firefox use more than 2 GB.

append: though I think the default for Qt4 is to have one backbuffer for the top level window, and the widgets then render to a chunk of that. But each widget has the option of having its own back buffer IIRC.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Matthew Leverton
Supreme Loser
January 1999
avatar

You cannot do all graphical effects without a buffer. My GUI is a mess regarding this right now, but my goal is to support both buffered (as it does now) and unbuffered (sub-bitmaps or transformations) widgets at the programmer's own discretion.

Peter Wang
Member #23
April 2000

axilmar said:

So the expose event works because the back and front buffers remain back and front buffers after a flip

No. As clarified in the more recent version of the docs:

Pointers to the special back and front buffer bitmaps remain valid and retain their semantics as back and front buffers respectively, although their contents may have changed.

(We took out the al_get_frontbuffer() function a while ago, so there is no such thing any more.)

Thomas Fjellstrom
Member #476
June 2000
avatar

In case you want an example of that "Painter" stuff, I implemented a simple Painter/PaintEngine setup in my Canva5 library. Its rather simple and doesn't do any caching (yet). But adding a cached version of objects would likely speed up the rendering of simple objects significantly (especially if the pixmaps were cached in atlases). The overhead of calling things like al_draw_circle hundreds of times is enormous.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

axilmar said:

You also have flickering if you use per-widget bitmaps - the drawing operation then becomes the blitting of the widget bitmap to the screen.

Buffering widgets does not work like that (i.e. one bitmap per widget). It works with a background bitmap that all widgets are drawn onto, and then the final result is displayed, either via page flipping or blitting.

That's the kind of buffering I was talking about - my WidgetHandler (gui / panel / window) class has two bitmaps, one background bitmap and one buffer bitmap. The background is redrawn as necessary and then the necessary widgets are drawn, but almost never all of them are redrawn at once. Having a buffer allows the user to change as much of the back buffer as he wants to without having to make every widget redraw itself all over again. Why redraw more than once when you don't have to?

axilmar said:

Because bitmaps take a lot of memory, and you will usually have to redraw the bitmap anyway.
...
If each window and each browser tab has one bitmap, we are talking about 30 bitmaps, which will consume 30 x 1650 x 1280 x 4 = 253440000 bytes, i.e. 241 MB.

And with 2GB being the standard normal amount of memory in a system these days, that's still only about 12% of the systems memory, which isn't that much.

axilmar said:

But the whole widget tree will have to be notified every 16 milliseconds of the timer. Isn't that a performance issue?

1,000 widgets * 60 updates per second = 60,000 function calls per second. That's not all that much for today's processors to handle. And 1,000 widgets is kind of ridiculous anyway, more like one or two hundred. Don't optimize until you identify a bottleneck.

 1   2 


Go to: