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.
Oscar Giner
Member #2,207
April 2002
avatar

axilmar said:

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.

You don't get flicker if you implement it property. It's actually how Windows (pre-Aero) works. My old GUI works this way, too (it's a convenient method because it's very efficient when widgets rarely change).

(Append: note that I wouldn't use this method on a modern GUI. It's in general more limited, and if you want that most widgets have cool animations and effects (I'm talking about a GUI designed for use in games), then you just want to render all the widgets every frame).

axilmar said:

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.

As the docs say, the contents may have changed (and the surfaces this bitmaps "point" to may change). Easy test: force Allegro to use the OpenGL driver, and enable "Triple buffering" in your GPU settings (this setting, on both nVidia and ATI, only affects OpenGL). For DirectX, there are 3rd party programs that allow to change the update method (forcing triple buffering for example, or increase the number of back buffers).

axilmar
Member #1,204
April 2001

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

Not really. Drawing part of a web page is not that slow.

Quote:

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.

That's allocated memory chunks used by various plugins, Javascript, etc. Not bitmaps.

Quote:

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.

Exactly. Only selected Qt4 widgets have back buffers enabled by default, in order to minimize memory use.

You cannot do all graphical effects without a buffer.

What kinds of graphical effects do you have in mind?

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.

That complicates using Expose events for a GUI. I'd have to think a solution.

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?

Good waste of resources, Reynaldo :-).

Quote:

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.

Considering all the other things that run in a system, it is.

Quote:

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.

You are master in wasting resources :-).

You don't get flicker if you implement it property.

You do get flickering, although less if you draw stuff quickly. If you blit bitmaps directly on the screen, then you get flickering.

Quote:

It's actually how Windows (pre-Aero) works.

No, it is not. Aero works like this: the top-level windows have a texture inside the video ram, and all drawing of those windows and of children windows goes into that texture. Then Windows renders this texture on the screen, using two buffers.

It's not like Reynaldo's system that has two bitmaps per widget.

Oscar Giner
Member #2,207
April 2002
avatar

axilmar said:

You do get flickering, although less if you draw stuff quickly. If you blit bitmaps directly on the screen, then you get flickering.

Of course you don't. You basically draw the widget in a buffer, and blit that buffer to the screen (overwriting the previously drawn widget). Where do you see the flicker in this? (if you want a real example: download my tetris clone, go to new game, and see if you see any flicker in the GUI there)

Quote:

No, it is not. Aero works like this: the top-level windows have a texture inside the video ram, and all drawing of those windows and of children windows goes into that texture. Then Windows renders this texture on the screen, using two buffers.

I said pre-Aero. Believe me I've worked with this, and in Windows you need to double buffer your widgets or you get flickering when they're redrawn (again, to be clear, this is true only if not using Aero). (As for Qt: while widgets may not be double buffered, Qt windows are always double buffered so you can resize windows without getting flickering. This is why there's no need for widgets to be double buffered other than as a cache for not having to redraw complex widgets).

Append:

Quote:

That's allocated memory chunks used by various plugins, Javascript, etc. Not bitmaps.

I don't know about Firefox since I don't use it, but Opera certainly stores each tab in its own bitmap. This allows for instant tab switching no matter how complex a page is, even on an ancient computer (as long as it has enough RAM).

axilmar
Member #1,204
April 2001

Of course you don't. You basically draw the widget in a buffer, and blit that buffer to the screen (overwriting the previously drawn widget). Where do you see the flicker in this? (if you want a real example: download my tetris clone, go to new game, and see if you see any flicker in the GUI there)

I was talking about the bitmaps of widgets, in the context of one bitmap per widget, as per Reynaldo's implementation. If you draw all the widgets in a buffer, then you don't get flickering.

Quote:

Believe me I've worked with this, and in Windows you need to double buffer your widgets or you get flickering when they're redrawn (again, to be clear, this is true only if not using Aero). (As for Qt: while widgets may not be double buffered, Qt windows are always double buffered so you can resize windows without getting flickering. This is why there's no need for widgets to be double buffered other than as a cache for not having to redraw complex widgets).

You're right. I've implemented a custom widget library for a project under Win32. The default drawing on an Window HDC is to draw directly in the VRAM, clipped by the HDC's update region.

Quote:

I don't know about Firefox since I don't use it,

There was an article on Reddit a few moons ago about the problem of Firefox memory usage, with links to Firefox's developers describing how memory allocation is done in Firefox. They spoke of memory compartments, and how a single reference to that compartment keeps the compartment from being deallocated.

Here is a relevant link.

Quote:

but Opera certainly stores each tab in its own bitmap

How do you know this? any links?

Oscar Giner
Member #2,207
April 2002
avatar

axilmar said:

How do you know this? any links?

Because even on an old Pentium 166 (the first computer I used Opera with), a complex page that maybe scrolled at 2-5fps (this was common with pages with a static background and transparent/translucent things on the front), was instantly shown when I clicked on its tab (it's obvious it was not being re-rendered).

Matthew Leverton
Supreme Loser
January 1999
avatar

axilmar said:

What kinds of graphical effects do you have in mind?

For instance:

  • A window has a background image

  • A button in that window is drawn with 50% transparency over that background image

  • The entire result is drawn at 25% transparency

So a pixel in the button is calculated by:

(0.5 * button + 0.5 * window background) * 0.75 + (desktop * 0.25)

In this case, if you buffer the window, it's extremely simple. (No need to buffer the button.)

Say you want to drag a window and have it wobble around (see Compiz's wobbly windows plugin). Again, if you buffer the window, you can easily distort the buffer.

I think for most practical use cases, if the window is buffered and all of its widgets are sub bitmaps of that, then you'll be fine. But there could still be cases where that's not sufficient, which is why I optionally support buffering per widget.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

axilmar said:

It's not like Reynaldo's system that has two bitmaps per widget.

I don't know where you got that idea from, but it's not true. I said the WidgetHandler class has two bitmaps, not every single widget. It's basically a window / panel / gui class and it handles all the mundane tasks like hover/focus/update/input/display.

axilmar said:

I was talking about the bitmaps of widgets, in the context of one bitmap per widget, as per Reynaldo's implementation.

Again, that's not correct.

axilmar
Member #1,204
April 2001

Because even on an old Pentium 166 (the first computer I used Opera with), a complex page that maybe scrolled at 2-5fps (this was common with pages with a static background and transparent/translucent things on the front), was instantly shown when I clicked on its tab (it's obvious it was not being re-rendered).

On machines with similar specs, clicking on the Windows task bar to bring another Netscape or Internet Explorer in the foreground resulted in the background window being rendered almost instantly.

So, on what basis do you claim Opera cached its page rendering on a bitmap? perhaps your eyes were too slow to see the redraw, or Opera painted the page on a background bitmap first, and then discarded the bitmap.

Say you want to drag a window and have it wobble around (see Compiz's wobbly windows plugin). Again, if you buffer the window, you can easily distort the buffer.

You can always render it in a bitmap when it's about to be dragged. Why cache the output? X-Windows may need the caching in order to avoid network delays, but an Allegro-based GUI wouldn't need to do that, because creating the back buffer, drawing the widget tree is very fast (unless you draw something really complex, that is).

I don't know where you got that idea from, but it's not true. I said the WidgetHandler class has two bitmaps, not every single widget. It's basically a window / panel / gui class and it handles all the mundane tasks like hover/focus/update/input/display.

You didn't explain that you only have one WidgetHandler instance per GUI. I thought each widget has its own WidgetHandler. The name 'WidgetHandler' suggests each widget has its own handler.

Oscar Giner
Member #2,207
April 2002
avatar

axilmar said:

perhaps your eyes were too slow to see the redraw

if a bitmap wasn't stored, it would be a 200 ms (talking about the example I mentioned of a page that scrolled at 3-5fps) delay between I click on a tab and I see the contents. That's a very noticeable delay.

Quote:

or Opera painted the page on a background bitmap first, and then discarded the bitmap.

Wouldn't that mean that it would need to keep a bitmap of each tab? So if I change to a new tab I can instantly see the page, while in the background it re-renders it to show me an up to date version?

axilmar
Member #1,204
April 2001

if a bitmap wasn't stored, it would be a 200 ms (talking about the example I mentioned of a page that scrolled at 3-5fps) delay between I click on a tab and I see the contents. That's a very noticeable delay.

Perhaps it was a 50 ms delay. Or a 100 ms delay. Or a 500 ms delay. You cannot tell how many milliseconds the delay is, simply by clicking on the tab.

I don't doubt you, I just want a little proof for your claims. That you saw it is not proof, because we humans cannot tell the exact delay in milliseconds in such cases.

Quote:

Wouldn't that mean that it would need to keep a bitmap of each tab?

Nope, it would simply mean that Opera used a background buffer to draw its page.

I also doubt the rendering of such a page would need more than 10 milliseconds. If you use Allegro 4 on such an old computer, open a video mode of 1024x768 and then proceed to draw a background and then some transparent text and bitmaps on it; it will hardly take a few milliseconds. Do it with Win32 that perhaps uses hardware acceleration (accelerated 2d was the norm back then), and it would take much less.

Oscar Giner
Member #2,207
April 2002
avatar

I already told you that scrolling was very slow (no more than 5 fps), almost unusable. Antialiased text rendering is very slow, as are translucent blits. Opera was specially slow rendering this kind of pages, too. IE for example was pretty fast.

You Pentium was awesomely fast, where did you bought it?. Because for me even the Allegro Grabber help viewer was laggy (just a bit).

If you want a more recent prove, take this page: http://bitcoincharts.com/charts/mtgoxUSD#kgthUSDzrg2zvztgSzm1g10zm2g25 The graph there takes a good fraction of a second to render on my computer. Tabing in-out is instant, when restoring/maximizing the window you see a noticeable delay in the graph updating (the size changes so it needs to be redrawn).

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

axilmar said:

You didn't explain that you only have one WidgetHandler instance per GUI. I thought each widget has its own WidgetHandler. The name 'WidgetHandler' suggests each widget has its own handler.

HandlerOfWidgets then? WidgetManager? That was the best name I could come up with.

Speaking of slow scrolling, there are some web pages that scroll like molasses. If they were buffered, that wouldn't happen.

axilmar
Member #1,204
April 2001

I already told you that scrolling was very slow (no more than 5 fps)

That does not mean drawing was slow. It may have been slow due to other reasons.

Quote:

Tabing in-out is instant, when restoring/maximizing the window you see a noticeable delay in the graph updating (the size changes so it needs to be redrawn).

Perhaps the graph itself is buffered and not the page. Perhaps the conversion of graph's data to an image is slow. Perhaps the fetching of data for the graph is slow. When I resize the page, all the elements are instantly redrawn except the graph.

HandlerOfWidgets then? WidgetManager? That was the best name I could come up with.

I once had in my GUI library:

typedef int (*WidgetHandler)(Widget *, int msg, void *data);

How about 'GUI'?

Quote:

Speaking of slow scrolling, there are some web pages that scroll like molasses. If they were buffered, that wouldn't happen.

It depends. If the whole page was buffered, then yes. But it would take a huge amount of memory. Imagine a bitmap 100 pages high, for example.

The slowness may be due to any number of parameters, including slow rendering.

Oscar Giner
Member #2,207
April 2002
avatar

Ok, believe what you want. I'm not going to do the research for you.

 1   2 


Go to: