 |
|
 |
hi man..
i don't know how did you write the code but i hope that you've looked at the example that i gave here but from what i've tested it's supposed to work better with the double buffer techniques.
anyway right now i'm in south america so i don't have time to check it out, sorry.. Gil
|
|
|
|
 |
|
 |
The .NET 2.0 stuff saved my day.
Thanks
|
|
|
|
 |
|
 |
Nice article Gil.
I have a suggestion/question
With GDI drawing I use a forground and a background device context for applications where the forground changes regularily. The OnPaint blits the background and then the forground but does no operations on the device contexts. Instead all forground drawing is done on OnDraw and background drawing done in InvaliateControl.
As I am new to GDI+ is this something that you could add ? Is there an equivalent to BitBlt that would allow blending of forground and background bitmaps to save repeatably drawing the parts of the control that don't change very often?
cheers
Jason
|
|
|
|
 |
|
 |
hi JaseNet
am.. i don't know if you read the whole article but what double buffering is doing is to draw the the control graphics into an image in the memory and draw it only one time to the "real" surface of the control this improves the performance, if you'll check out the manual way it also disables the OnPaintBackground event so you draw the foreground and background together on a single paint event there isn't really a background just an event of drawing the control. about drawing parts of the control what the manual way gives you is a full control of the paint event so you don't really have to redraw the whole control each time you can write some code that will draw only the parts the you want.
about BitBlt i never had to use it on C# i used it in VB6 but that was long time ago, i'm sure you can use the API with [DllImport] just look around the net..
Gil
|
|
|
|
 |
|
 |
Hi Gil
Sorry for the confusion. I am fmiliar with double buffering and have read the article. I was looking for a way of extending it using C#. An example of what I was suggesting...
If you had a control that was dynamic and displayed a scrolling time history for several events such as the cpu usage display then there is a performance benefit in having the background of the control such as grids, axis, rotated text and watermarks predrawn on another drawing surface. The background surface would only change when the control was resized or for example the axis were changed.
The forground drawing surface would only have to contain the dynamic part of the data such as the trace information or rendered display or whatever. This would typically involve displaying a lot of data, say 4 times a second.
As GDI+ is not hardware accelerated it seemed like a good idea to adopt the GDI approach and use two surfaces. For most of the time no drawing would happen on the background surface, only the forground so the cpu is not wasting time constantly drawing all of the display, only the parts that changed.
I accept what you are saying about only updating the invalidated regions but in reality this would end up invalidating most, if not all of the display.
I have looked at alpha blending the two surfaces but the performance hit on GDI+ is too expensive.
thanks
Jason
|
|
|
|
 |
|
 |
hi again
well i think this is a good idea but it depends very much on the solution that is being built, and what i aimed for in this article is for the general use of the techniques of double buffering, your suggesting is very good and will surly be fitted in complex graphic project but in simple projects like a progress bar i don't know if it's worth the spending of time for it but on the next update for the article i'll mention it as a possibility.
i appreciate your comment Gil
|
|
|
|
 |
|
 |
I had to do something similar recently.
GDI+ gradients are a very computationally expensive procedure. I had a few gradient circles, and drawing them each frame killed the app. So I rendered the gradient circles into a bitmap object using Graphics.FromImage(Bitmap), and then stored the image away in memory.
Then, whenever any individual part of my control needed repainting, I would use the PaintEventArgs.Graphics.DrawImage() method (which I've read somewhere is just a bit slower than bitblt), but I would make the source/destination Rectangles equal to the clipping Rectangle. This way, I would only draw the background image where Windows told me it needed drawn.
Then, after drawing the image, you just render the rest of your dynamic information with e.g. DrawString() etc after having done DrawImage().
The final piece of the puzzle is to intelligently Invalidate(). If you Invalidate() the whole form, DrawImage() will draw the whole bitmap. But if you know that your e.g. CPU usage graph needs to be updated, just Invalidate() the Rectangle that holds the graph. For extra performance, make something like a background Region, and if the clipping Rectangle doesn't intersect at all with the background Region, you don't even need to call DrawImage().
Hope some of that helped...
|
|
|
|
 |
|
 |
Nice article but the download won't compile as AssemblyInfo.cs is missing.. Cut and paste this for now
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DoubleBufferExample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DoubleBufferExample")]
[assembly: AssemblyCopyright("Copyright © 2005")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e5fa6eb1-2959-4d33-84dc-0178b1f8743a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
|
|
 |
|
 |
Brings me back to the good old amiga days! Double buffering was the buzz word back then.
This is just what I have been looking for
|
|
|
|
 |
|
 |
Have you done any benchmarking concerning the time it takes to do the rendering using the different double-buffer techniques you have presented?
Maybe you could include this in your test application?
Source code for the test application would be great too.
It could be worth mentioning the huge performance impact that you get if you use DrawImage instead of DrawImageUnscaled. Or maybe this doesn't apply in .NET 2 using OptimizedDoubleBuffer?
Good work.
|
|
|
|
 |
|
 |
hi Mikael
there is a source code included i don't know if you saw it but it demonstrates almost all this techniques.
about benchmarking every technique got it's own benefits so everyone who uses this much check his needs from what i have tested the manual way is sometimes better for the filling test while the OptimizedDoubleBuffer is usually better in the draw test.
about DrawImage and DrawImageUnScaled that depends on your graphic area if you keep it small i don't think u'll see much diffrent if any.
thanks for your commet Gil
|
|
|
|
 |
|
 |
Mikael Wiberg wrote: It could be worth mentioning the huge performance impact that you get if you use DrawImage instead of DrawImageUnscaled. Or maybe this doesn't apply in .NET 2 using OptimizedDoubleBuffer?
I hear this before, and actually there is no performance impact. DrawImageUnscaled is just one of many overloads of the DrawImage method.
//extracted from Reflector
public void DrawImageUnscaled(Image image, Point point)
{
this.DrawImage(image, point.X, point.Y);
}
|
|
|
|
 |
|
 |
hi givanfp
thanks for the comment i'll check it out
Gil
|
|
|
|
 |
|
 |
Hi,
good idea to make an overview on this topic but some points seem incomplete/wrong:
1. In your last sample/last line you use a variable ControlGraphics. I think in this sample it should be e.Graphics instead (always try your samples before posting them).
2. Same sample: You use this.CreateGraphics() to get a Graphics object. As there is already a Graphics object provided with the event arguments I'm not sure if this should be done (how about disposing?).
3. To be effective the allocation shouldn't be done within the Paint method. It can be done once and then forgot.
4. The new property Control.DoubleBuffered internally just call SetStyle with OptimizedDoubleBuffer and AllPaintingInWmPaint.
5. It would have been nice if you could have mentioned that own double buffering implementations have great flexibility. When painting into a bitmap you can reuse it the next time OnPaint is called unless you know something has changed.
|
|
|
|
 |
|
 |
hi Robert
first of all thanks for the commet.
this is the first version of this article i know that the code sample aren't good that's becouse i took them out of the source code itself and i built it a lot more efficiently , if you take a look at it you'll see that all your notes are in that code.
i had a choise of putting a small sample of each technique or putting a huge amont of code that i think a begginer won't understand/put the time into.
after seeing this first comment i will consider writing new small blocks of code to this article
thanks Gil
|
|
|
|
 |
|
 |
You didn't mention this in your article, but it should be mentioned in case any newbies run across this. In order for the ControlStyle DoubleBuffered or OptimizedDoubleBuffer to be effective, you also need to set two other styles:
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
Personally, for some controls which need to be repainted when they are resized, I also set another ControlStyle:
this.SetStyle(ControlStyles.ResizeRedraw, true);
This article did show me though how the BufferedGraphics classes could be used. Thanks!
|
|
|
|
 |
|
 |
hi Tim
thanks for the commet i'm working on an updated version of this article right now and i will put this changes into the updated version.
thanks Gil
|
|
|
|
 |
|
 |
Thanks for that, I was pulling my hair out trying to get a control to paint correctly.
|
|
|
|
 |
|
 |
- Is there any reason why you split up each code block into multiple <pre> sections? It would flow better if each code block was in a single <pre> section. If you wanted to put in blank lines, you can use <br/> instead
- Sentences begin with capital letters
- The word is "technique", not "technic"
Perhaps I'm being a little picky, but presentation is as important as content.
Ryan "Punctuality is only a virtue for those who aren't smart enough to think of good excuses for being late" John Nichol "Point Of Impact"
|
|
|
|
 |
|
 |
hi Ryan
there's no special reason i edited the article on the online editor, and it was uneasy to work with, i will send an updated version of this article very soon.
thanks Gil
|
|
|
|
 |
|
 |
I downloaded your source code, (Download sourcecode - 12.46 kb). When I tried to build it on VS 2005 Express I encountered the below error message. If I am suppose to make some settings or references in the project, please be more specific.
Thanks.
Error 1 Resource file "Properties\Resources.resx" cannot be found. DoubleBuffering
|
|
|
|
 |
|
 |
hi firmwaredsp
i think you can still compile it by removing the reference but i will send an update version of this article in few days.
thanks Gil
|
|
|
|
 |
|
 |
This is the error message that was generated when I tried to build with VS2005 Express, your Updated as of 2/1/06 version.
Error 1 Source file '...\Properties\AssemblyInfo.cs' could not be opened ('The system cannot find the file specified. ')
-- modified at 3:31 Wednesday 1st February, 2006
|
|
|
|
 |
|
 |
One topic, explored well, I learnt something (didn't know about the .NET 2.0 changes with double buffering). Excellent. Thank-you
|
|
|
|
 |
|
 |
I agree, well done !
Matthew Hazlett
Sometimes I miss the simpler DOS days of Borland Turbo Pascal (but not very often).
|
|
|
|
 |