|
|
|
date: Mon, 18 Aug 2008 19:12:57 -0500,
group: microsoft.public.dotnet.framework
back
Graphics.DrawImage is very slow
Hi,
I'm trying to improve the painting performance of a control on my form.
The scenario is this - I have a custom control which inherits from Control,
and I manually paint the entire GUI for it. The GUI is fairly static, so
once I've drawn the appropriate image, I cache that to an Image object and
re-use that.
My code snippet is as follows:
Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs)
e.Graphics.DrawImage(_displayImage, e.ClipRectangle, e.ClipRectangle,
GraphicsUnit.Pixel)
End Sub
Where _displayImage is the cached Image object.
Performance absolutely blows. It's fine to initially paint the screen, but
if I (for example) load up an instance of calculator and drag it over my
application, repainting of these controls is incredibly slow. I can
literally saturate the GUI of my app (when it's covered with these custom
controls) with ghostly trails of the calculator window. Once I stop
dragging the calc window, *then* my controls seem to update.
Is there some smarter solution? I've tried using Graphics.DrawImageUnscaled
but it seems to have no effect on performance. My control is set to
DoubleBuffer, UserPaint, and AllPaintingInWMPaint. I'm surprised that this
isn't faster, as all I'm doing is drawing an in-memory bitmap to the screen.
I'm even using clipping so that it should only repaint the affected area.
Why so slow? :-(
Thanks,
Alex
date: Mon, 18 Aug 2008 19:12:57 -0500
author: Alex Clark ail
Re: Graphics.DrawImage is very slow
On Mon, 18 Aug 2008 17:12:57 -0700, Alex Clark <quanta@noemail.noemail>
wrote:
> [...]
> The scenario is this - I have a custom control which inherits from
> Control,
> and I manually paint the entire GUI for it. The GUI is fairly static, so
> once I've drawn the appropriate image, I cache that to an Image object
> and
> re-use that.
>
> [...]
> Performance absolutely blows.
All due respect, that's not a very useful description of the problem. :)
> It's fine to initially paint the screen, but
> if I (for example) load up an instance of calculator and drag it over my
> application, repainting of these controls is incredibly slow. I can
> literally saturate the GUI of my app (when it's covered with these custom
> controls) with ghostly trails of the calculator window. Once I stop
> dragging the calc window, *then* my controls seem to update.
It sounds to me as though the controls aren't getting painted at all. So
I'm not sure what it means for it to be "incredibly slow".
That said, you mention that your application is "covered with these custom
controls". How many? The fact is, there are practical limits to just how
many controls you can put in a window and still expect reasonable drawing
performance. If you have a large number, performance will suffer.
It's also impossible to evaluate any sort of performance issue with just a
code snippet. You should post a concise-but-complete code sample that
reliably demonstrates the problem.
Also, because this is a performance issue, you should be as specific about
the details as you can. What methods are being called? How long do they
take to execute? How often are they called? How sensitive to the number
of controls being used is the issue? That sort of thing. Finally, it's
important to be clear about what the system configuration is, especially
the video card and CPU.
As a test, you could try using some built-in .NET control instead of your
own in an otherwise-identical program and see how performance compares.
That would at least give some information as to whether the performance
issue is typical, or specific only to your custom control.
Pete
date: Mon, 18 Aug 2008 20:33:08 -0700
author: Peter Duniho
Re: Graphics.DrawImage is very slow
Hi Peter,
> All due respect, that's not a very useful description of the problem. :)
lol, I know, sorry, I'll try to clear that up a bit below.
> It sounds to me as though the controls aren't getting painted at all. So
> I'm not sure what it means for it to be "incredibly slow".
The control *does* get repainted, but it's laggy. If I drag calculator over
my form, the calculator window sort of "streaks" across it, leaving ghostly
images behind on the controls. Eventually they repaint themselves but it
can take a few seconds. It's as though there's a long delay between the
Invalidate and Paint calls, but I don't have any specific code in there that
would cause that. It's just taking a long time to refresh itself, it seems.
> That said, you mention that your application is "covered with these custom
> controls". How many? The fact is, there are practical limits to just how
> many controls you can put in a window and still expect reasonable drawing
> performance. If you have a large number, performance will suffer.
In all honesty it doesn't matter if it's covered in them or if it's just
one, the problem happens regardless. The most I'd fit on screen would be
roughly 10 - we're talking full width, and about 64px height (sort of like
list view items stacked one atop the other).
> It's also impossible to evaluate any sort of performance issue with just a
> code snippet. You should post a concise-but-complete code sample that
> reliably demonstrates the problem.
I know, sorry, should've posted a snippet but the project is complex. I'll
try to extract the relevant stuff into a sample repro project.
> Also, because this is a performance issue, you should be as specific about
> the details as you can. What methods are being called? How long do they
> take to execute? How often are they called? How sensitive to the number
> of controls being used is the issue? That sort of thing. Finally, it's
> important to be clear about what the system configuration is, especially
> the video card and CPU.
Methods: barely any. Once I've created an appropriate bitmap (that's done
early on) it's pretty much as simple as what I posted in the OP. I override
OnPaint, and call e.Graphics.DrawImage with my "here's one I made earlier"
bitmap. I clip it so that it should only repaint the invalidated area as
well. That is literally all it's doing, but between it getting invalidated
(me dragging an app over the top of it) and it actually refreshing, there
can be as much as a 3s delay (if I'm still rapidly dragging the other app
around the screen). CPU usage is high at the time as well.
Not really sensitive to the number of controls, it's slow with one, it's
slow with 12.
System is moderate spec, XP Pro x64, 2GB DDR800, Pentium D 3.4, PCI Express
128mb Radeon card.
> As a test, you could try using some built-in .NET control instead of your
> own in an otherwise-identical program and see how performance compares.
> That would at least give some information as to whether the performance
> issue is typical, or specific only to your custom control.
No contest, if I use a dozen large Buttons, ComboBoxen, or even ListViews
the repainting is snappy. Ironically I did a test a while back with a .NET
Panel control where I was painting a complex gradient bitmap with bubbles on
the background (just handling the PaintBackground event). With clipping and
some smart caching of the bitmap, performance was beautiful and snappy, even
in Debug mode.
Maybe it's because I'm inheriting from Control rather than UserControl or
Panel?
date: Tue, 19 Aug 2008 15:15:28 -0500
author: Alex Clark ail
Re: Graphics.DrawImage is very slow
On Tue, 19 Aug 2008 13:15:28 -0700, Alex Clark <quanta@noemail.noemail>
wrote:
> [...]
>> It sounds to me as though the controls aren't getting painted at all.
>> So
>> I'm not sure what it means for it to be "incredibly slow".
>
> The control *does* get repainted, but it's laggy. If I drag calculator
> over
> my form, the calculator window sort of "streaks" across it, leaving
> ghostly
> images behind on the controls. Eventually they repaint themselves but it
> can take a few seconds. It's as though there's a long delay between the
> Invalidate and Paint calls, but I don't have any specific code in there
> that
> would cause that. It's just taking a long time to refresh itself, it
> seems.
I think I know what you mean, but you should try to be more precise. I
don't think you're calling Invalidate() at all (Windows is doing the
invalidation internally as the other window moves over your control), and
no painting is actually done until your OnPaint() method is called.
So, according to your description, it's not that the _painting_ is slow,
but that the OnPaint() method is not even called until much later than you
expect it to.
>> That said, you mention that your application is "covered with these
>> custom
>> controls". How many? The fact is, there are practical limits to just
>> how
>> many controls you can put in a window and still expect reasonable
>> drawing
>> performance. If you have a large number, performance will suffer.
>
> In all honesty it doesn't matter if it's covered in them or if it's just
> one, the problem happens regardless.
Then you definitely have something wrong with your own program.
> [...]
> I know, sorry, should've posted a snippet but the project is complex.
> I'll
> try to extract the relevant stuff into a sample repro project.
If you don't solve it yourself, you should definitely do that.
I'd guess there's at least a 50/50 chance of you finding the problem
yourself as you whittle your existing program down to something more
suitable as a sample.
> [...] I clip it so that it should only repaint the invalidated area as
> well. That is literally all it's doing, but between it getting
> invalidated
> (me dragging an app over the top of it) and it actually refreshing, there
> can be as much as a 3s delay (if I'm still rapidly dragging the other app
> around the screen). CPU usage is high at the time as well.
For what it's worth, using the ClipRectangle is probably pointless. It's
such a slight optimization and complicates the drawing. If that code
should ever have to change in the future, it could wind up broken because
of the explicit use of ClipRectangle (i.e. something could change to make
that rectangle unsuitable as a source or destination rectangle).
> [...]
> Maybe it's because I'm inheriting from Control rather than UserControl or
> Panel?
No, that's not the problem.
I wrote a simple test program that has a custom control (derived from
Control) that just generates a Bitmap for use in an OnPaint() method. I
then ran the program and the Calculator accessory at the same time and had
no trouble at all with performance, even with 20 instances of the control
on my form.
Granted, I'm using 32-bit Windows. I suppose you could be running into
some sort of driver bug related to the 64-bit Windows stuff. You should
try the same code on a different computer, preferably a 32-bit XP system.
Barring that, without any sample code, I have to guess. And my guess is
that you've got something else going on in your program that is somehow
tying up the GUI thread when the UI is invalidated by another window
moving across it. What that could be I have no idea. But for sure, this
is not a general issue that exists in .NET. Assuming it's not a driver
problem, this is fixable. We just need to see a complete code sample that
reproduces the issue.
Pete
date: Tue, 19 Aug 2008 15:23:55 -0700
author: Peter Duniho
Re: Graphics.DrawImage is very slow
Hi Peter,
(VB.NET Code)
This is what I've got in a testbed app. This is the only code I've written
inside Form1.
'---------------
Protected Overrides Sub OnPaintBackground(ByVal e As
System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(e)
e.Graphics.DrawImageUnscaled(GetBackgroundImage(e), 0, 0)
End Sub
Private Function GetBackgroundImage(ByVal e As PaintEventArgs) As Image
Static _image As Image
If Not IsNothing(_image) Then Return _image
Dim rect As Rectangle
Dim rgn As New Region
Dim rnd As New Random(DateTime.Now.Millisecond)
Dim xc, yc, iDeg As Integer
If Not IsNothing(_image) Then
Return _image
Else
_image = New Bitmap(picDraw.Width, picDraw.Height)
End If
rect = picDraw.ClientRectangle
Using br As New LinearGradientBrush(rect, Color.Red, Color.Blue,
LinearGradientMode.ForwardDiagonal)
Using br2 As New LinearGradientBrush(rect, Color.Green,
Color.Orange, LinearGradientMode.ForwardDiagonal)
Using g As Graphics = Graphics.FromImage(_image)
g.SetClip(e.ClipRectangle, CombineMode.Replace)
g.FillRectangle(br, rect)
For x As Integer = 1 To 2000
xc = rnd.Next(0, picDraw.Width)
yc = rnd.Next(0, picDraw.Height)
g.DrawLine(Pens.White, xc, yc, xc + 10, yc + 10)
rnd = New Random(rnd.Next)
iDeg = rnd.Next(10, 360)
g.FillPie(br2, New Rectangle(xc, yc, 10, 10), 0,
iDeg)
Next
End Using
End Using
End Using
Return _image
End Function
'----------------------
Note that, in the call to GetBackgroundImage, if the image has already been
created it just returns that. This is obviously a simplified scenario
because it doesn't repaint for resize etc, it literally only gets created
one time. Performance is better, but even in Release mode I'm not finding
it to be fantastic. I can drag calculator over the form and have a slightly
laggy update of the image. I suspect in my app it's more of a problem
because I have a variety of controls which are all custom painting, and a
selection of background threads doing monitoring work as well, which is
probably stealing some degree of priority from the GUI thread.
It's probably a moot point anyway, because we're heading for a WPF rewrite
soon and a lot of the tests I've done with that seem to display far better
front end performance. I just wondered if I was making some kind of
schoolboy error in the calls to DrawImage, and if there was a much faster
way to do it.
Thanks,
Alex
date: Thu, 21 Aug 2008 14:43:39 -0500
author: Alex Clark ail
Re: Graphics.DrawImage is very slow
On Thu, 21 Aug 2008 12:43:39 -0700, Alex Clark <quanta@noemail.noemail>
wrote:
> [...] I just wondered if I was making some kind of
> schoolboy error in the calls to DrawImage, and if there was a much faster
> way to do it.
I don't see anything in the code you posted that would explain a
performance issue (though I'm not sure why you have the second check for a
null _image value). I do wonder if the code you posted is _really_ the
code you're using, since a static local would be shared across all
instances of the control, which seems like an odd thing to do.
But as far as the performance issue goes, whatever it is, it's in code you
didn't share. I'm sure your code is somehow responsible for the slowdown,
but whether it's a matter of a "schoolboy error" or something that's
simply inherent in the design and not easily fixed, I can't say.
Pete
date: Thu, 21 Aug 2008 12:56:24 -0700
author: Peter Duniho
Re: Graphics.DrawImage is very slow
Hi Peter,
No, it's not the code I'm using, I was just using it to demonstrate a
complex bitmap being created one time and then drawn on each call to
OnPaint.
However, only after I posted the code did I recall I'd been testing painting
through transparent controls (the OnPaint is for the Form, but creating the
bitmap checks the size of a PictureBox control). I was actually overlaying
a transparent PictureBox on the form (dockstyle set to fill). Once I
removed that in my test app, the repainting performance was super snappy -
even in *debug* mode.
So that sorta puts me straight back to the drawing board in terms of my own
app, but at least it eliminates a good few things. I think I'll try to
"turn off" the background threads and see if that boosts foreground painting
performance.
"Peter Duniho" wrote in message
news:op.uf85oah98jd0ej@petes-computer.local...
> On Thu, 21 Aug 2008 12:43:39 -0700, Alex Clark <quanta@noemail.noemail>
> wrote:
>
>> [...] I just wondered if I was making some kind of
>> schoolboy error in the calls to DrawImage, and if there was a much faster
>> way to do it.
>
> I don't see anything in the code you posted that would explain a
> performance issue (though I'm not sure why you have the second check for a
> null _image value). I do wonder if the code you posted is _really_ the
> code you're using, since a static local would be shared across all
> instances of the control, which seems like an odd thing to do.
>
> But as far as the performance issue goes, whatever it is, it's in code you
> didn't share. I'm sure your code is somehow responsible for the slowdown,
> but whether it's a matter of a "schoolboy error" or something that's
> simply inherent in the design and not easily fixed, I can't say.
>
> Pete
date: Thu, 21 Aug 2008 15:05:16 -0500
author: Alex Clark ail
Re: Graphics.DrawImage is very slow
On Thu, 21 Aug 2008 13:05:16 -0700, Alex Clark <quanta@noemail.noemail>
wrote:
> Hi Peter,
>
> No, it's not the code I'm using, I was just using it to demonstrate a
> complex bitmap being created one time and then drawn on each call to
> OnPaint.
But that wasn't useful. I can write that kind of code myself in five
minutes, had already done so, and had already pointed out that it worked
fine, without any performance issues at all. Posting another "proof of
concept" code snippet doesn't add anything to the discussion.
Unless you are posting a _complete_ code sample that you have tested
yourself and verified that it reproduces the problem you're trying to
illustrate, any code sample you post isn't going to be helpful in
understanding the problem you're actually having.
> However, only after I posted the code did I recall I'd been testing
> painting
> through transparent controls (the OnPaint is for the Form, but creating
> the
> bitmap checks the size of a PictureBox control). I was actually
> overlaying
> a transparent PictureBox on the form (dockstyle set to fill). Once I
> removed that in my test app, the repainting performance was super snappy
> - even in *debug* mode. [...]
I hope that sufficiently illustrates the importance of posting an _actual_
concise-but-complete code sample that reliably demonstrates the problem.
:)
Pete
date: Thu, 21 Aug 2008 16:32:15 -0700
author: Peter Duniho
Re: Graphics.DrawImage is very slow
Hi Zhi-Xin,
It's a long story but I think I nailed most of the performance issues, it's
repainting much faster and smoother now, so the issue is solved.
Many thanks,
Alex
"Zhi-Xin Ye [MSFT]" wrote in message
news:5Y%23fwRBCJHA.1768@TK2MSFTNGHUB02.phx.gbl...
> Dear Alex,
>
> How did you paint the container control and the custom control? If you
> don't put the custom controls on the container control, do you still have
> the performance problem?
>
> I'm looking forward to hearing from you.
>
> Sincerely,
> Zhi-Xin Ye
> Microsoft Managed Newsgroup Support Team
>
> Delighting our customers is our #1 priority. We welcome your comments and
> suggestions about how we can improve the support we provide to you. Please
> feel free to let my manager know what you think of the level of service
> provided. You can send feedback directly to my manager at:
> msdnmg@microsoft.com.
>
> ==================================================
> Get notification to my posts through email? Please refer to
> http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.
>
> Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
> where an initial response from the community or a Microsoft Support
> Engineer within 1 business day is acceptable. Please note that each follow
> up response may take approximately 2 business days as the support
> professional working with you may need further investigation to reach the
> most efficient resolution. The offering is not appropriate for situations
> that require urgent, real-time or phone-based interactions or complex
> project analysis and dump analysis issues. Issues of this nature are best
> handled working with a dedicated Microsoft Support Engineer by contacting
> Microsoft Customer Support Services (CSS) at
> http://support.microsoft.com/select/default.aspx?target=assistance&ln=en-us.
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no
> rights.
>
date: Wed, 27 Aug 2008 12:08:12 -0500
author: Alex Clark ail
Re: Graphics.DrawImage is very slow
Hi, Alex,
Could you share how you solved the problem? I got into the same issue.
thanks,
bill
"Alex Clark" wrote:
> Hi Zhi-Xin,
>
> It's a long story but I think I nailed most of the performance issues, it's
> repainting much faster and smoother now, so the issue is solved.
>
> Many thanks,
> Alex
>
>
>
> "Zhi-Xin Ye [MSFT]" wrote in message
> news:5Y%23fwRBCJHA.1768@TK2MSFTNGHUB02.phx.gbl...
> > Dear Alex,
> >
> > How did you paint the container control and the custom control? If you
> > don't put the custom controls on the container control, do you still have
> > the performance problem?
> >
> > I'm looking forward to hearing from you.
> >
> > Sincerely,
> > Zhi-Xin Ye
> > Microsoft Managed Newsgroup Support Team
> >
> > Delighting our customers is our #1 priority. We welcome your comments and
> > suggestions about how we can improve the support we provide to you. Please
> > feel free to let my manager know what you think of the level of service
> > provided. You can send feedback directly to my manager at:
> > msdnmg@microsoft.com.
> >
> > ==================================================
> > Get notification to my posts through email? Please refer to
> > http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.
> >
> > Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
> > where an initial response from the community or a Microsoft Support
> > Engineer within 1 business day is acceptable. Please note that each follow
> > up response may take approximately 2 business days as the support
> > professional working with you may need further investigation to reach the
> > most efficient resolution. The offering is not appropriate for situations
> > that require urgent, real-time or phone-based interactions or complex
> > project analysis and dump analysis issues. Issues of this nature are best
> > handled working with a dedicated Microsoft Support Engineer by contacting
> > Microsoft Customer Support Services (CSS) at
> > http://support.microsoft.com/select/default.aspx?target=assistance&ln=en-us.
> > ==================================================
> > This posting is provided "AS IS" with no warranties, and confers no
> > rights.
> >
>
>
>
date: Wed, 3 Sep 2008 11:54:01 -0700
author: bill
|
|