Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » Developing U++ » U++ Developers corner » Should we double-buffer by default?
Should we double-buffer by default? [message #4053] Tue, 18 July 2006 15:23 Go to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
I am in process of refactoring U++ painting engine.

This is quite complicated topic, much more complicated than it seems, if the goal is to avoid flickering e.g. when resizing windows.

There of course is "simple" solution to avoid flickering forever - full window double-buffering.

So far, I stayed away from this, taking the hard approach and using double-buffering just for areas that really need it (namely areas covered by transparent Ctrls).

This leads to very complicated algorithm and the results are questionable. Now I have tried to benchmark the new (improved) painting engine in several modes on both my A64 and venerable testing NT4.0 Celeron@433Mhz with 4MB S3 VGA and 96MB ram. Numbers are time for "repaint the window when resizing" routine:

1. raw mode - no backbuffering:
A64 - 2.8 ms
Celeron433 - 90 ms

2. full window backbuffering:
A64 - 2.4 ms
Cel433 - 115 ms
note that this mode could be probably further improved a little bit...

3. multirun mode - in this mode, transparent areas are doublebuffered and painted one by one:
A64 - 8.8 ms
Cel433 - 266 ms

4. single run mode - single back buffer is created for all transparent area and they are painted in single run:
A64 - 6 ms
Cel433 - 145 ms

Looks like trying to be smart does not really pay off...

Now reading Qt docs, since Qt4.0 they do doublebuffering as the only option. Should not we too? (OK, this whole message is for Daniel in the first place... Wink

Mirek
Re: Should we double-buffer by default? [message #4054 is a reply to message #4053] Tue, 18 July 2006 15:31 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
More thoughts:

- maybe I will simply try that - make U++ back-buffering for a couple of weeks and will see. We can always get back to more complicated model

- maybe we could do some form of automatic adaptation - if average repainting time for window breaks some threshold, use direct painting instead, even if it is flickering (I would rather have resizing smooth at the price of flickering than vice versa).

Mirek
Re: Should we double-buffer by default? [message #4055 is a reply to message #4053] Tue, 18 July 2006 15:56 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Tue, 18 July 2006 09:23


Now reading Qt docs, since Qt4.0 they do doublebuffering as the only option. Should not we too? (OK, this whole message is for Daniel in the first place... Wink



Thank you Mirek Wink

Indeed, to answer if double-buffering should be used as default is not easy. Generaly idea is great and it solves many corner issues with painting.

The main problem with double-buffering is speed of drawing, which is depended mainly on graphics card and the screen resolution. Unofrtunately I always had feeling that apps that are working in full screen in double-buffering mode are less responsive (at least when win32 api (gdi) is used) than "classical" painted ones (even if cpu has 1ghz and modern gfx card like gf4 were used).

I will try your new code today evening and then I'll be able to say more. I think that we should make tests in apps working in maximized modes in resolutions 1024x768 and 1280x1024. In smaller windows there should not be any noticeable difference.
Re: Should we double-buffer by default? [message #4056 is a reply to message #4055] Tue, 18 July 2006 16:36 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
unodgs wrote on Tue, 18 July 2006 09:56


(even if cpu has 1ghz and modern gfx card like gf4 were used).



Just a sidenote - while I do not quite like that kind of argument, I have to mention that gf4 is not "modern gfx". 7xxx is "modern". gf4 is 5 years old...

That said, I am quite happy with double-buffer performance on my 1.2Ghz/GF4 rig....

Mirek
Re: Should we double-buffer by default? [message #4057 is a reply to message #4056] Tue, 18 July 2006 23:43 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Tue, 18 July 2006 10:36


Just a sidenote - while I do not quite like that kind of argument, I have to mention that gf4 is not "modern gfx". 7xxx is "modern". gf4 is 5 years old...



Modern in sense of momory bandwitch, speed of drawing 2d primitives - not 3d stuff Wink

From my experince I know that in win32 env gdi work faster (and the double-buffering as well) if memory<->gfx transfers are fast.
Eg p41.7 + gf2mx 32mb was faster (I cosider double-buffering mode in upp and opera that uses qt) than duron 1ghz + gf4200Ti (128MB).

Re: Should we double-buffer by default? [message #4058 is a reply to message #4057] Tue, 18 July 2006 23:57 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
I believe that double-buffering does not do memory<->GPU transfers, on decent card with good driver...

Mirek
Re: Should we double-buffer by default? [message #4060 is a reply to message #4058] Wed, 19 July 2006 00:42 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Reply to ICQ:

> Mirek I don't understand. If theide is now all double-buffered why I can see eg in thisbacks window when scrolling array that first body of array ctrl is scrolled and then child controls

- because scroll is used to scroll window area. Double buffering takes effect later... (yes, I still have "detect Ctrl position change that is scrolled and avoid repainting" in my list. When that will be done, this will disappear).

- also, sometimes (e.g. HeaderCtrl) there is Sync that forces immediate repaint

Mirek
Re: Should we double-buffer by default? [message #4063 is a reply to message #4060] Wed, 19 July 2006 08:09 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Tue, 18 July 2006 18:42


- because scroll is used to scroll window area. Double buffering takes effect later... (yes, I still have "detect Ctrl position change that is scrolled and avoid repainting" in my list. When that will be done, this will disappear).


I came to the same conclusion thinking about it later Smile
Re: Should we double-buffer by default? [message #4064 is a reply to message #4058] Wed, 19 July 2006 08:34 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Tue, 18 July 2006 17:57

I believe that double-buffering does not do memory<->GPU transfers, on decent card with good driver...



I've found on usenet:

Quote:


Bitmaps created by CreateCompatibleBitmap() are managed by the video driver. They may or may not be in video memory.

John - Microsoft Developer Support



So if the backbuffer is created in system memory (maybe from unknown reasons on my duron it was) gfx<->memory transfer speed is important.
Re: Should we double-buffer by default? [message #4065 is a reply to message #4064] Wed, 19 July 2006 09:01 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
BTW, any idea how to detect a system that is better to flicker than backbuffer? Smile

I was thinking about measuring time of backbuffer paint routine and when it reaches some threshold (50ms), switch to direct flickering mode.

I am however afraid that random time fluctuation would switch decent system as well...

Mirek
Re: Should we double-buffer by default? [message #4066 is a reply to message #4065] Wed, 19 July 2006 10:09 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Wed, 19 July 2006 03:01

BTW, any idea how to detect a system that is better to flicker than backbuffer? Smile

I was thinking about measuring time of backbuffer paint routine and when it reaches some threshold (50ms), switch to direct flickering mode.

I am however afraid that random time fluctuation would switch decent system as well...



Unfortunately I have no idea how to detect it (if it is detectable at all) Time measuring seems to be a better idea, but instead of doing it in every Paint() and dynamicaly switch the render mode better would be to do some typical tests at the beginning of the application.

Ok, now lets talk a little about problems with double-buffering.
I tested it mainly in my GridTest application. This is simply app with one tab control and two sheets. In first is grid control, in second array control.
What is intersting in debug mode painting is noticeable slower with double buffering (before it was faster). I checked this on 2 computers (app was maximized):

1. Sempron 64 2.1 ghz, gf6600 1280x1024
2. P4 1.7, gf2mx, 1024x768

In release mode on machine 1 speed was very good, on machine 2 refreshing speed was worst (and it was also worst than in "old" upp rendering mode).

I tested mainly column resizeing. On machine 2 in my grid there is significant lag between mouse position and resized column position. In array ctrl is even worst because header scrolls normaly (no lag) but the body is painted 5-8 pixels behind (I guess this is not synchronized and after fixing it the result will be the same as in my grid).
Anyway in both cases we lost the most important thing: responsivity and feeling of "lightweight" ui.

I also noticed that in my grid ScrollView do nothing (it worked before). The grid consist of 4 frames. Top header, left header , scrollbars and the main frame - grid body.
If scroll was detected the OnScroll() routine from main frame was called. And it looks like this:

void GridCtrl::OnScroll()
{
	if(!doscroll)
		return;
	
	Point newpos(sbx, sby);
	Size delta = oldpos - newpos;	
	
	scrollxdir = delta.cx == 0 ? scrollxdir : delta.cx < 0 ? 1 : -1;
	scrollydir = delta.cy == 0 ? scrollydir : delta.cy < 0 ? 1 : -1;

	if(th.drawColLine || lh.drawRowLine)
	{
		oldpos = newpos;
		return;
	}
		
	//if(!IsFullRefresh())
	{
		ScrollView(delta);
		if(delta.cx != 0)
		{
			Size sz = th.GetSize();
			th.ScrollView(Rect(fixedWidth, 0, sz.cx, sz.cy), delta.cx, 0);
			scrollLeftRight = true;
		}
		if(delta.cy != 0)
		{
			lh.ScrollView(0, delta.cy);
		}
	}
	oldpos = newpos;
	UpdateCtrlsPos(0, 0, 0, 0, 1);
}

I commented if(!IsFullRefresh) to be sure the header will be scrolled. th is top header lh is left header. Unfortunately
th.ScrollView and lh.ScrollView stopped working. Even if I add
lh/th.Sync() nothing changes. Bug? or there are some important changes I should be aware of?
Re: Should we double-buffer by default? [message #4067 is a reply to message #4066] Wed, 19 July 2006 11:01 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
OK, I have tested on my SisGX/Sempron1.8 notebook and while the difference is small, I must say there is difference...

Means back to development.... Now I am thinking about some sort of more simple approach to the old problem.... In fact, the real trouble of all this is "sibling Ctrl intersection". That makes all the trouble, if I want really correct algorithm. Anyway, at the same time it is not very often corner case.

So my next idea is to detect this problem and perform non-buffered draw just for ctrls that do not have this problem. Also, maybe we could detect and handle unbuffered just Ctrls that are "big" (say bigger that 200x200 pixels).

I will test these new ideas tommorow or on Friday.

As for GridCtrl scrolling problem, I think I know where to look and I think it is in CtrlDraw.cpp Smile, but sample code would help, if possible..... (upload to ftp, please).

Mirek
Re: Should we double-buffer by default? [message #4070 is a reply to message #4067] Wed, 19 July 2006 11:18 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Wed, 19 July 2006 05:01

OK, I have tested on my SisGX/Sempron1.8 notebook and while the difference is small, I must say there is difference...


Good I'm not alone Wink
Quote:


Means back to development.... Now I am thinking about some sort of more simple approach to the old problem.... In fact, the real trouble of all this is "sibling Ctrl intersection". That makes all the trouble, if I want really correct algorithm. Anyway, at the same time it is not very often corner case.
So my next idea is to detect this problem and perform non-buffered draw just for ctrls that do not have this problem. Also, maybe we could detect and handle unbuffered just Ctrls that are "big" (say bigger that 200x200 pixels).


Could you describe the problem of sibling ctrl intersections more? (if you have time, I would like to think about solution too Smile )
As for unbuffered draw this is some kind of idea. I would also add to this ability to set by hand if control is or isn't double buffered.
Quote:


As for GridCtrl scrolling problem, I think I know where to look and I think it is in CtrlDraw.cpp Smile, but sample code would help, if possible..... (upload to ftp, please).


I will upload it today evenig - no problem.
Re: Should we double-buffer by default? [message #4071 is a reply to message #4070] Wed, 19 July 2006 11:47 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Attempt to describe sibling Ctrl intersection problem:

You have opaque Ctrl (can be painted unbuffered) which is intersected by next sibling transparent Ctrl (other part of this sibling Ctrl is above either parent Ctrl or worse, can be above ANOTHER opaque sibling).

Now the correct appearance should be the same as if you paint everything from the first child to the last, doing the same for childs of childs etc... Means next sibling Ctrl should be painted over our opaque Ctrl. Note that you want to backpaint this transparent Ctrl.

This was in U++ (in old and monday/thuesday versions) solved by scanning for all transparent (or non-opaque) areas and back-painting them whith all "bellow" Ctrls (including opaque). The trouble of this approach is that some areas get painted more times.

Mirek
Re: Should we double-buffer by default? [message #4076 is a reply to message #4053] Wed, 19 July 2006 15:04 Go to previous messageGo to next message
mr_ped is currently offline  mr_ped
Messages: 825
Registered: November 2005
Location: Czech Republic - Praha
Experienced Contributor
There's another "span buffer" technique also as third option, but it's way too different from single/double buffer.

I was using it with my 2D parallax scrolling engine for one never released 2D shooter game, and it allowed me to do things like 10+ parallax layers with ~30 FPS on 133MHz in 640x480, but you gain performance only if lot of areas are redrawed, what IMHO doesn't seem like the case for ordinary GUI controls.
(except transparent controls, where the span buffer will help partially to detect everything hidden behind solid spans (if some controls do overlap), but in the end you will need to draw the solid background and than run as many passes again as many transparent spans are above the solid one, so there's no performance gain)

Another slight advantage is, that with span buffer you can refresh the content of window from top to down line by line, while double-buffering only single line being processed, so you need less memory on graphics card (1 frame buffer + 1 line), but again U++ is so far used on ordinary PC = plenty of memory. (maybe on PocketPC it can be more interesting option...)

But the main disadvantage is you must render everything with spans, so that would mean SW render of anything. Also antialiasing/cleartype would require lot of thinking and improving of the original simple span buffer. Manageable, but too complex.


One final note... I always use only "rectangle" during window resize, the "resize with content visible" always seems too slow for me.
Re: Should we double-buffer by default? [message #4079 is a reply to message #4071] Wed, 19 July 2006 16:25 Go to previous messageGo to next message
unodgs is currently offline  unodgs
Messages: 1366
Registered: November 2005
Location: Poland
Ultimate Contributor

luzr wrote on Wed, 19 July 2006 05:47

Attempt to describe sibling Ctrl intersection problem:

You have opaque Ctrl (can be painted unbuffered) which is intersected by next sibling transparent Ctrl.



Lets be more precise. Saying sibling you mean child control or control placed somewhere next to this opaque control (but not involved into parent->child relation).
If you saying intersected you mean that a control is partialy coverd by another control or that another control lies inside a control placed below it or both cases?

Quote:


(other part of this sibling Ctrl is above either parent Ctrl or worse, can be above ANOTHER opaque sibling)



Althought I think I understand it would be nice if you put some screenshot to ilustrate the problem.

Sorry for going so deep into details but I want to be sure that we are speaking the same language and I understand problem correctly.

[Updated on: Wed, 19 July 2006 16:26]

Report message to a moderator

Re: Should we double-buffer by default? [message #4080 is a reply to message #4079] Wed, 19 July 2006 16:43 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Sibling -> has the same parent
Intersects -> GetRect for both intersects

See the screenshot.

Re: Should we double-buffer by default? [message #4085 is a reply to message #4080] Wed, 19 July 2006 17:59 Go to previous messageGo to next message
fudadmin is currently offline  fudadmin
Messages: 1321
Registered: November 2005
Location: Kaunas, Lithuania
Ultimate Contributor
Administrator
I would like to have an alternative "page fipping" mode, as well.
(needs detection if a computer has enough video memory for double size screen). What do you think?
Re: Should we double-buffer by default? [message #4087 is a reply to message #4085] Wed, 19 July 2006 18:56 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
There is no page flipping mode in Win32 GDI or X11.

Mirek
Re: Should we double-buffer by default? [message #4089 is a reply to message #4087] Wed, 19 July 2006 19:23 Go to previous messageGo to previous message
fudadmin is currently offline  fudadmin
Messages: 1321
Registered: November 2005
Location: Kaunas, Lithuania
Ultimate Contributor
Administrator
...CreateDIBSection technology to do fast animation in Windows. This approach gave the programmer direct access to the bitmap in system memory so that one can use optimized routines for drawing to the bitmap...
Or is that not correct?
Previous Topic: let's discuss new Draw principles and problems...
Next Topic: A list of SQL dialects to support (eventually)..
Goto Forum:
  


Current Time: Sat Apr 27 19:03:34 CEST 2024

Total time taken to generate the page: 0.02015 seconds