R – (.NET/C#/winforms) Artifacting when drawing on a Form with Graphics

doublebufferedgdi+graphicsnetwinforms

My objective is to move visual elements drawn using methods of a Graphics object across a Form with no flicker or artifacting (in .NET 3.5). I can successfully achieve flickerless movement by either using automatic double buffering (setting the Form's DoubleBuffered property to true) or implementing a back-buffer myself. I am however struggling to find a way to use either method without clearly visible artifacts showing.

When using automatic double buffering, a page-tearing effect is evident. It looks as though the back-buffer is being slowly, progressively copied to the form, from top to bottom, over as many as three refreshes of my 60Hz LCD.

When I implement double buffering myself (see code block for details) it looks as though the back buffer is copied to the form fast enough for no page-tearing to occur. However another type of artifact sometimes appears. The code below, which allows you to move a blue rectangle on a white background left and right on the form using the arrow keys, should reproduce the effect as a series of horizontal white bands that sometimes appear on the left and right edges of the rectangle just as it is moved.

public partial class Form1 : Form {
    int x;
    Bitmap buffer;

    public Form1() {
        InitializeComponent();
        buffer = new Bitmap(Width, Height);
    }

    private void Form1_Paint(object sender, PaintEventArgs e) {
        Graphics g = Graphics.FromImage(buffer);
        g.Clear(Color.FromArgb(255, 255, 255));
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.FillRectangle(Brushes.Blue, x, 0, 100, 500);
        e.Graphics.DrawImageUnscaled(buffer, 0, 0);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent) {
        //Don't allow the background to paint
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e) {
        const int scrollSpeed = 20;
        if(e.KeyData == Keys.Left) {
            x -= scrollSpeed;
            Refresh();
        }
        else {
            if(e.KeyData == Keys.Right) {
                x += scrollSpeed;
                Refresh();
            }
        }
    }
}

if(others able to reproduce the effect) {
    Am I doing something wrong, perhaps triggering some
    kind of race condition in the painting code or is
    this just a behavior of the runtime that I have to
    live with?
}
else {
    Could it be a peculiarity of my display card or a
    bugged display driver?
}

Best Answer

It may be important to know that graphics cards accelerating 2D operations usually accelerate GDI, not GDI+. I think that using a GDI bitmap and drawing it directly using a GDI methods (e.g. through p/invoke) would make things faster.

Related Topic