user750905
user750905

Reputation: 21

Double Buffering with vsync (in sync with refresh rate of screen) - C# windows forms

I've been trying to update the BMP of a PictureBox 60 times per second with a line pattern that changes for every update. What's happening is the image is being partially updated in between screen refreshes. So, what you see is part of one pattern and part of the next. I need to update precisely once for every screen refresh. Ideally, my goal is to update a back buffer and then copy it into the front buffer. I've heard that you can use vsync in games to lock the front buffer such that the screen is only updated right after the screen refreshes. If I could take advantage of that locking, it would allow me to precisely updated once per refresh. But I haven't been able to figure out how to do it yet.

Any ideas?

I did try using the DoubleBuffering = true property in windows forms. But it might not work for the PictureBox. I used CopyMemory (a native dll call) to copy the new pattern into the bitmap that is in the PictureBox.

I also tried to use WriteableBitmap with the same technique in the last paragraph, but for some reason the back buffer is never copied to the front buffer, even though I did it the way other people suggested on stack exchange. I tried this for a couple hours or so. The image never updated on the screen with that technique.

Upvotes: 2

Views: 2094

Answers (1)

user750905
user750905

Reputation: 21

I found the solution to my own question. The best way to do it was to create an XNA 2D application. I forced vsync in my graphics card settings. I then turned this property on in the XNA application. In the game constructor, I used this: this.IsFixedTimeStep = true;

public Game1()
{
    this.IsFixedTimeStep = true;
    this.TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 1000 / 60);//60 times per second
    graphics = new GraphicsDeviceManager(this)
    {
        PreferredBackBufferWidth = 800,
        PreferredBackBufferHeight = 600,
        SynchronizeWithVerticalRetrace = true,
    };

    graphics.ApplyChanges();
    Content.RootDirectory = "Content";
}

Then declare a global variable: bool _IsDirty = true; And declare the following functions:

protected override bool BeginDraw()
{
    if (_IsDirty)
    {
        _IsDirty = false;
        base.BeginDraw();
        return true;
    }
    else
        return false;
}
protected override void EndDraw()
{
    if (!_IsDirty)
    {
        base.EndDraw();
        _IsDirty = true;
    }
}

protected override void Draw(GameTime gameTime)
{
    //graphics.GraphicsDevice.Clear(Color.Black);

    // Draw the sprite.
    spriteBatch.Begin();
    spriteBatch.Draw(textureImg, new Rectangle(0, 0, 800, 600), Color.White);
    spriteBatch.End();
    base.Draw(gameTime);
}

Upvotes: 0

Related Questions