views:

85

answers:

1

I have an owner-drawn control where performance is an issue during quick repaints such as object drags, resizing and painting the selector square. i have noticed that several other apps, including Picasa, will temporarily draw a reduced-quality image during fast repaint scenarios and then update the image with a higher-quality version when the UI "settles down."

How should I (can I?) produce a lower-quality image to paint when many quick redraws are taking place? Are there other strategies similar to this i can employ to increase performance (or fake increased performance.)

Extra Info:

This is a forms-designer-like application that makes heavy use of owner drawing. It works well but begins to bog down when more than three or four images need to be painted into rectangles in the client area. (End users are allowed to create different types of elements of which images take the heaviest toll on drawing.)

I am using the DrawImageUnscaled GDI+ method to draw images which is supposed to be much more efficient than DrawImage but performance profiling shows that DrawImageUnscaled is still the bottleneck. I think my only recourse is to come up with clever ways to draw less.

P.S. A previous question related to this issue earned me a Tumbleweed badge so i'm taking another approach: http://stackoverflow.com/questions/2587911/how-to-increase-performance-over-gdis-drawimageunscaled

+2  A: 

Wait - you missed out on a piece of low hanging fruit here. Those probably aren't really redrawing the image at all during re-size operations. They might be resizing the existing image in the video ram using StretchBlt - which can be optimized by the video driver/hardware to be very very fast, faster than you could ever 'redraw a reduced quality image.'

strategy:
-image objects have member variable for Last Position/Size (rect)
-repaint of image object draws full-quality
-repaint of image updates last position
-during dragging, do this:
* StrechBlt from Last Position/Size to Current position/Size
* Update Last Position/Size
* If more than a few secs. of drawing, and/or >.2s since last mouse move, call the repaint (not just invalidate - you want it NOW) to get a new full-quality image. Also do if you detect overlaps from other objects (will get StrechBlt'd too)

Sample code I use in an app that does something similar (a zoom-in like effect that sizes a window that could have 100s of objects - looks like an ipad demo only smoother):

Declare Function StretchBlt Lib "gdi32.dll" _
   (ByVal hdcDest As IntPtr, _
    ByVal nXOriginDest As Integer, _
    ByVal nYOriginDest As Integer, _
    ByVal nWidthDest As Integer, _
    ByVal nHeightDest As Integer, _
    ByVal hdcSrc As IntPtr, _
    ByVal nXOriginSrc As Integer, _
    ByVal nYOriginSrc As Integer, _
    ByVal nWidthSrc As Integer, _
    ByVal nHeightSrc As Integer, _
    ByVal dwRop As Int32) As Boolean

    Using g As Graphics = f.pb.CreateGraphics
        ' parm of True says draw plain view - no text = looks bad Zooming.
        f.DrawAll(g, True)
        For i As Integer = iSteps To 1 Step -1
            Dim HDC1 As IntPtr = g.GetHdc
            Try
                ' Size of bite will not be right, but by re-adjusting 
                ' with each iteration, it will make it to full-screen.
                ' Looks as good as having it right to start with, only much easier.
                TopBite = objTop \ i
                BottomBite = h - ((h - objBottom) \ i)
                ' Stretch/move the stuff.
                StretchBlt(HDC1, 0, 0, w - LeftBite, h, _
                  HDC1, LeftBite, TopBite, w - LeftBite, BottomBite - TopBite, 13369376)
                ' Calculate where MyEntry would be after each stretch. Then the Bite 
                ' size calcs above will ensure its closer next time. 
                SimulateStretch(objTop, objBottom, TopBite, BottomBite, h)
            Finally
                g.ReleaseHdc(HDC1)
            End Try
            ' Clear exposed/invalid area to the right.
            g.FillRectangle(br, w - LeftBite, 0, LeftBite, h)
            ' Sleep will make Swells close in duration between small/big window.
            ' (Can I actually sleep this short of a time?)
            System.Threading.Thread.Sleep(5)
        Next
    End Using

Of course if somebody sizes it itty-bitty image and then back up, it will be super low-quality and pixellated - so you can use a smarter algorythm to occasionally fire the real onpaint during mousedrag if not resizing.

note the nuts and bolts of this will depend on specific implementation. You should give more details of your app so I can get it right (what exactly does it look like?) I am assuming a big square usercontrol w/ many ownerdrawn elements, all resized at once equally. IF you have them start small and get resized so they start overlapping, you'll have to periodically do full redraws more often during mouse-resize operations.

FastAl
You may also be able to strechblt from the HQ image in a memory HDC, for better quality w/ less performance, but I never did it, don't know the ramifications.
FastAl